diff --git a/.gitlab/merge_request_templates/Default.md b/.gitlab/merge_request_templates/Default.md deleted file mode 100644 index eed4d5e..0000000 --- a/.gitlab/merge_request_templates/Default.md +++ /dev/null @@ -1,42 +0,0 @@ -## Description - -_Please provide a brief summary of the changes in this merge request._ - -_If possible, add a short screengrab or some screenshots of the changes._ - -## Testing Instructions - -_Please provide instructions on how the code reviewers can test your changes:_ - -1. [Step 1] -2. [Step 2] -3. [Step 3] -4. ... - -_Please include any specific information on test data, configurations, or other requirements that are necessary to properly test the changes._ - -Once you've tested the changes, please confirm that they work as expected and that there are no regressions or unexpected side effects. If any issues are discovered during testing, please include detailed steps to reproduce the issue in the merge request comments. Thank you! - -## Related Issues - -_Please list any related issues or pull requests that are relevant to this merge request._ -_E.g. WES-XXX-..._ - -## Known bugs or issues - -_Please list any known bugs or issues related to the changes in this merge request._ - -## Checklist - -- [ ] I have filled in this template. -- [ ] I have tested my changes thoroughly (both in the editor + **build and run (ctrl+B)**!). -- [ ] I have added appropriate unit tests. -- [ ] I have added appropriate playmode tests. -- [ ] I have updated the user documentation as necessary. -- [ ] Code reviewed by 2 people. - -## Additional Notes - -_Please add any additional notes or comments that may be helpful for reviewers to understand your changes._ - -/assign_reviewer @wesign/unityappreviewers diff --git a/Assets/Accounts/Prefabs/CourseProgressCard.prefab b/Assets/Accounts/Prefabs/CourseProgressCard.prefab index 96e9231..8eb5eaf 100644 --- a/Assets/Accounts/Prefabs/CourseProgressCard.prefab +++ b/Assets/Accounts/Prefabs/CourseProgressCard.prefab @@ -343,6 +343,12 @@ MonoBehaviour: button: {fileID: -2577348215772602702} courseProgress: entries: [] + courseIndex: 0 + progress: -1 + completedLearnables: 0 + inUseLearnables: 0 + totalLearnables: 0 + learnables: [] courseList: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} thumbnail: {fileID: 5101881939775039227} title: {fileID: 5101881939882359064} @@ -491,8 +497,8 @@ MonoBehaviour: m_Calls: [] m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] diff --git a/Assets/Accounts/Prefabs/MinigameProgressCard.prefab b/Assets/Accounts/Prefabs/MinigameProgressCard.prefab index d45ffcc..832d01d 100644 --- a/Assets/Accounts/Prefabs/MinigameProgressCard.prefab +++ b/Assets/Accounts/Prefabs/MinigameProgressCard.prefab @@ -68,8 +68,8 @@ MonoBehaviour: m_Calls: [] m_text: 'Topscore: 123456789' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -275,6 +275,9 @@ MonoBehaviour: button: {fileID: 5555894415693752970} minigameProgress: entries: [] + minigameIndex: 0 + latestScores: [] + highestScores: [] minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} thumbnail: {fileID: 5101881939775039227} title: {fileID: 5101881939882359064} @@ -423,8 +426,8 @@ MonoBehaviour: m_Calls: [] m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] diff --git a/Assets/Accounts/Prefabs/UserCard.prefab b/Assets/Accounts/Prefabs/UserCard.prefab index 3012c96..dc8137f 100644 --- a/Assets/Accounts/Prefabs/UserCard.prefab +++ b/Assets/Accounts/Prefabs/UserCard.prefab @@ -96,7 +96,7 @@ MonoBehaviour: m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} m_SelectOnRight: {fileID: 0} - m_Transition: 1 + m_Transition: 0 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} @@ -277,15 +277,15 @@ MonoBehaviour: m_Calls: [] m_text: Gebruiker m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4294309365 + m_fontColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -481,13 +481,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 172fcacd3bd90f442a6b94f0ff43a76a, type: 3} m_Name: m_EditorClassIdentifier: - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - user: - username: - avatar: {fileID: 0} - playtime: 0 - courses: [] - minigames: [] button: {fileID: 7566391564300576381} avatar: {fileID: 5164936991071620901} username: {fileID: 7566391564272109414} diff --git a/Assets/Accounts/Scenes/ChangeUserScreen.unity b/Assets/Accounts/Scenes/ChangeUserScreen.unity index 77c4ac2..2d55980 100644 --- a/Assets/Accounts/Scenes/ChangeUserScreen.unity +++ b/Assets/Accounts/Scenes/ChangeUserScreen.unity @@ -538,8 +538,8 @@ MonoBehaviour: m_Calls: [] m_text: Een nieuwe gebruiker maken m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -673,8 +673,8 @@ MonoBehaviour: m_Calls: [] m_text: 'Veranderen naar:' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -755,10 +755,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 906197777} m_Modifications: - - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument - value: Common/Scenes/StartScreen - objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name value: ButtonBack @@ -793,11 +789,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -829,11 +825,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -867,7 +863,7 @@ GameObject: - component: {fileID: 840332114} - component: {fileID: 840332113} m_Layer: 5 - m_Name: Button + m_Name: ContinueButton m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -938,8 +934,8 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: ChangeUserScreen, Assembly-CSharp + - m_Target: {fileID: 2129020786} + m_TargetAssemblyTypeName: ChangeUserScreen, AccountsScripts m_MethodName: IChooseYou m_Mode: 1 m_Arguments: @@ -999,7 +995,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -1045,14 +1040,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1070,22 +1065,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3a7f31ce7a41c294b95cb1f9fbec207f, type: 3} - m_Name: - m_EditorClassIdentifier: - userPrefab: {fileID: 7566391564300576383, guid: f5103a1b6ba1b0445a0d049203b9b6b2, type: 3} - usersContainer: {fileID: 1438010722} - error: {fileID: 1815188481} - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} --- !u!1 &1143249623 GameObject: m_ObjectHideFlags: 0 @@ -1099,7 +1078,7 @@ GameObject: - component: {fileID: 1143249626} - component: {fileID: 1143249625} m_Layer: 5 - m_Name: Button (1) + m_Name: CreateUserButton m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -1170,8 +1149,8 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: ChangeUserScreen, Assembly-CSharp + - m_Target: {fileID: 2129020786} + m_TargetAssemblyTypeName: ChangeUserScreen, AccountsScripts m_MethodName: GotoUserCreation m_Mode: 1 m_Arguments: @@ -1280,8 +1259,8 @@ MonoBehaviour: m_Calls: [] m_text: Verder m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -1607,10 +1586,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -1654,7 +1633,7 @@ RectTransform: - {fileID: 906197777} - {fileID: 1815188482} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -1721,8 +1700,8 @@ MonoBehaviour: m_Calls: [] m_text: Er moet minstens 1 gebruiker zijn. m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -1905,3 +1884,50 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2109596086} m_CullTransparentMesh: 1 +--- !u!1 &2129020785 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2129020787} + - component: {fileID: 2129020786} + m_Layer: 0 + m_Name: ChangeUserController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2129020786 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2129020785} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3a7f31ce7a41c294b95cb1f9fbec207f, type: 3} + m_Name: + m_EditorClassIdentifier: + userPrefab: {fileID: 7566391564300576383, guid: f5103a1b6ba1b0445a0d049203b9b6b2, type: 3} + usersContainer: {fileID: 1438010722} + error: {fileID: 1815188481} +--- !u!4 &2129020787 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2129020785} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Accounts/Scenes/UserCreationScreen.unity b/Assets/Accounts/Scenes/UserCreationScreen.unity index e9392cd..8610dce 100644 --- a/Assets/Accounts/Scenes/UserCreationScreen.unity +++ b/Assets/Accounts/Scenes/UserCreationScreen.unity @@ -251,8 +251,8 @@ MonoBehaviour: m_Calls: [] m_text: "\u200B" m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -326,6 +326,113 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 200054640} m_CullTransparentMesh: 1 +--- !u!1001 &268687073 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 906197777} + m_Modifications: + - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_Name + value: ButtonBack + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_Pivot.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_Pivot.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_SizeDelta.x + value: 50 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_SizeDelta.y + value: 50 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_AnchoredPosition.x + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_AnchoredPosition.y + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} +--- !u!224 &268687074 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + m_PrefabInstance: {fileID: 268687073} + m_PrefabAsset: {fileID: 0} +--- !u!1 &268687075 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + m_PrefabInstance: {fileID: 268687073} + m_PrefabAsset: {fileID: 0} --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -441,7 +548,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 1 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 1, y: 0.5} @@ -470,8 +577,8 @@ MonoBehaviour: m_Calls: [] m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -576,7 +683,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} @@ -605,8 +712,8 @@ MonoBehaviour: m_Calls: [] m_text: 'Nieuwe Gebruiker:' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -713,7 +820,7 @@ RectTransform: m_Children: - {fileID: 1087307047} m_Father: {fileID: 906197777} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -811,7 +918,7 @@ MonoBehaviour: m_CaretWidth: 1 m_ReadOnly: 0 m_RichText: 1 - m_GlobalFontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_GlobalFontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_OnFocusSelectAll: 1 m_ResetOnDeActivation: 1 m_RestoreOriginalTextOnEscape: 1 @@ -889,7 +996,7 @@ RectTransform: m_Children: - {fileID: 1229328480} m_Father: {fileID: 906197777} - m_RootOrder: 4 + m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0} m_AnchorMax: {x: 0.5, y: 0} @@ -940,8 +1047,8 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: UserCreationScreen, Assembly-CSharp + - m_Target: {fileID: 1787496675} + m_TargetAssemblyTypeName: UserCreationScreen, AccountsScripts m_MethodName: CreateUser m_Mode: 1 m_Arguments: @@ -1001,7 +1108,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -1021,6 +1127,7 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: + - {fileID: 268687074} - {fileID: 629516232} - {fileID: 589847187} - {fileID: 645809400} @@ -1047,14 +1154,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1072,43 +1179,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fc3902e35c042b14f83b24498d31d587, type: 3} - m_Name: - m_EditorClassIdentifier: - errorMessage: {fileID: 589847186} - inputName: {fileID: 645809401} - avatarsContainer: {fileID: 1832217925} - avatarPrefab: {fileID: 6263784960026409964, guid: c09ef5423059da444ad7743174e9f077, type: 3} - sprites: - - {fileID: 21300000, guid: 4654657a2ebea444898fa6eeaefcd18d, type: 3} - - {fileID: 21300000, guid: b67b99d98d1ceb1489743bcd78b9ab70, type: 3} - - {fileID: 21300000, guid: e4af402f37099cd4195d7d2654519744, type: 3} - - {fileID: 21300000, guid: 73f4e028d9efb644aa23538a749667c5, type: 3} - - {fileID: 21300000, guid: bc11ff9d6cc35de45ab58f39f13d7142, type: 3} - - {fileID: 21300000, guid: 2b01165a5836ab14593d7a5862bd6793, type: 3} - - {fileID: 21300000, guid: 1a28fa2c46acbb1408633e4e98061d56, type: 3} - - {fileID: 21300000, guid: 8009fc8cfee7ea848a678e056731c02e, type: 3} - - {fileID: 21300000, guid: 7272bfa2b3f87564eb961d41c641479d, type: 3} - - {fileID: 21300000, guid: 1a4d7d2fe1dc58448b2c0451d2924003, type: 3} - - {fileID: 21300000, guid: 439c062e9ba9d0f439dffd41509ceee7, type: 3} - - {fileID: 21300000, guid: 8962e03659a079546810c3ad9c8a211c, type: 3} - - {fileID: 21300000, guid: 182fb89eba9c64041bef31ca35c4bcd8, type: 3} - - {fileID: 21300000, guid: c7006b8cc5cff974b9ff307fe13fdd5e, type: 3} - - {fileID: 21300000, guid: 16f645dc2176fa248af566b5295b451a, type: 3} - - {fileID: 21300000, guid: d574bf2c96bb5b74080b4cf8ca51312d, type: 3} - - {fileID: 21300000, guid: 47a49435e7b8c9a49b162fb4d6f9ceaa, type: 3} - - {fileID: 21300000, guid: e3c4feacdb7710349b326280e2163a84, type: 3} - users: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - selectedAvatar: 0 --- !u!1 &1087307046 GameObject: m_ObjectHideFlags: 0 @@ -1222,8 +1292,8 @@ MonoBehaviour: m_Calls: [] m_text: Verder m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -1345,10 +1415,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -1391,13 +1461,62 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} +--- !u!1 &1787496674 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1787496676} + - component: {fileID: 1787496675} + m_Layer: 0 + m_Name: UserCreationController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1787496675 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1787496674} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fc3902e35c042b14f83b24498d31d587, type: 3} + m_Name: + m_EditorClassIdentifier: + errorMessage: {fileID: 589847186} + inputName: {fileID: 645809401} + avatarsContainer: {fileID: 1832217925} + avatarPrefab: {fileID: 6263784960026409964, guid: c09ef5423059da444ad7743174e9f077, type: 3} + backButton: {fileID: 268687075} +--- !u!4 &1787496676 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1787496674} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1832217924 GameObject: m_ObjectHideFlags: 0 @@ -1428,7 +1547,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 3 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -1540,8 +1659,8 @@ MonoBehaviour: m_Calls: [] m_text: Naam (max 12 letters) m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] diff --git a/Assets/Accounts/Scenes/UserProgressScreen.unity b/Assets/Accounts/Scenes/UserProgressScreen.unity index ecf1d23..1f2ba9e 100644 --- a/Assets/Accounts/Scenes/UserProgressScreen.unity +++ b/Assets/Accounts/Scenes/UserProgressScreen.unity @@ -487,6 +487,61 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &400519678 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 400519680} + - component: {fileID: 400519679} + m_Layer: 0 + m_Name: UserProgressController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &400519679 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 400519678} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a59f8e8c48fbd4444a41df01694d13a7, type: 3} + m_Name: + m_EditorClassIdentifier: + username: {fileID: 1021209698} + avatar: {fileID: 1873954004} + playtime: {fileID: 1716832605} + highscoreMarker: {fileID: 7141392721760992647, guid: c54186c4d7aafd5459b0097d481b8fbf, type: 3} + courseCardPrefab: {fileID: 5101881939626277738, guid: b953de8778612cd449ba1999c4f7b8c4, type: 3} + coursesContainer: {fileID: 1487493400} + emptyCourses: {fileID: 494202816} + minigameCardPrefab: {fileID: 5101881939626277738, guid: af026fa8050694c4f816aa0c615e1992, type: 3} + minigamesContainer: {fileID: 67107106} + emptyMinigames: {fileID: 505387970} + progressGraph: {fileID: 913667425} +--- !u!4 &400519680 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 400519678} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &494202816 GameObject: m_ObjectHideFlags: 0 @@ -848,10 +903,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 906197777} m_Modifications: - - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument - value: Common/Scenes/StartScreen - objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name value: ButtonBack @@ -886,11 +937,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -922,11 +973,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -958,7 +1009,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -1005,14 +1055,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1030,30 +1080,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a59f8e8c48fbd4444a41df01694d13a7, type: 3} - m_Name: - m_EditorClassIdentifier: - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - username: {fileID: 1021209698} - avatar: {fileID: 1873954004} - playtime: {fileID: 1716832605} - highscoreMarker: {fileID: 7141392721760992647, guid: c54186c4d7aafd5459b0097d481b8fbf, type: 3} - courseCardPrefab: {fileID: 5101881939626277738, guid: b953de8778612cd449ba1999c4f7b8c4, type: 3} - coursesContainer: {fileID: 1487493400} - emptyCourses: {fileID: 494202816} - minigameCardPrefab: {fileID: 5101881939626277738, guid: af026fa8050694c4f816aa0c615e1992, type: 3} - minigamesContainer: {fileID: 67107106} - emptyMinigames: {fileID: 505387970} - progressGraph: {fileID: 913667425} --- !u!1 &909961605 GameObject: m_ObjectHideFlags: 0 @@ -1255,8 +1281,8 @@ MonoBehaviour: m_Calls: [] m_text: QQQQQQQQQQQQ m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -1906,8 +1932,8 @@ MonoBehaviour: m_Calls: [] m_text: 'Totale speeltijd: ' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -2029,10 +2055,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -2075,7 +2101,7 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} diff --git a/Assets/Accounts/ScriptableObjects/UserAvatarList.asset b/Assets/Accounts/ScriptableObjects/UserAvatarList.asset new file mode 100644 index 0000000..dd6dba2 --- /dev/null +++ b/Assets/Accounts/ScriptableObjects/UserAvatarList.asset @@ -0,0 +1,42 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 81765ea55baf15d45b01b02187b02429, type: 3} + m_Name: UserAvatarList + m_EditorClassIdentifier: + avatars: + - {fileID: 21300000, guid: 6feaaea4b64633f49b4538bfd4b3755c, type: 3} + - {fileID: 21300000, guid: 399cc241fc79bd74db314f146e7fb6b9, type: 3} + - {fileID: 21300000, guid: 4654657a2ebea444898fa6eeaefcd18d, type: 3} + - {fileID: 21300000, guid: 0cc198f1cde659246a199b30459720b1, type: 3} + - {fileID: 21300000, guid: 7f105a09a3d164547925ee1bdfa595ca, type: 3} + - {fileID: 21300000, guid: 313c22e5834595645989d609fe9d8853, type: 3} + - {fileID: 21300000, guid: e5f3d99cdf5298d4f86d42dd019a6bad, type: 3} + - {fileID: 21300000, guid: b67b99d98d1ceb1489743bcd78b9ab70, type: 3} + - {fileID: 21300000, guid: e4af402f37099cd4195d7d2654519744, type: 3} + - {fileID: 21300000, guid: 73f4e028d9efb644aa23538a749667c5, type: 3} + - {fileID: 21300000, guid: 61e56570163833e448037bc353ada0ac, type: 3} + - {fileID: 21300000, guid: 8e69dfd19237abb4f98eb11e74153109, type: 3} + - {fileID: 21300000, guid: bc11ff9d6cc35de45ab58f39f13d7142, type: 3} + - {fileID: 21300000, guid: f989719a5c45c7a4183b2bc12c1c4905, type: 3} + - {fileID: 21300000, guid: 1392922567cd59d4fb0beceea3f5917a, type: 3} + - {fileID: 21300000, guid: 3c314ae9e10eafb49b57c98c9e779bd8, type: 3} + - {fileID: 21300000, guid: 33509e453b5093e43a148a668a961c56, type: 3} + - {fileID: 21300000, guid: 39ac3b86729423846be1fbd56b8d92d6, type: 3} + - {fileID: 21300000, guid: 1118d67f50622cc4ab02aa23c6dc1fd4, type: 3} + - {fileID: 21300000, guid: e519f0f7b00e6834187963a0131cae52, type: 3} + - {fileID: 21300000, guid: eefb367ff44256d43a14cde2c3924321, type: 3} + - {fileID: 21300000, guid: 83d6525e4efa4954091e08095349f45a, type: 3} + - {fileID: 21300000, guid: db31bca6363270441ab54421f55c1263, type: 3} + - {fileID: 21300000, guid: 9d5771baa6ea6e041b066135d6798e1c, type: 3} + - {fileID: 21300000, guid: 2b01165a5836ab14593d7a5862bd6793, type: 3} + - {fileID: 21300000, guid: 8c304fe460423214ea0bb6ebc235ed2d, type: 3} + - {fileID: 21300000, guid: b203b4e5f8568ff46b2277ce6d61017a, type: 3} diff --git a/Assets/Accounts/ScriptableObjects/UserList.asset.meta b/Assets/Accounts/ScriptableObjects/UserAvatarList.asset.meta similarity index 79% rename from Assets/Accounts/ScriptableObjects/UserList.asset.meta rename to Assets/Accounts/ScriptableObjects/UserAvatarList.asset.meta index bad75c7..aa1812e 100644 --- a/Assets/Accounts/ScriptableObjects/UserList.asset.meta +++ b/Assets/Accounts/ScriptableObjects/UserAvatarList.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 072bec636a40f7e4e93b0ac624a3bda2 +guid: 017ec1af3b6cc4d4ab2b506911a4edad NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/Accounts/Scripts/AccountsScripts.asmdef b/Assets/Accounts/Scripts/AccountsScripts.asmdef index 9238363..8a40a7f 100644 --- a/Assets/Accounts/Scripts/AccountsScripts.asmdef +++ b/Assets/Accounts/Scripts/AccountsScripts.asmdef @@ -3,6 +3,7 @@ "rootNamespace": "", "references": [ "GUID:6055be8ebefd69e48b49212b09b47b2f", + "GUID:e83ddf9a537a96b4a804a16bb7872ec1", "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25" ], "includePlatforms": [], diff --git a/Assets/Accounts/Scripts/ChangeUserScreen.cs b/Assets/Accounts/Scripts/ChangeUserScreen.cs index e5e0041..3bacfde 100644 --- a/Assets/Accounts/Scripts/ChangeUserScreen.cs +++ b/Assets/Accounts/Scripts/ChangeUserScreen.cs @@ -22,11 +22,6 @@ public class ChangeUserScreen : MonoBehaviour /// public GameObject error; - /// - /// Reference to the user list - /// - public UserList userList; - /// /// Index of the current selected user in the UserList /// @@ -42,7 +37,7 @@ public class ChangeUserScreen : MonoBehaviour /// void Start() { - userList.Load(); + PersistentDataController.GetInstance().Load(); error.SetActive(false); DisplayUsers(); } @@ -57,8 +52,8 @@ public class ChangeUserScreen : MonoBehaviour Destroy(child.gameObject); } - List users = userList.GetUsers(); - currentUserIndex = userList.GetCurrentUserIndex(); + List users = UserList.GetUsers(); + currentUserIndex = UserList.IndexOf(UserList.GetCurrentUser().GetUsername()); for (int i = 0; i < users.Count; i++) { User user = users[i]; @@ -99,8 +94,7 @@ public class ChangeUserScreen : MonoBehaviour /// public void IChooseYou() { - userList.ChangeCurrentUser(currentUserIndex); - userList.Save(); + UserList.ChangeCurrentUser(currentUserIndex); SystemController.GetInstance().BackToPreviousScene(); } diff --git a/Assets/Accounts/Scripts/CourseProgressCard.cs b/Assets/Accounts/Scripts/CourseProgressCard.cs index 76b7550..2c6522b 100644 --- a/Assets/Accounts/Scripts/CourseProgressCard.cs +++ b/Assets/Accounts/Scripts/CourseProgressCard.cs @@ -21,7 +21,7 @@ public class CourseProgressCard : MonoBehaviour /// /// Reference to the progress so we can display a progress bar /// - public Progress courseProgress; + public PersistentDataController.SavedCourseProgress courseProgress; /// /// Reference to the list of courses so we can query the correct course @@ -48,11 +48,11 @@ public class CourseProgressCard : MonoBehaviour /// void Start() { - Course course = courseList.GetCourseByIndex(courseProgress.Get("courseIndex")); + Course course = courseList.GetCourseByIndex(courseProgress.courseIndex); thumbnail.sprite = course.thumbnail; title.text = course.title; - progressBar.value = courseProgress.Get("courseProgress"); + progressBar.value = courseProgress.progress; button.onClick.AddListener(selectActivity); } } diff --git a/Assets/Accounts/Scripts/MinigameProgressCard.cs b/Assets/Accounts/Scripts/MinigameProgressCard.cs index 6e4b2f5..aca0b4b 100644 --- a/Assets/Accounts/Scripts/MinigameProgressCard.cs +++ b/Assets/Accounts/Scripts/MinigameProgressCard.cs @@ -22,7 +22,7 @@ public class MinigameProgressCard : MonoBehaviour /// /// Reference to the minigame progress /// - public Progress minigameProgress; + public PersistentDataController.SavedMinigameProgress minigameProgress; /// /// Reference to the minigame list @@ -49,11 +49,11 @@ public class MinigameProgressCard : MonoBehaviour /// void Start() { - Minigame minigame = minigameList.GetMinigameByIndex(minigameProgress.Get("minigameIndex")); + Minigame minigame = minigameList.GetMinigameByIndex(minigameProgress.minigameIndex); thumbnail.sprite = minigame.thumbnail; title.text = minigame.title; - List highscores = minigameProgress.Get>("highestScores"); + List highscores = minigameProgress.highestScores; int score = highscores.Count > 0 ? highscores[0].scoreValue : 0; highscore.text = $"Topscore: {score}"; button.onClick.AddListener(selectActivity); diff --git a/Assets/Accounts/Scripts/Progress.cs b/Assets/Accounts/Scripts/Progress.cs deleted file mode 100644 index e6adf98..0000000 --- a/Assets/Accounts/Scripts/Progress.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; -using UnityEngine; - -/// -/// A class for holding all progress belonging to a user -/// -[Serializable] -public class Progress -{ - /// - /// A helper class for handling the stored progress - /// - [Serializable] - protected class DataEntry - { - /// - /// The key, used to reference the data object - /// - public string key; - - /// - /// The object, representated as a list of byte (which can be serialized) - /// - public List bytes = new List(); - - public DataEntry(string key, byte[] data) - { - this.key = key; - this.bytes = new List(data); - } - } - - /// - /// Entries in the Progress object - /// - [SerializeField] - private List entries = new List(); - - - /// - /// Update the value of a certain key, - /// or add a new value if the key was not present - /// - /// The type of the data to be added/updated - /// The key, used for referencing the data - /// The object of type - /// true if successful, false otherwise - public bool AddOrUpdate(string key, T data) - { - if (data == null) - return false; - - DataEntry entry = entries.Find(x => x.key == key); - - // Hacky serialization stuff - BinaryFormatter bf = new BinaryFormatter(); - using (MemoryStream ms = new MemoryStream()) - { - bf.Serialize(ms, data); - if (entry != null) - { - entry.bytes.Clear(); - entry.bytes.AddRange(ms.ToArray()); - } - else - { - entries.Add(new DataEntry(key, ms.ToArray())); - } - return true; - } - } - - /// - /// Get the data object of a certain key - /// - /// The type of the data object - /// The key referencing the data object - /// The data, cast to a type - /// - public T Get(string key) - { - BinaryFormatter bf = new BinaryFormatter(); - using (MemoryStream ms = new MemoryStream()) - { - // Find the correct key - foreach (DataEntry entry in entries) - { - if (entry.key == key) - { - // Hacky serialization stuff - byte[] data = entry.bytes.ToArray(); - ms.Write(data, 0, data.Length); - ms.Seek(0, SeekOrigin.Begin); - return (T)bf.Deserialize(ms); - } - } - } - // Raise an exception when key is not found - throw new KeyNotFoundException(); - } - - /// - /// Check whether a key is present - /// - /// The key to check - /// true if a item can be found with the specified key - public bool Has(string key) - { - return entries.Find(x => x.key == key) != null; - } -} diff --git a/Assets/Accounts/Scripts/User.cs b/Assets/Accounts/Scripts/User.cs index 74aa614..7a57238 100644 --- a/Assets/Accounts/Scripts/User.cs +++ b/Assets/Accounts/Scripts/User.cs @@ -2,40 +2,45 @@ using System; using System.Collections.Generic; using System.Linq; using UnityEngine; +using static PersistentDataController; /// /// A class holding all information of a user /// -[Serializable] public class User { /// - /// User nickname + /// Reference to the user stored data record /// - public string username; + private SavedUserData storedUserData; /// - /// The avatar of the user + /// Constructor /// - public Sprite avatar; + /// Reference to the user stored data record + public User(SavedUserData data) + { + this.storedUserData = data; + } /// - /// The total playtime of the user + /// Get the username /// - /// TODO: needs to be implemented - public double playtime; + /// + public string GetUsername() { return storedUserData.username; } /// - /// List of courses a user started/completed + /// Get the total playtime /// - [SerializeField] - public List courses = new List(); + /// + public double GetPlaytime() { return storedUserData.playtime; } /// - /// List of minigames a user played + /// Get the avatar /// - [SerializeField] - public List minigames = new List(); + /// + public Sprite GetAvatar() { return UserList.AVATARS[storedUserData.avatarIndex]; } + /// /// Get a list of all recently started courses @@ -46,10 +51,10 @@ public class User { // TODO: return better results (for now only return all courses) List> recentCourses = new List>(); - foreach (Progress courseProgress in courses) + foreach (var courseProgress in storedUserData.courses) { - CourseIndex idx = courseProgress.Get("courseIndex"); - float progress = courseProgress.Get("courseProgress"); + CourseIndex idx = courseProgress.courseIndex; + float progress = courseProgress.progress; recentCourses.Add(Tuple.Create(idx, progress)); } return recentCourses.Take(3).ToList(); @@ -63,31 +68,67 @@ public class User public List> GetRecommendedCourses() { List> recommenedCourses = new List>(); - if (courses.Count == 0) + if (storedUserData.courses.Count == 0) { recommenedCourses.Add(Tuple.Create(CourseIndex.FINGERSPELLING, 0.0f)); } else { // TODO: return better results (for now only return all courses) - foreach (Progress courseProgress in courses) + foreach (var courseProgress in storedUserData.courses) { - CourseIndex idx = courseProgress.Get("courseIndex"); - float progress = courseProgress.Get("courseProgress"); + CourseIndex idx = courseProgress.courseIndex; + float progress = courseProgress.progress; recommenedCourses.Add(Tuple.Create(idx, progress)); } } return recommenedCourses.Take(3).ToList(); } + /// + /// Get the progress of all courses the user did + /// + /// + public List GetCourses() + { + return storedUserData.courses; + } + /// /// Get the progress of a certain course /// /// Index of course /// Progress belonging to the courseIndex, null if course was not found - public Progress GetCourseProgress(CourseIndex courseIndex) + public SavedCourseProgress GetCourseProgress(CourseIndex courseIndex) { - return courses.Find((p) => p.Get("courseIndex") == courseIndex); + return storedUserData.courses.Find((p) => p.courseIndex == courseIndex); + } + + /// + /// Add new progress of a course + /// + /// SavedCourseProgress data record + public void AddCourseProgress(SavedCourseProgress progress) + { + storedUserData.courses.Add(progress); + } + + /// + /// Reset progress of a course + /// + /// Index of course + public void ResetCourseProgress(CourseIndex courseIndex) + { + storedUserData.courses.RemoveAll((p) => p.courseIndex == courseIndex); + } + + /// + /// Get the progress of all minigames the user did + /// + /// + public List GetMinigames() + { + return storedUserData.minigames; } /// @@ -95,8 +136,26 @@ public class User /// /// Index of the minigame /// Progress belonging to the minigameIndex, null if minigame was not found - public Progress GetMinigameProgress(MinigameIndex minigameIndex) + public SavedMinigameProgress GetMinigameProgress(MinigameIndex minigameIndex) { - return minigames.Find((p) => p.Get("minigameIndex") == minigameIndex); + return storedUserData.minigames.Find((p) => p.minigameIndex == minigameIndex); + } + + /// + /// Add new progress of a minigame + /// + /// SavedMinigameProgress data record + public void AddMinigameProgress(SavedMinigameProgress progress) + { + storedUserData.minigames.Add(progress); + } + + /// + /// Reset progress of a minigame + /// + /// Index of the minigame + public void ResetMinigameProgress(MinigameIndex minigameIndex) + { + storedUserData.minigames.RemoveAll((p) => p.minigameIndex == minigameIndex); } } diff --git a/Assets/Accounts/Scripts/UserAvatarList.cs b/Assets/Accounts/Scripts/UserAvatarList.cs new file mode 100644 index 0000000..e753689 --- /dev/null +++ b/Assets/Accounts/Scripts/UserAvatarList.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using UnityEngine; + +/// +/// Container to hold a reference to all possible user avatar sprites +/// +[CreateAssetMenu(menuName = "Create new Scriptable/User Avatar List")] +public class UserAvatarList : ScriptableObject +{ + /// + /// List of avatar sprites + /// + public List avatars = new List(); + + public void Awake() + { + UserList.AVATARS = avatars; + } +} diff --git a/Assets/Accounts/Scripts/Progress.cs.meta b/Assets/Accounts/Scripts/UserAvatarList.cs.meta similarity index 83% rename from Assets/Accounts/Scripts/Progress.cs.meta rename to Assets/Accounts/Scripts/UserAvatarList.cs.meta index f99f844..e6a265c 100644 --- a/Assets/Accounts/Scripts/Progress.cs.meta +++ b/Assets/Accounts/Scripts/UserAvatarList.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d887bc641cc7a8f4abf9d4eb34d26923 +guid: 81765ea55baf15d45b01b02187b02429 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Accounts/Scripts/UserCard.cs b/Assets/Accounts/Scripts/UserCard.cs index d807568..3bc3ea2 100644 --- a/Assets/Accounts/Scripts/UserCard.cs +++ b/Assets/Accounts/Scripts/UserCard.cs @@ -8,11 +8,6 @@ using UnityEngine.UI; /// public class UserCard : MonoBehaviour { - /// - /// Reference to the userlist - /// - public UserList userList; - /// /// User to upload info into this card /// @@ -53,8 +48,8 @@ public class UserCard : MonoBehaviour /// void Start() { - avatar.sprite = user.avatar; - username.text = user.username; + avatar.sprite = user.GetAvatar(); + username.text = user.GetUsername(); button.onClick.AddListener(selectUser); } @@ -63,10 +58,9 @@ public class UserCard : MonoBehaviour /// public void DeleteUser() { - if (userList.DeleteUser(user)) + if (UserList.DeleteUser(user.GetUsername())) { // User is removed, update and save - userList.Save(); updateUserCardContainer(); } else diff --git a/Assets/Accounts/Scripts/UserCreationScreen.cs b/Assets/Accounts/Scripts/UserCreationScreen.cs index 6b5cb77..34bf655 100644 --- a/Assets/Accounts/Scripts/UserCreationScreen.cs +++ b/Assets/Accounts/Scripts/UserCreationScreen.cs @@ -34,20 +34,9 @@ public class UserCreationScreen : MonoBehaviour /// public GameObject avatarPrefab; - /// - /// List of all sprites that are supported as avatars - /// - public List sprites = new List(); - - /// - /// Reference to the UserList ScriptableObject - /// - public UserList users; - /// /// Current selected avatar /// - [SerializeField] private int selectedAvatar = 0; /// @@ -55,6 +44,16 @@ public class UserCreationScreen : MonoBehaviour /// private List avatars = new List(); + /// + /// Reference to the back button, so we can deactivate it when the user cannot go back (when no user is found at startup) + /// + public GameObject backButton; + + /// + /// Boolean used to check whether the user can go back to the previous scene + /// + public static bool canGoBack = true; + /// /// Start is called before the first frame update @@ -62,8 +61,12 @@ public class UserCreationScreen : MonoBehaviour void Start() { errorMessage.SetActive(false); + backButton.SetActive(canGoBack); - for (int i = 0; i < sprites.Count; i++) + // Reset to default value + UserCreationScreen.canGoBack = true; + + for (int i = 0; i < UserList.AVATARS.Count; i++) { // Create instance of prefab GameObject instance = GameObject.Instantiate(avatarPrefab, avatarsContainer); @@ -79,7 +82,7 @@ public class UserCreationScreen : MonoBehaviour // Set background color background.color = selectedAvatar == i ? Color.blue : Color.gray; // Find correct component for setting the sprite - instance.transform.Find("Image").GetComponent().sprite = sprites[i]; + instance.transform.Find("Image").GetComponent().sprite = UserList.AVATARS[i]; } } @@ -113,10 +116,10 @@ public class UserCreationScreen : MonoBehaviour string username = inputName.text; if (IsValidUsername(username)) { - if (users.GetUserByUsername(username) == null) + if (UserList.GetUserByUsername(username) == null) { // Create a new entry in the UserList ScriptableObject - users.ChangeCurrentUser(users.CreateAndAddNewUser(username, sprites[selectedAvatar])); + UserList.AddUser(username, UserList.AVATARS[selectedAvatar]); SystemController.GetInstance().BackToPreviousScene(); } // Warn user that username already exists diff --git a/Assets/Accounts/Scripts/UserList.cs b/Assets/Accounts/Scripts/UserList.cs index 44916f0..4a17766 100644 --- a/Assets/Accounts/Scripts/UserList.cs +++ b/Assets/Accounts/Scripts/UserList.cs @@ -1,87 +1,33 @@ using System; using System.Collections.Generic; -using System.IO; using UnityEngine; /// /// Keep track of all users /// -[CreateAssetMenu(menuName = "Create new Scriptable/UserList")] -public class UserList : ScriptableObject +public static class UserList { /// - /// Helper class to enable serialization of the UserList class - /// (ScriptableObjects cannot be serialized) + /// List of possible avatar sprites /// - [Serializable] - public class StoredUserList - { - /// - /// The index of the current/last logged in user in the storedUsers list - /// - public int currentUserIndex = -1; - - /// - /// A list containing all users (which can be serialized) - /// - public List storedUsers = new List(); - } - - /// - /// Reference to the serializable version of UserList - /// - [SerializeField] - private StoredUserList storedUserList = new StoredUserList(); - - /// - /// Path of the .json-file to store all serialized data - /// - public static string PATH = null; - - /// - /// OnEnable will make sure the PATH-variable is correctly initialized - /// - void OnEnable() - { - // The PATH variable can be set by the testing framework, - // so we don't overwrite the actual userlist with test data - if (PATH == null) - { - PATH = $"{Application.persistentDataPath}/users.json"; - Load(); - } - } - - /// - /// Create a new user - /// - /// The username of the new user - /// Reference to the user avatar - /// A newly created user - public User CreateNewUser(string name, Sprite avatar) - { - User user = new User(); - user.username = name; - user.avatar = avatar; - return user; - } + public static List AVATARS = new List(); /// /// Create a new user and save (add to list) /// - /// The username of the new user + /// The username of the new user /// Reference to the user avatar /// A newly created user - public User CreateAndAddNewUser(string name, Sprite avatar) + public static User AddUser(string username, Sprite avatar) { - User user = CreateNewUser(name, avatar); - storedUserList.storedUsers.Add(user); - if (storedUserList.storedUsers.Count == 1) - { - storedUserList.currentUserIndex = 0; - } - Save(); - return user; + PersistentDataController pdc = PersistentDataController.GetInstance(); + PersistentDataController.SavedUserData data = new PersistentDataController.SavedUserData(); + data.username = username; + data.playtime = 0.0; + data.avatarIndex = AVATARS.IndexOf(avatar); + + pdc.AddUser(data); + return new User(data); } /// @@ -89,43 +35,61 @@ public class UserList : ScriptableObject /// /// The username of the user /// User-object if a user with such username was found, null otherwise - public User GetUserByUsername(string username) + public static User GetUserByUsername(string username) { - foreach (User user in storedUserList.storedUsers) - if (user.username == username) return user; + foreach (User user in GetUsers()) + if (user.GetUsername() == username) return user; return null; } + /// + /// Get a user by index + /// + /// The index of the user + /// User object + /// + public static User GetUserByIndex(int index) + { + List users = GetUsers(); + if (index < 0 || users.Count <= index) + throw new IndexOutOfRangeException(); + + return users[index]; + } + /// /// Get a list of all users currently stored /// /// A list of all users - public List GetUsers() + public static List GetUsers() { - return storedUserList.storedUsers; + PersistentDataController pdc = PersistentDataController.GetInstance(); + return pdc.GetUsers().ConvertAll((d) => new User(d)); } /// /// Get the current logged in user /// /// The current logged in user - public User GetCurrentUser() + public static User GetCurrentUser() { - if (storedUserList.storedUsers.Count == 0) - { + List users = GetUsers(); + if (users.Count == 0) return null; - } - return storedUserList.storedUsers[storedUserList.currentUserIndex]; + return users[PersistentDataController.GetInstance().GetCurrentUser()]; } /// - /// Get the index in the userlist of the current playing user + /// Get the index in the userlist of a user /// /// - public int GetCurrentUserIndex() + public static int IndexOf(string username) { - return storedUserList.currentUserIndex; + int idx = GetUsers().FindIndex((e) => e.GetUsername() == username); + if (idx < 0) + throw new KeyNotFoundException(); + return idx; } /// @@ -133,89 +97,66 @@ public class UserList : ScriptableObject /// /// Index of the user in the userlist /// - public void ChangeCurrentUser(int index) + public static void ChangeCurrentUser(int index) { - if (0 <= index && index < storedUserList.storedUsers.Count) - { - storedUserList.currentUserIndex = index; - } - else - { + if (index < 0 || GetUsers().Count <= index) throw new IndexOutOfRangeException(); - } + + PersistentDataController.GetInstance().SetCurrentUser(index, true); } + /// /// Change the current user /// - /// Reference to the user in the userlist + /// Username of the user /// - public void ChangeCurrentUser(User user) + public static void ChangeCurrentUser(string username) { - int idx = storedUserList.storedUsers.IndexOf(user); - if (idx < 0) - { - throw new KeyNotFoundException(); - } - storedUserList.currentUserIndex = idx; - } - - /// - /// Remove the user - /// - /// The index of the user in the userlist - /// true if user was successful removed, false otherwise e.GetUsername() == username); + try { ChangeCurrentUser(index); } + catch (IndexOutOfRangeException) { throw new KeyNotFoundException(); } } /// /// I am inevitable, *snap* /// - /// Reference to the user to be removed + /// The index of the user in the userlist /// true if the user was successful removed, false otherwise - public bool DeleteUser(User user) + /// + public static bool DeleteUser(int index) { - if (1 < storedUserList.storedUsers.Count) - { - if (storedUserList.currentUserIndex == storedUserList.storedUsers.Count - 1) - { - storedUserList.currentUserIndex--; - } + List users = GetUsers(); + if (index < 0 || users.Count <= index) + throw new IndexOutOfRangeException(); - return storedUserList.storedUsers.Remove(user); + if (1 < users.Count) + { + PersistentDataController.GetInstance().DeleteUser(index); + return true; } return false; } /// - /// Save the users + /// Delete a user from the userliset /// - public void Save() + /// Username of the user + /// true if the user was successful removed, false otherwise + /// + public static bool DeleteUser(string username) { - string json = JsonUtility.ToJson(storedUserList); - File.CreateText(PATH).Close(); - File.WriteAllText(PATH, json); + int index = GetUsers().FindIndex((e) => e.GetUsername() == username); + + try { return DeleteUser(index); } + catch (IndexOutOfRangeException) { throw new KeyNotFoundException(); } } /// - /// Override the current content of the userlist by what is stored on disk + /// Save the current UserList /// - public void Load() + public static void Save() { - storedUserList.storedUsers.Clear(); - storedUserList.currentUserIndex = -1; - - if (!File.Exists(PATH)) - { - Save(); - } - string text = File.ReadAllText(PATH); - storedUserList = JsonUtility.FromJson(text); + PersistentDataController.GetInstance().Save(); } } diff --git a/Assets/Accounts/Scripts/UserProgressScreen.cs b/Assets/Accounts/Scripts/UserProgressScreen.cs index 7ccafdb..a89fcbb 100644 --- a/Assets/Accounts/Scripts/UserProgressScreen.cs +++ b/Assets/Accounts/Scripts/UserProgressScreen.cs @@ -10,11 +10,6 @@ using UnityEngine.UI; /// public class UserProgressScreen : MonoBehaviour { - /// - /// Reference to the userlist - /// - public UserList userList; - /// /// Reference to the current user /// @@ -112,12 +107,12 @@ public class UserProgressScreen : MonoBehaviour void Start() { // Assign the current user - userList.Load(); - user = userList.GetCurrentUser(); + PersistentDataController.GetInstance().Load(); + user = UserList.GetCurrentUser(); // Set correct displayed items - username.text = user.username; - avatar.sprite = user.avatar; + username.text = user.GetUsername(); + avatar.sprite = user.GetAvatar(); // TODO: implement total playtime //playtime.text = $"Totale speeltijd: {user.playtime.ToString("0.00")}"; @@ -126,9 +121,10 @@ public class UserProgressScreen : MonoBehaviour int i = 0; // Display courses - coursesContainer.SetActive(user.courses.Count > 0); - emptyCourses.SetActive(user.courses.Count <= 0); - foreach (Progress courseProgress in user.courses) + var courses = user.GetCourses(); + coursesContainer.SetActive(courses.Count > 0); + emptyCourses.SetActive(courses.Count <= 0); + foreach (var courseProgress in courses) { // Create instance of prefab GameObject instance = GameObject.Instantiate(courseCardPrefab, coursesContainer.transform.Find("Viewport").Find("Content").transform); @@ -142,13 +138,14 @@ public class UserProgressScreen : MonoBehaviour // Store reference to background so we can apply fancy coloring Image background = instance.GetComponent(); background.color = Color.gray; - activities.Add(Tuple.Create(background, (int)courseProgress.Get("courseIndex"))); + activities.Add(Tuple.Create(background, (int)courseProgress.courseIndex)); } // Display minigames - minigamesContainer.SetActive(user.minigames.Count > 0); - emptyMinigames.SetActive(user.minigames.Count <= 0); - foreach (Progress minigameProgress in user.minigames) + var minigames = user.GetMinigames(); + minigamesContainer.SetActive(minigames.Count > 0); + emptyMinigames.SetActive(minigames.Count <= 0); + foreach (var minigameProgress in minigames) { // Create instance of prefab GameObject instance = GameObject.Instantiate(minigameCardPrefab, minigamesContainer.transform.Find("Viewport").Find("Content").transform); @@ -162,7 +159,7 @@ public class UserProgressScreen : MonoBehaviour // Store reference to background so we can apply fancy coloring Image background = instance.GetComponent(); background.color = Color.gray; - activities.Add(Tuple.Create(background, (int)minigameProgress.Get("minigameIndex"))); + activities.Add(Tuple.Create(background, (int)minigameProgress.minigameIndex)); } } @@ -183,7 +180,7 @@ public class UserProgressScreen : MonoBehaviour selectedActivity = newActivity; activities[selectedActivity].Item1.color = Color.blue; - if (selectedActivity < user.courses.Count) + if (selectedActivity < user.GetCourses().Count) { // TODO: create a better graph //DisplayCourseGraph((CourseIndex)activities[selectedActivity].Item2); @@ -211,9 +208,9 @@ public class UserProgressScreen : MonoBehaviour /// Index of the minigame private void DisplayMinigameGraph(MinigameIndex minigameIndex) { - Progress progress = user.GetMinigameProgress(minigameIndex); - List latestScores = progress.Get>("latestScores"); - List highestScores = progress.Get>("highestScores"); + var progress = user.GetMinigameProgress(minigameIndex); + List latestScores = progress.latestScores; + List highestScores = progress.highestScores; if (0 < highestScores.Count) { PlotGraph(latestScores.ConvertAll((s) => (double)s.scoreValue), highestScores[0].scoreValue); diff --git a/Assets/Accounts/Tests/AccountsTests.asmdef b/Assets/Accounts/Tests/AccountsTests.asmdef index df1d734..a492685 100644 --- a/Assets/Accounts/Tests/AccountsTests.asmdef +++ b/Assets/Accounts/Tests/AccountsTests.asmdef @@ -5,7 +5,8 @@ "UnityEngine.TestRunner", "UnityEditor.TestRunner", "AccountsScripts", - "InterfacesScripts" + "InterfacesScripts", + "ArchitectureScripts" ], "includePlatforms": [ "Editor" diff --git a/Assets/Accounts/Tests/ProgressTest.cs b/Assets/Accounts/Tests/ProgressTest.cs deleted file mode 100644 index 6500940..0000000 --- a/Assets/Accounts/Tests/ProgressTest.cs +++ /dev/null @@ -1,213 +0,0 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; -using UnityEngine; - -/// -/// Test the Progress class -/// -[TestFixture] -public class ProgressTest -{ - /// - /// Reference to the progress object to be tested - /// - private Progress progress; - - /// - /// A dummy serializable struct to perform test operations on - /// - [Serializable] - private struct SerializableStruct - { - public int r, g, b; - public float x, y, z; - } - - /// - /// A dummy non-serializable struct to perform test operations on - /// - private struct NonSerializableStruct - { - public int r, g, b; - public float x, y, z; - } - - /// - /// Setup the tests - /// - [SetUp] - public void Setup_Progress() - { - progress = new Progress(); - } - - /// - /// Test for creation of a new progress - /// - [Test] - public void Test_New_Progress() - { - Assert.IsNotNull(progress); - } - - /// - /// Test whether invalid data will not be added - /// - [Test] - public void Test_Progress_Add_InvalidData() - { - Assert.IsFalse(progress.AddOrUpdate("key", null)); - } - - /// - /// Test whether a duplicated key will be added - /// - [Test] - public void Test_Progress_Add_DuplicateKey() - { - progress.AddOrUpdate("key 1", 0); - Assert.IsTrue(progress.AddOrUpdate("key 1", 1)); - } - - /// - /// Test whether a int value can be added - /// - [Test] - public void Test_Progress_Add_Int() - { - Assert.IsTrue(progress.AddOrUpdate("key", 1)); - } - - /// - /// Test whether a double value can be added - /// - [Test] - public void Test_Progress_Add_Double() - { - Assert.IsTrue(progress.AddOrUpdate("key", 1.0)); - } - - /// - /// Test whether a string value can be added - /// - [Test] - public void Test_Progress_Add_String() - { - Assert.IsTrue(progress.AddOrUpdate("key", "Hello World!")); - } - - /// - /// Test whether a serializable struct can be added - /// - [Test] - public void Test_Progress_Add_SerializableStruct() - { - Assert.IsTrue(progress.AddOrUpdate("key", new SerializableStruct())); - } - - /// - /// Test whether a non-serializable struct will throw an error - /// - [Test] - public void Test_Progress_Add_NonSerializableStruct() - { - NonSerializableStruct nss = new NonSerializableStruct(); - Assert.Throws(delegate { progress.AddOrUpdate("key", nss); }); - } - - /// - /// Test whether a key is present - /// - [Test] - public void Test_Progress_Has_ValidKey() - { - progress.AddOrUpdate("key", 1); - Assert.IsTrue(progress.Has("key")); - } - - /// - /// Test whether a key is not present - /// - [Test] - public void Test_Progress_Has_InvalidKey() - { - Assert.IsFalse(progress.Has("non-existing key")); - } - - /// - /// Test whether an invalid key will throw an error - /// - [Test] - public void Test_Progress_Get_InvalidKey() - { - Assert.Throws(delegate { progress.Get("non-existing key"); }); - } - - /// - /// Test whether an invalid type will throw an error - /// - [Test] - public void Test_Progress_Get_InvalidType() - { - progress.AddOrUpdate("key", 123456789); - Assert.Throws(delegate { progress.Get("key"); }); - } - - /// - /// Test whether a value is correctly updated - /// - [Test] - public void Test_Progress_Update() - { - progress.AddOrUpdate("key", 1); - Assert.AreEqual(progress.Get("key"), 1); - progress.AddOrUpdate("key", 2); - Assert.AreEqual(progress.Get("key"), 2); - } - - /// - /// Test whether a int value can be read - /// - [Test] - public void Test_Progress_Get_Int() - { - progress.AddOrUpdate("key", 1); - Assert.AreEqual(progress.Get("key"), 1); - } - - /// - /// Test whether a double value can be read - /// - [Test] - public void Test_Progress_Get_Double() - { - progress.AddOrUpdate("key", 1.0); - Assert.AreEqual(progress.Get("key"), 1.0); - } - - /// - /// Test whether a string value can be read - /// - [Test] - public void Test_Progress_Get_String() - { - progress.AddOrUpdate("key", "Hello World!"); - Assert.AreEqual(progress.Get("key"), "Hello World!"); - } - - /// - /// Test whether a serializable struct can be read - /// - [Test] - public void Test_Progress_Get_Struct() - { - int R = 1, G = 10, B = 100; - float X = 0.1f, Y = 0.01f, Z = 0.001f; - SerializableStruct data = new SerializableStruct { r = R, g = G, b = B, x = X, y = Y, z = Z }; - progress.AddOrUpdate("key", data); - SerializableStruct result = progress.Get("key"); - Assert.AreEqual(result, data); - } -} diff --git a/Assets/Accounts/Tests/UserListTest.cs b/Assets/Accounts/Tests/UserListTest.cs index 4adff57..faef19b 100644 --- a/Assets/Accounts/Tests/UserListTest.cs +++ b/Assets/Accounts/Tests/UserListTest.cs @@ -1,8 +1,8 @@ using NUnit.Framework; using System; -using System.Collections; using System.Collections.Generic; using System.IO; +using UnityEditor; using UnityEngine; /// @@ -12,20 +12,10 @@ using UnityEngine; public class UserListTest { /// - /// Create a new path so the existing users.json file will not be overwritten + /// Create a new path so the existing .json file will not be overwritten /// private static string PATH = $"{Application.persistentDataPath}/unit_test_users.json"; - /// - /// NUnit test magic (for skipping the setup) - /// - public const string SKIP_SETUP = "SKIP_SETUP"; - - /// - /// Reference to the userlist to be tested - /// - private UserList userList; - /// /// Helper variable for quick user creation /// @@ -34,11 +24,7 @@ public class UserListTest /// /// Helper variable for quick user creation /// - private Sprite avatar = Sprite.Create( - Texture2D.blackTexture, - new Rect(0, 0, Texture2D.blackTexture.width, Texture2D.blackTexture.height), - new Vector2(0.5f, 0.5f) - ); + private Sprite avatar = null; /// /// Setup the tests @@ -46,27 +32,14 @@ public class UserListTest [SetUp] public void Setup_UserList() { - // Check whether the current test needs to skip the setup - ArrayList cat = TestContext.CurrentContext.Test.Properties["_CATEGORIES"] as ArrayList; - bool skip = cat != null && cat.Contains(SKIP_SETUP); - if (!skip) - { - // The actual setup code - UserList.PATH = UserListTest.PATH; - userList = ScriptableObject.CreateInstance(); - } - } + PersistentDataController.PATH = UserListTest.PATH; - /// - /// Test whether the UserList.PATH is correctly set - /// - [Test] - [Category(SKIP_SETUP)] - public void Test_UserList_OnEnable() - { - UserList.PATH = null; - userList = ScriptableObject.CreateInstance(); - Assert.AreEqual($"{Application.persistentDataPath}/users.json", UserList.PATH); + if (File.Exists(PATH)) + File.Delete(PATH); + + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); + avatar = UserList.AVATARS[0]; } /// @@ -75,36 +48,22 @@ public class UserListTest [Test] public void Test_New_UserList() { - Assert.IsNotNull(userList); - Assert.Zero(userList.GetUsers().Count); + Assert.Zero(UserList.GetUsers().Count); } /// /// Test for creation of new user (without adding the user to the list) /// [Test] - public void Test_UserList_CreateNewUser() + public void Test_UserList_AddUser() { - User user = userList.CreateNewUser(username, avatar); + Assert.Zero(UserList.GetUsers().Count); + User user = UserList.AddUser(username, avatar); Assert.IsNotNull(user); - Assert.Zero(userList.GetUsers().Count); - Assert.AreEqual(username, user.username); - Assert.AreEqual(avatar, user.avatar); - } - - /// - /// Test for creating a new user and adding the user to the list - /// - public void Test_UserList_CreateAndAddNewUser() - { - Assert.AreEqual(-1, userList.GetCurrentUserIndex()); - User user = userList.CreateAndAddNewUser(username, avatar); - - Assert.IsNotNull(user); - Assert.AreEqual(1, userList.GetUsers().Count); - Assert.AreEqual(user, userList.GetUsers()[0]); - Assert.Zero(userList.GetCurrentUserIndex()); + Assert.AreEqual(1, UserList.GetUsers().Count); + Assert.AreEqual(username, user.GetUsername()); + Assert.AreEqual(avatar, user.GetAvatar()); } /// @@ -113,9 +72,9 @@ public class UserListTest [Test] public void Test_UserList_GetUserByUsername_Valid() { - User u = userList.CreateAndAddNewUser(username, avatar); - User v = userList.GetUserByUsername(username); - Assert.AreEqual(u, v); + User u = UserList.AddUser(username, avatar); + User v = UserList.GetUserByUsername(username); + Assert.AreEqual(u.GetUsername(), v.GetUsername()); } /// @@ -124,32 +83,70 @@ public class UserListTest [Test] public void Test_UserList_GetUserByUsername_Null() { - User user = userList.GetUserByUsername("not-a-user"); + User user = UserList.GetUserByUsername("not-a-user"); Assert.IsNull(user); } + + + /// + /// Test whether an existing user can be found by its username + /// + [Test] + public void Test_UserList_GetUserByIndex_Valid() + { + User u = UserList.AddUser(username, avatar); + User v = UserList.GetUserByIndex(0); + Assert.AreEqual(u.GetUsername(), v.GetUsername()); + } + + /// + /// Test whether a non-existing user can not be found + /// + [Test] + public void Test_UserList_GetUserByIndex_Exception() + { + Assert.Throws(delegate { UserList.GetUserByIndex(0); }); + } + + /// + /// Test whether a userlist is correctly returned + /// + [Test] + public void Test_UserList_GetUsers() + { + List u = new List(); + for (int i = 0; i < 5; i++) + u.Add(UserList.AddUser($"{username}_{i}", avatar)); + + List v = UserList.GetUsers(); + Assert.AreEqual(v.Count, u.Count); + for (int i = 0; i < 5; i++) + Assert.AreEqual(u[i].GetUsername(), v[i].GetUsername()); + } + /// /// Test whether the correct current user is returned /// [Test] public void Test_UserList_GetCurrentUser() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - userList.ChangeCurrentUser(2); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + UserList.ChangeCurrentUser(2); - User W = userList.GetCurrentUser(); - Assert.AreEqual(w, W); + User W = UserList.GetCurrentUser(); + Assert.AreEqual(w.GetUsername(), W.GetUsername()); } /// /// Test whether a null user is returned when the userlist is empty /// [Test] - public void Test_UserList_GetCurrent_Empty() + public void Test_UserList_GetCurrentUser_Empty() { - User user = userList.GetCurrentUser(); + User user = UserList.GetCurrentUser(); Assert.IsNull(user); } @@ -157,24 +154,30 @@ public class UserListTest /// Test whether the correct index is returned for the current user /// [Test] - public void Test_UserList_GetCurrentUserIndex() + public void Test_UserList_IndexOf_Valid() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - userList.ChangeCurrentUser(2); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + UserList.ChangeCurrentUser(2); - int idx = userList.GetCurrentUserIndex(); - Assert.AreEqual(2, idx); + Assert.AreEqual(0, UserList.IndexOf(u.GetUsername())); + Assert.AreEqual(1, UserList.IndexOf(v.GetUsername())); + Assert.AreEqual(2, UserList.IndexOf(w.GetUsername())); } /// - /// Test whether a bad index is returned when the userlist is empty + /// Test whether the correct index is returned for the current user /// [Test] - public void Test_UserList_GetCurrentUserIndex_Empty() + public void Test_UserList_IndexOf_Exception() { - Assert.AreEqual(-1, userList.GetCurrentUserIndex()); + User u = new User(new PersistentDataController.SavedUserData() + { + username = username, + avatarIndex = 0 + }); + Assert.Throws(delegate { UserList.IndexOf(u.GetUsername()); }); } /// @@ -183,13 +186,13 @@ public class UserListTest [Test] public void Test_UserList_ChangeCurrentUser_ValidIndex() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - userList.ChangeCurrentUser(2); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + UserList.ChangeCurrentUser(2); - User W = userList.GetCurrentUser(); - Assert.AreEqual(w, W); + User W = UserList.GetCurrentUser(); + Assert.AreEqual(w.GetUsername(), W.GetUsername()); } /// @@ -198,11 +201,11 @@ public class UserListTest [Test] public void Test_UserList_ChangeCurrentUser_InvalidIndex() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - Assert.Throws(delegate { userList.ChangeCurrentUser(-1); }); - Assert.Throws(delegate { userList.ChangeCurrentUser(5); }); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + Assert.Throws(delegate { UserList.ChangeCurrentUser(-1); }); + Assert.Throws(delegate { UserList.ChangeCurrentUser(5); }); } /// @@ -211,41 +214,45 @@ public class UserListTest [Test] public void Test_UserList_ChangeCurrentUser_IndexEmpty() { - Assert.Throws(delegate { userList.ChangeCurrentUser(0); }); + Assert.Throws(delegate { UserList.ChangeCurrentUser(0); }); } /// /// Test whether the current user is correctly changed /// [Test] - public void Test_UserList_ChangeCurrentUser_ValidUser() + public void Test_UserList_ChangeCurrentUser_ValidUsername() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - userList.ChangeCurrentUser(v); - User V = userList.GetCurrentUser(); - Assert.AreEqual(v, V); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + UserList.ChangeCurrentUser(v.GetUsername()); + User V = UserList.GetCurrentUser(); + Assert.AreEqual(v.GetUsername(), V.GetUsername()); } /// /// Test whether the current user is not changed when a non-existing user is given /// [Test] - public void Test_UserList_ChangeCurrentUser_InvalidUser() + public void Test_UserList_ChangeCurrentUser_InvalidUsername() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateNewUser($"{username}_{'v'}", avatar); - Assert.Throws(delegate { userList.ChangeCurrentUser(v); }); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = new User(new PersistentDataController.SavedUserData() + { + username = $"{username}_{'v'}", + avatarIndex = 0 + }); + Assert.Throws(delegate { UserList.ChangeCurrentUser(v.GetUsername()); }); } /// /// Test whether the current user is not changed when a null user is given /// [Test] - public void Test_UserList_ChangeCurrentUser_NullUser() + public void Test_UserList_ChangeCurrentUser_NullUsername() { - Assert.Throws(delegate { userList.ChangeCurrentUser(null); }); + Assert.Throws(delegate { UserList.ChangeCurrentUser(null); }); } /// @@ -254,10 +261,10 @@ public class UserListTest [Test] public void Test_UserList_DeleteUser_ValidIndex() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - Assert.IsTrue(userList.DeleteUser(1)); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + Assert.IsTrue(UserList.DeleteUser(1)); } /// @@ -266,11 +273,11 @@ public class UserListTest [Test] public void Test_UserList_DeleteUser_InValidIndex() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - Assert.IsFalse(userList.DeleteUser(-1)); - Assert.IsFalse(userList.DeleteUser(5)); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + Assert.Throws(delegate { UserList.DeleteUser(-1); }); + Assert.Throws(delegate { UserList.DeleteUser(5); }); } /// @@ -279,44 +286,61 @@ public class UserListTest [Test] public void Test_UserList_DeleteUser_IndexEmpty() { - Assert.IsFalse(userList.DeleteUser(0)); + Assert.Throws(delegate { UserList.DeleteUser(0); }); } /// /// Test whether deleting an existing user will correctly remove the user and set the currentUserIndex correctly /// [Test] - public void Test_UserList_DeleteUser_LastValid() + public void Test_UserList_DeleteUser_BeforeCurrentUser() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - userList.ChangeCurrentUser(2); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + UserList.ChangeCurrentUser(1); - Assert.AreEqual(3, userList.GetUsers().Count); - Assert.AreEqual(2, userList.GetCurrentUserIndex()); - Assert.IsTrue(userList.DeleteUser(w)); - Assert.AreEqual(2, userList.GetUsers().Count); - Assert.AreEqual(1, userList.GetCurrentUserIndex()); + Assert.AreEqual(3, UserList.GetUsers().Count); + Assert.AreEqual(1, UserList.IndexOf(UserList.GetCurrentUser().GetUsername())); + Assert.IsTrue(UserList.DeleteUser(u.GetUsername())); + Assert.AreEqual(2, UserList.GetUsers().Count); + Assert.AreEqual(0, UserList.IndexOf(UserList.GetCurrentUser().GetUsername())); } /// - /// Test whether deleting an existing user will remove the user correctly + /// Test whether deleting an existing user will correctly remove the user and set the currentUserIndex correctly /// - /// This will change the currentUserIndex to point to another user [Test] - public void Test_UserList_DeleteUser_FirstValid() + public void Test_UserList_DeleteUser_CurrentUser() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateAndAddNewUser($"{username}_{'v'}", avatar); - User w = userList.CreateAndAddNewUser($"{username}_{'w'}", avatar); - userList.ChangeCurrentUser(0); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + UserList.ChangeCurrentUser(1); - Assert.AreEqual(3, userList.GetUsers().Count); - Assert.AreEqual(0, userList.GetCurrentUserIndex()); - Assert.IsTrue(userList.DeleteUser(u)); - Assert.AreEqual(2, userList.GetUsers().Count); - Assert.AreEqual(0, userList.GetCurrentUserIndex()); + Assert.AreEqual(3, UserList.GetUsers().Count); + Assert.AreEqual(1, UserList.IndexOf(UserList.GetCurrentUser().GetUsername())); + Assert.IsTrue(UserList.DeleteUser(v.GetUsername())); + Assert.AreEqual(2, UserList.GetUsers().Count); + Assert.AreEqual(0, UserList.IndexOf(UserList.GetCurrentUser().GetUsername())); + } + + /// + /// Test whether deleting an existing user will correctly remove the user and set the currentUserIndex correctly + /// + [Test] + public void Test_UserList_DeleteUser_AfterCurrentUser() + { + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = UserList.AddUser($"{username}_{'v'}", avatar); + User w = UserList.AddUser($"{username}_{'w'}", avatar); + UserList.ChangeCurrentUser(1); + + Assert.AreEqual(3, UserList.GetUsers().Count); + Assert.AreEqual(1, UserList.IndexOf(UserList.GetCurrentUser().GetUsername())); + Assert.IsTrue(UserList.DeleteUser(w.GetUsername())); + Assert.AreEqual(2, UserList.GetUsers().Count); + Assert.AreEqual(1, UserList.IndexOf(UserList.GetCurrentUser().GetUsername())); } /// @@ -325,12 +349,16 @@ public class UserListTest [Test] public void Test_UserList_DeleteUser_Invalid() { - User u = userList.CreateAndAddNewUser($"{username}_{'u'}", avatar); - User v = userList.CreateNewUser($"{username}_{'v'}", avatar); + User u = UserList.AddUser($"{username}_{'u'}", avatar); + User v = new User(new PersistentDataController.SavedUserData() + { + username = $"{username}_{'v'}", + avatarIndex = 0 + }); - Assert.AreEqual(1, userList.GetUsers().Count); - Assert.IsFalse(userList.DeleteUser(v)); - Assert.AreEqual(1, userList.GetUsers().Count); + Assert.AreEqual(1, UserList.GetUsers().Count); + Assert.Throws(delegate { UserList.DeleteUser(v.GetUsername()); }); + Assert.AreEqual(1, UserList.GetUsers().Count); } /// @@ -339,10 +367,14 @@ public class UserListTest [Test] public void Test_UserList_DeleteUser_Empty() { - User user = userList.CreateNewUser(username, avatar); - Assert.Zero(userList.GetUsers().Count); - Assert.IsFalse(userList.DeleteUser(user)); - Assert.Zero(userList.GetUsers().Count); + User user = new User(new PersistentDataController.SavedUserData() + { + username = username, + avatarIndex = 0 + }); + Assert.Zero(UserList.GetUsers().Count); + Assert.Throws(delegate { UserList.DeleteUser(user.GetUsername()); }); + Assert.Zero(UserList.GetUsers().Count); } /// @@ -351,23 +383,16 @@ public class UserListTest [Test] public void Test_UserList_Save_New() { - if (File.Exists(PATH)) - { - File.Delete(PATH); - } - List u = new List(); for (int i = 0; i < 5; i++) - { - u.Add(userList.CreateAndAddNewUser($"{username}_{i}", avatar)); - } - userList.ChangeCurrentUser(3); - userList.Save(); + u.Add(UserList.AddUser($"{username}_{i}", avatar)); + + UserList.ChangeCurrentUser(3); + UserList.Save(); FileAssert.Exists(PATH); string content = File.ReadAllText(PATH); - int id = avatar.GetInstanceID(); - string expected = $"{{\"currentUserIndex\":3,\"storedUsers\":[{{\"username\":\"u5erNam3_0\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}},{{\"username\":\"u5erNam3_1\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}},{{\"username\":\"u5erNam3_2\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}},{{\"username\":\"u5erNam3_3\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}},{{\"username\":\"u5erNam3_4\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}}]}}"; + string expected = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"u5erNam3_0\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}},{{\"entries\":[],\"username\":\"u5erNam3_1\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}},{{\"entries\":[],\"username\":\"u5erNam3_2\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}},{{\"entries\":[],\"username\":\"u5erNam3_3\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}},{{\"entries\":[],\"username\":\"u5erNam3_4\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":3,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; Assert.AreEqual(expected, content); } @@ -385,16 +410,14 @@ public class UserListTest List u = new List(); for (int i = 0; i < 5; i++) - { - u.Add(userList.CreateAndAddNewUser($"{username}_{i}", avatar)); - } - userList.ChangeCurrentUser(3); - userList.Save(); + u.Add(UserList.AddUser($"{username}_{i}", avatar)); + + UserList.ChangeCurrentUser(3); + UserList.Save(); FileAssert.Exists(PATH); string content = File.ReadAllText(PATH); - int id = avatar.GetInstanceID(); - string expected = $"{{\"currentUserIndex\":3,\"storedUsers\":[{{\"username\":\"u5erNam3_0\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}},{{\"username\":\"u5erNam3_1\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}},{{\"username\":\"u5erNam3_2\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}},{{\"username\":\"u5erNam3_3\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}},{{\"username\":\"u5erNam3_4\",\"avatar\":{{\"instanceID\":{id}}},\"playtime\":0.0,\"courses\":[],\"minigames\":[]}}]}}"; + string expected = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"u5erNam3_0\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}},{{\"entries\":[],\"username\":\"u5erNam3_1\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}},{{\"entries\":[],\"username\":\"u5erNam3_2\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}},{{\"entries\":[],\"username\":\"u5erNam3_3\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}},{{\"entries\":[],\"username\":\"u5erNam3_4\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":3,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; Assert.AreEqual(expected, content); } @@ -404,67 +427,11 @@ public class UserListTest [Test] public void Test_UserList_Save_Empty() { - userList.Save(); + UserList.Save(); FileAssert.Exists(PATH); string content = File.ReadAllText(PATH); - string expected = "{\"currentUserIndex\":-1,\"storedUsers\":[]}"; + string expected = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[],\"currentUser\":-1,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; Assert.AreEqual(expected, content); } - - /// - /// Test whether a userlist (containing some users) is correrctly loaded - /// - [Test] - public void Test_UserList_Load() - { - List u = new List(); - for (int i = 0; i < 5; i++) - { - u.Add(userList.CreateAndAddNewUser($"{username}_{i}", avatar)); - } - userList.ChangeCurrentUser(3); - userList.Save(); - - userList.Load(); - Assert.AreEqual(userList.GetUsers().Count, u.Count); - Assert.AreEqual(userList.GetCurrentUserIndex(), 3); - List v = userList.GetUsers(); - for (int i = 0; i < 5; i++) - { - Assert.AreEqual(u[i].username, v[i].username); - Assert.AreEqual(u[i].avatar, v[i].avatar); - } - } - - /// - /// Test whether an empty userlist is correctly loaded - /// - [Test] - public void Test_UserList_Load_Empty() - { - userList.Save(); - userList.Load(); - Assert.Zero(userList.GetUsers().Count); - Assert.AreEqual(-1, userList.GetCurrentUserIndex()); - } - - /// - /// Test if the user save file is not found, a new one will be created and an empty userlist will be loaded - /// - [Test] - public void Test_UserList_Load_NotFound() - { - List u = new List(); - for (int i = 0; i < 5; i++) - { - u.Add(userList.CreateAndAddNewUser($"{username}_{i}", avatar)); - } - userList.ChangeCurrentUser(3); - userList.Save(); - - File.Delete(PATH); - userList.Load(); - Assert.Zero(userList.GetUsers().Count); - } } diff --git a/Assets/Accounts/Tests/UserTest.cs b/Assets/Accounts/Tests/UserTest.cs index 81d4045..e95924d 100644 --- a/Assets/Accounts/Tests/UserTest.cs +++ b/Assets/Accounts/Tests/UserTest.cs @@ -19,7 +19,10 @@ public class UserTest [SetUp] public void Setup_User() { - user = new User(); + PersistentDataController.SavedUserData data = new PersistentDataController.SavedUserData(); + data.username = "username"; + data.avatarIndex = 0; + user = new User(data); } @@ -30,8 +33,8 @@ public class UserTest public void Test_New_User() { Assert.NotNull(user); - Assert.Zero(user.courses.Count); - Assert.Zero(user.minigames.Count); + Assert.Zero(user.GetCourses().Count); + Assert.Zero(user.GetMinigames().Count); } /// @@ -40,10 +43,10 @@ public class UserTest [Test] public void Test_User_AddCourse() { - Progress p = new Progress(); - user.courses.Add(p); - Assert.AreEqual(user.courses.Count, 1); - Assert.Zero(user.minigames.Count); + var p = new PersistentDataController.SavedCourseProgress(); + user.AddCourseProgress(p); + Assert.AreEqual(user.GetCourses().Count, 1); + Assert.Zero(user.GetMinigames().Count); } /// @@ -52,10 +55,10 @@ public class UserTest [Test] public void Test_User_AddMinigame() { - Progress p = new Progress(); - user.minigames.Add(p); - Assert.Zero(user.courses.Count); - Assert.AreEqual(user.minigames.Count, 1); + var p = new PersistentDataController.SavedMinigameProgress(); + user.AddMinigameProgress(p); + Assert.Zero(user.GetCourses().Count); + Assert.AreEqual(user.GetMinigames().Count, 1); } /// @@ -73,10 +76,10 @@ public class UserTest [Test] public void Test_User_GetRecentCourses_All() { - Progress p = new Progress(); - p.AddOrUpdate("courseIndex", CourseIndex.FINGERSPELLING); - p.AddOrUpdate("courseProgress", 0.5f); - user.courses.Add(p); + var p = new PersistentDataController.SavedCourseProgress(); + p.courseIndex = CourseIndex.FINGERSPELLING; + p.progress = 0.5f; + user.AddCourseProgress(p); List> list = user.GetRecentCourses(); Assert.AreEqual(list.Count, 1); Assert.AreEqual(list[0].Item1, CourseIndex.FINGERSPELLING); @@ -101,10 +104,10 @@ public class UserTest [Test] public void Test_User_GetRecommendedCourses_All() { - Progress p = new Progress(); - p.AddOrUpdate("courseIndex", CourseIndex.FINGERSPELLING); - p.AddOrUpdate("courseProgress", 0.5f); - user.courses.Add(p); + var p = new PersistentDataController.SavedCourseProgress(); + p.courseIndex = CourseIndex.FINGERSPELLING; + p.progress = 0.5f; + user.AddCourseProgress(p); List> list = user.GetRecommendedCourses(); Assert.AreEqual(list.Count, 1); Assert.AreEqual(list[0].Item1, CourseIndex.FINGERSPELLING); @@ -127,13 +130,27 @@ public class UserTest [Test] public void Test_User_GetCourseProgress_Valid() { - Progress p = new Progress(); - p.AddOrUpdate("courseIndex", CourseIndex.FINGERSPELLING); - p.AddOrUpdate("courseProgress", 3.14159265f); - user.courses.Add(p); - Progress q = user.GetCourseProgress(CourseIndex.FINGERSPELLING); - Assert.AreEqual(q.Get("courseIndex"), CourseIndex.FINGERSPELLING); - Assert.AreEqual(q.Get("courseProgress"), 3.14159265f); + var p = new PersistentDataController.SavedCourseProgress(); + p.courseIndex = CourseIndex.FINGERSPELLING; + p.progress = 3.14159265f; + user.AddCourseProgress(p); + var q = user.GetCourseProgress(CourseIndex.FINGERSPELLING); + Assert.AreEqual(q.courseIndex, CourseIndex.FINGERSPELLING); + Assert.AreEqual(q.progress, 3.14159265f); + } + + /// + /// Test progress of a course is correctly reset (aka removed) + /// + [Test] + public void Test_User_ResetCourseProgres() + { + var p = new PersistentDataController.SavedCourseProgress(); + p.courseIndex = CourseIndex.FINGERSPELLING; + user.AddCourseProgress(p); + Assert.IsNotNull(user.GetCourseProgress(CourseIndex.FINGERSPELLING)); + user.ResetCourseProgress(CourseIndex.FINGERSPELLING); + Assert.IsNull(user.GetCourseProgress(CourseIndex.FINGERSPELLING)); } /// @@ -145,9 +162,9 @@ public class UserTest Assert.Null(user.GetMinigameProgress(MinigameIndex.SPELLING_BEE)); Assert.Null(user.GetMinigameProgress((MinigameIndex)100)); - Progress p = new Progress(); - p.AddOrUpdate("minigameIndex", MinigameIndex.SPELLING_BEE); - user.minigames.Add(p); + var p = new PersistentDataController.SavedMinigameProgress(); + p.minigameIndex = MinigameIndex.SPELLING_BEE; + user.AddMinigameProgress(p); Assert.Null(user.GetMinigameProgress(MinigameIndex.HANGMAN)); } @@ -157,10 +174,26 @@ public class UserTest [Test] public void Test_User_GetMinigameProgress_Valid() { - Progress p = new Progress(); - p.AddOrUpdate("minigameIndex", MinigameIndex.SPELLING_BEE); - user.minigames.Add(p); - Progress q = user.GetMinigameProgress(MinigameIndex.SPELLING_BEE); - Assert.AreEqual(q.Get("minigameIndex"), CourseIndex.FINGERSPELLING); + var p = new PersistentDataController.SavedMinigameProgress(); + p.minigameIndex = MinigameIndex.SPELLING_BEE; + user.AddMinigameProgress(p); + var q = user.GetMinigameProgress(MinigameIndex.SPELLING_BEE); + Assert.AreEqual(q.minigameIndex, MinigameIndex.SPELLING_BEE); + Assert.Zero(q.latestScores.Count); + Assert.Zero(q.highestScores.Count); + } + + /// + /// Test progress of a minigame is correctly reset (aka removed) + /// + [Test] + public void Test_User_ResetMinigameProgres() + { + var p = new PersistentDataController.SavedMinigameProgress(); + p.minigameIndex = MinigameIndex.SPELLING_BEE; + user.AddMinigameProgress(p); + Assert.IsNotNull(user.GetMinigameProgress(MinigameIndex.SPELLING_BEE)); + user.ResetMinigameProgress(MinigameIndex.SPELLING_BEE); + Assert.IsNull(user.GetMinigameProgress(MinigameIndex.SPELLING_BEE)); } } diff --git a/Assets/Resources.meta b/Assets/Common/Animations.meta similarity index 77% rename from Assets/Resources.meta rename to Assets/Common/Animations.meta index a546ddd..c69f34c 100644 --- a/Assets/Resources.meta +++ b/Assets/Common/Animations.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c3f7371598add9549b5351c44a9e17b3 +guid: 53d0f67255b6c3247a9cad0b471eb5cc folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Common/Animations/Back.controller b/Assets/Common/Animations/Back.controller new file mode 100644 index 0000000..77f4478 --- /dev/null +++ b/Assets/Common/Animations/Back.controller @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Back + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 2880384107061315038} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &2880384107061315038 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 0} diff --git a/Assets/Common/Animations/Back.controller.meta b/Assets/Common/Animations/Back.controller.meta new file mode 100644 index 0000000..ab959e8 --- /dev/null +++ b/Assets/Common/Animations/Back.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ca332ce2e8825e34f82740a12f57810c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Buttons.controller b/Assets/Common/Animations/Buttons.controller new file mode 100644 index 0000000..bd36276 --- /dev/null +++ b/Assets/Common/Animations/Buttons.controller @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Buttons + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 5848517627646673126} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &5848517627646673126 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 0} diff --git a/Assets/Common/Animations/Buttons.controller.meta b/Assets/Common/Animations/Buttons.controller.meta new file mode 100644 index 0000000..f14b962 --- /dev/null +++ b/Assets/Common/Animations/Buttons.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 196bc314c0fd00a42aede7fc33ab93f5 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Circle (1).controller b/Assets/Common/Animations/Circle (1).controller new file mode 100644 index 0000000..5195afc --- /dev/null +++ b/Assets/Common/Animations/Circle (1).controller @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1107 &-6272214886661875936 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 0} +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Circle (1) + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: -6272214886661875936} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} diff --git a/Assets/Common/Animations/Circle (1).controller.meta b/Assets/Common/Animations/Circle (1).controller.meta new file mode 100644 index 0000000..29440a6 --- /dev/null +++ b/Assets/Common/Animations/Circle (1).controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47b8ff2adcd4fa64981587b8490f907b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Circle (2).controller b/Assets/Common/Animations/Circle (2).controller new file mode 100644 index 0000000..4521af0 --- /dev/null +++ b/Assets/Common/Animations/Circle (2).controller @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1107 &-6308562069067372193 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 0} +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Circle (2) + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: -6308562069067372193} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} diff --git a/Assets/Common/Animations/Circle (2).controller.meta b/Assets/Common/Animations/Circle (2).controller.meta new file mode 100644 index 0000000..199c893 --- /dev/null +++ b/Assets/Common/Animations/Circle (2).controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1871dbf4971f77743ad5c9793fe979f2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Circle (3).controller b/Assets/Common/Animations/Circle (3).controller new file mode 100644 index 0000000..c501963 --- /dev/null +++ b/Assets/Common/Animations/Circle (3).controller @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Circle (3) + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 3271612862522806351} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &3271612862522806351 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 0} diff --git a/Assets/Common/Animations/Circle (3).controller.meta b/Assets/Common/Animations/Circle (3).controller.meta new file mode 100644 index 0000000..62db9fc --- /dev/null +++ b/Assets/Common/Animations/Circle (3).controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51c408377313b474fa55f6c01c841728 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Circle (4).controller b/Assets/Common/Animations/Circle (4).controller new file mode 100644 index 0000000..b08e514 --- /dev/null +++ b/Assets/Common/Animations/Circle (4).controller @@ -0,0 +1,72 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Circle (4) + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 2495558535500084297} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1102 &1544610970356599174 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_course_item + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: [] + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 20b914049e2da0641a3179082f6e0834, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1107 &2495558535500084297 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 1544610970356599174} + m_Position: {x: 310.9442, y: 121.69531, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 1544610970356599174} diff --git a/Assets/Common/Animations/Circle (4).controller.meta b/Assets/Common/Animations/Circle (4).controller.meta new file mode 100644 index 0000000..6d8cf2a --- /dev/null +++ b/Assets/Common/Animations/Circle (4).controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d2ff77db5e35814cbe7ed8d0ca8a00b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Course Item.controller b/Assets/Common/Animations/Course Item.controller new file mode 100644 index 0000000..dab99c3 --- /dev/null +++ b/Assets/Common/Animations/Course Item.controller @@ -0,0 +1,72 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1102 &-5646733052509372245 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_activity_item + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: [] + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 20b914049e2da0641a3179082f6e0834, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Course Item + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 731691231060793380} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &731691231060793380 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: -5646733052509372245} + m_Position: {x: 200, y: 0, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: -5646733052509372245} diff --git a/Assets/Common/Animations/Course Item.controller.meta b/Assets/Common/Animations/Course Item.controller.meta new file mode 100644 index 0000000..5e97864 --- /dev/null +++ b/Assets/Common/Animations/Course Item.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f13ed5d552355e419355775df689c02 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/CourseMenu EnterFrom ListCourses+CourseActivity.playable b/Assets/Common/Animations/CourseMenu EnterFrom ListCourses+CourseActivity.playable new file mode 100644 index 0000000..31c553a --- /dev/null +++ b/Assets/Common/Animations/CourseMenu EnterFrom ListCourses+CourseActivity.playable @@ -0,0 +1,288 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7334886842214567036 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 460ce3dd5a966464d9d44fbbc21865ba, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-6792405358425382423 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -7334886842214567036} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -6792405358425382423} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_slide_left + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-4585668829722489210 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 2943149940030982406} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -4585668829722489210} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_slide_up + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: CourseMenu EnterFrom ListCourses+CourseActivity + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: -4585668829722489210} + - {fileID: -6792405358425382423} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &2943149940030982406 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 145c4b1bf19fd5b4f972c105a6069005, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} diff --git a/Assets/Hangman/ScriptableObjects/HangmanImages.asset.meta b/Assets/Common/Animations/CourseMenu EnterFrom ListCourses+CourseActivity.playable.meta similarity index 79% rename from Assets/Hangman/ScriptableObjects/HangmanImages.asset.meta rename to Assets/Common/Animations/CourseMenu EnterFrom ListCourses+CourseActivity.playable.meta index 767422f..8fa831d 100644 --- a/Assets/Hangman/ScriptableObjects/HangmanImages.asset.meta +++ b/Assets/Common/Animations/CourseMenu EnterFrom ListCourses+CourseActivity.playable.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b472de3ef0c50c0449bad9ff8511056c +guid: 4675612037800af438b7fc34ec77fdf3 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/Common/Animations/CourseMenu EnterFrom MainMenu.playable b/Assets/Common/Animations/CourseMenu EnterFrom MainMenu.playable new file mode 100644 index 0000000..2954fef --- /dev/null +++ b/Assets/Common/Animations/CourseMenu EnterFrom MainMenu.playable @@ -0,0 +1,155 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-4664426466800762542 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 7070252279921862817} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: -4664426466800762542} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_back_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: CourseMenu EnterFrom MainMenu + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: -4664426466800762542} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &7070252279921862817 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 752d0f004af2172429eaf9c4baf8effe, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} diff --git a/Assets/Common/Animations/CourseMenu EnterFrom MainMenu.playable.meta b/Assets/Common/Animations/CourseMenu EnterFrom MainMenu.playable.meta new file mode 100644 index 0000000..a69f6ca --- /dev/null +++ b/Assets/Common/Animations/CourseMenu EnterFrom MainMenu.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d6b723dad69fc14499c2e4dc32aeb16c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/ListCourses EnterFrom CourseMenu.playable b/Assets/Common/Animations/ListCourses EnterFrom CourseMenu.playable new file mode 100644 index 0000000..d5a35a0 --- /dev/null +++ b/Assets/Common/Animations/ListCourses EnterFrom CourseMenu.playable @@ -0,0 +1,304 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7222763729682898453 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 3581386170263735695} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: -7222763729682898453} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_small_slide_midleft + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: ListCourses EnterFrom CourseMenu + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: -7222763729682898453} + - {fileID: 3912059771208757551} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &371366304060360721 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: b86b0f9bd6fa451488c24ba65ea3aad0, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &3010610408803047961 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3} + m_Name: Signal Emitter + m_EditorClassIdentifier: + m_Time: 0.25 + m_Retroactive: 0 + m_EmitOnce: 0 + m_Asset: {fileID: 11400000, guid: 43d3b5349c78425499a459f42eed4e88, type: 2} +--- !u!114 &3581386170263735695 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f6fd16e035ba19b4286f05948f2f4d9d, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &3912059771208757551 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 371366304060360721} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: 3912059771208757551} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_big_slide_midleft + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Common/Animations/ListCourses EnterFrom CourseMenu.playable.meta b/Assets/Common/Animations/ListCourses EnterFrom CourseMenu.playable.meta new file mode 100644 index 0000000..7f96588 --- /dev/null +++ b/Assets/Common/Animations/ListCourses EnterFrom CourseMenu.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17824baf0a53c5246bead5f5a446767d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/ListCourses ExitTo CourseMenu.playable b/Assets/Common/Animations/ListCourses ExitTo CourseMenu.playable new file mode 100644 index 0000000..c7426d9 --- /dev/null +++ b/Assets/Common/Animations/ListCourses ExitTo CourseMenu.playable @@ -0,0 +1,329 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8488586922750316490 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 8f47c24f13799904b860d0cf234d8469, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-7898205786510554628 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b46e36075dd1c124a8422c228e75e1fb, type: 3} + m_Name: Signal Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: + - {fileID: 3010610408803047961} +--- !u!114 &-7222763729682898453 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 3.469446951953614e-18 + m_ClipIn: 0 + m_Asset: {fileID: -2558360859124918117} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: -7222763729682898453} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 3.469446951953614e-18 + m_DisplayName: exit_circle_small_slide_midleft + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-2558360859124918117 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: da5b82de67e79d74a97b0cb839a98df7, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: ListCourses ExitTo CourseMenu + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: -7222763729682898453} + - {fileID: 3912059771208757551} + - {fileID: -7898205786510554628} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &3010610408803047961 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3} + m_Name: Signal Emitter + m_EditorClassIdentifier: + m_Time: 0.25 + m_Retroactive: 0 + m_EmitOnce: 0 + m_Asset: {fileID: 11400000, guid: 43d3b5349c78425499a459f42eed4e88, type: 2} +--- !u!114 &3912059771208757551 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -8488586922750316490} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: 3912059771208757551} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_big_slide_midleft + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Common/Animations/ListCourses ExitTo CourseMenu.playable.meta b/Assets/Common/Animations/ListCourses ExitTo CourseMenu.playable.meta new file mode 100644 index 0000000..86c8200 --- /dev/null +++ b/Assets/Common/Animations/ListCourses ExitTo CourseMenu.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 735f6e8af06d3724cb4bb8442e891944 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/ListMinigames EnterFrom MainMenu.playable b/Assets/Common/Animations/ListMinigames EnterFrom MainMenu.playable new file mode 100644 index 0000000..ab935c0 --- /dev/null +++ b/Assets/Common/Animations/ListMinigames EnterFrom MainMenu.playable @@ -0,0 +1,288 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7222763729682898453 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -6766252174420112766} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: -7222763729682898453} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_small_slide_midleft + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-6766252174420112766 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f6fd16e035ba19b4286f05948f2f4d9d, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-4858115428818155844 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: b86b0f9bd6fa451488c24ba65ea3aad0, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: ListMinigames EnterFrom MainMenu + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: -7222763729682898453} + - {fileID: 3912059771208757551} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &3912059771208757551 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -4858115428818155844} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: 3912059771208757551} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_big_slide_midleft + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Common/Animations/ListMinigames EnterFrom MainMenu.playable.meta b/Assets/Common/Animations/ListMinigames EnterFrom MainMenu.playable.meta new file mode 100644 index 0000000..bfb2a89 --- /dev/null +++ b/Assets/Common/Animations/ListMinigames EnterFrom MainMenu.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c9a1662ababacc549a2b60d2bddb6a11 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/ListMinigames ExitTo MainMenu.playable b/Assets/Common/Animations/ListMinigames ExitTo MainMenu.playable new file mode 100644 index 0000000..c50898b --- /dev/null +++ b/Assets/Common/Animations/ListMinigames ExitTo MainMenu.playable @@ -0,0 +1,288 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7222763729682898453 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -6766252174420112766} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: -7222763729682898453} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_small_slide_midleft + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-6766252174420112766 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f6fd16e035ba19b4286f05948f2f4d9d, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-4858115428818155844 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: b86b0f9bd6fa451488c24ba65ea3aad0, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: ListMinigames ExitTo MainMenu + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: -7222763729682898453} + - {fileID: 3912059771208757551} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &3912059771208757551 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -4858115428818155844} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: 3912059771208757551} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_big_slide_midleft + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Common/Animations/ListMinigames ExitTo MainMenu.playable.meta b/Assets/Common/Animations/ListMinigames ExitTo MainMenu.playable.meta new file mode 100644 index 0000000..3079502 --- /dev/null +++ b/Assets/Common/Animations/ListMinigames ExitTo MainMenu.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e807bc2046af3034b94c2e8c86ca9432 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/MainMenu EnterFrom CourseMenu+Settings.playable b/Assets/Common/Animations/MainMenu EnterFrom CourseMenu+Settings.playable new file mode 100644 index 0000000..ea730e0 --- /dev/null +++ b/Assets/Common/Animations/MainMenu EnterFrom CourseMenu+Settings.playable @@ -0,0 +1,1580 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8582760416834872199 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 758275327411311502} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.5 + m_ClipIn: 0 + m_Asset: {fileID: 7057593053156110156} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -8582760416834872199} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.5 + m_DisplayName: enter_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-8275657409746777211 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f38641deec023914a8d830f42330654e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-6461985129190707182 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333334 + m_ClipIn: 0 + m_Asset: {fileID: -3031510136711171083} + m_Duration: 0.41666666666666663 + m_TimeScale: 1 + m_ParentTrack: {fileID: -6461985129190707182} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333334 + m_DisplayName: enter_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-5458175745502731281 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 1aff287d00868b74b828ed876fa8231f, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-4269651558545598804 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a16748d9461eae46a725db9776d5390, type: 3} + m_Name: Markers + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &-3460374503973533952 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 758275327411311502} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333331 + m_ClipIn: 0 + m_Asset: {fileID: 3621677159347486517} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: -3460374503973533952} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333331 + m_DisplayName: enter_quit_slide + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-3453646169293782431 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 460ce3dd5a966464d9d44fbbc21865ba, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-3031510136711171083 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 145c4b1bf19fd5b4f972c105a6069005, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-2701421434816263238 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333333 + m_ClipIn: 0 + m_Asset: {fileID: -3453646169293782431} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -2701421434816263238} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333333 + m_DisplayName: enter_circle_slide_left + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-2531812989389365972 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: c55cca00f69821f4abce1c51b3a5e819, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-644108254300868384 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333333 + m_ClipIn: 0 + m_Asset: {fileID: -5458175745502731281} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -644108254300868384} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333333 + m_DisplayName: enter_circle_slide_right + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: MainMenu EnterFrom CourseMenu+Settings + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: 2004666627601121409} + - {fileID: 758275327411311502} + - {fileID: 3948122334867949208} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: -4269651558545598804} +--- !u!114 &516649734906522701 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: e304c92e8f6fa224cb38de6f7e75d943, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &758275327411311502 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Buttons + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 4350005768353392531} + - {fileID: 7595589887998305822} + - {fileID: -8582760416834872199} + - {fileID: -3460374503973533952} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &994782306206548664 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (4) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333334 + m_ClipIn: 0 + m_Asset: {fileID: -8275657409746777211} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 994782306206548664} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333334 + m_DisplayName: exit_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &2004666627601121409 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Title + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 7960070878223035243} + - {fileID: 8745738078766204527} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &2921595501635262924 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: e304c92e8f6fa224cb38de6f7e75d943, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &3621677159347486517 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 1e2b932f783a4e140ab54dbc89975636, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &3948122334867949208 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Circles + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 4179371391357151474} + - {fileID: -6461985129190707182} + - {fileID: -2701421434816263238} + - {fileID: -644108254300868384} + - {fileID: 994782306206548664} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &4179371391357151474 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333333 + m_ClipIn: 0 + m_Asset: {fileID: 4692543505633170018} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 4179371391357151474} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333333 + m_DisplayName: enter_circle_shrink + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &4350005768353392531 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 758275327411311502} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.3333333333333333 + m_ClipIn: 0 + m_Asset: {fileID: 2921595501635262924} + m_Duration: 0.41666666666666674 + m_TimeScale: 1 + m_ParentTrack: {fileID: 4350005768353392531} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.3333333333333333 + m_DisplayName: enter_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &4692543505633170018 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: ba7536156a6aa6647a7063b33638b17c, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &7057593053156110156 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: e304c92e8f6fa224cb38de6f7e75d943, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &7595589887998305822 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 758275327411311502} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.4166666666666667 + m_ClipIn: 0 + m_Asset: {fileID: 516649734906522701} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 7595589887998305822} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.4166666666666667 + m_DisplayName: enter_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &7960070878223035243 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 2004666627601121409} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 8336679900562273499} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 7960070878223035243} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &8336679900562273499 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: c55cca00f69821f4abce1c51b3a5e819, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &8745738078766204527 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 2004666627601121409} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -2531812989389365972} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 8745738078766204527} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Common/Animations/MainMenu EnterFrom CourseMenu+Settings.playable.meta b/Assets/Common/Animations/MainMenu EnterFrom CourseMenu+Settings.playable.meta new file mode 100644 index 0000000..fa5b9ee --- /dev/null +++ b/Assets/Common/Animations/MainMenu EnterFrom CourseMenu+Settings.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e9c4a356b1ade0d4aae5b9c332f7113b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/MainMenu EnterFrom Default.playable b/Assets/Common/Animations/MainMenu EnterFrom Default.playable new file mode 100644 index 0000000..9a3f18c --- /dev/null +++ b/Assets/Common/Animations/MainMenu EnterFrom Default.playable @@ -0,0 +1,1447 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8582760416834872199 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 758275327411311502} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.5 + m_ClipIn: 0 + m_Asset: {fileID: 7057593053156110156} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -8582760416834872199} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.5 + m_DisplayName: enter_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-6461985129190707182 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.16666666666666666 + m_ClipIn: 0 + m_Asset: {fileID: -3031510136711171083} + m_Duration: 0.41666666666666663 + m_TimeScale: 1 + m_ParentTrack: {fileID: -6461985129190707182} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.16666666666666666 + m_DisplayName: enter_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-5458175745502731281 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 1aff287d00868b74b828ed876fa8231f, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-4269651558545598804 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a16748d9461eae46a725db9776d5390, type: 3} + m_Name: Markers + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &-3453646169293782431 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 460ce3dd5a966464d9d44fbbc21865ba, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-3031510136711171083 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 145c4b1bf19fd5b4f972c105a6069005, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-2701421434816263238 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333333 + m_ClipIn: 0 + m_Asset: {fileID: -3453646169293782431} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -2701421434816263238} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333333 + m_DisplayName: enter_circle_slide_left + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-2531812989389365972 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: c55cca00f69821f4abce1c51b3a5e819, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-644108254300868384 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333333 + m_ClipIn: 0 + m_Asset: {fileID: -5458175745502731281} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -644108254300868384} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333333 + m_DisplayName: enter_circle_slide_right + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: MainMenu EnterFrom Default + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: 2004666627601121409} + - {fileID: 758275327411311502} + - {fileID: 3948122334867949208} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: -4269651558545598804} +--- !u!114 &516649734906522701 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: e304c92e8f6fa224cb38de6f7e75d943, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &581980765139174905 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 145c4b1bf19fd5b4f972c105a6069005, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &685363172391209897 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 1e2b932f783a4e140ab54dbc89975636, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &758275327411311502 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Buttons + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 4350005768353392531} + - {fileID: 7595589887998305822} + - {fileID: -8582760416834872199} + - {fileID: 6319176095920718519} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &2004666627601121409 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Title + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 7960070878223035243} + - {fileID: 8745738078766204527} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &2921595501635262924 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: e304c92e8f6fa224cb38de6f7e75d943, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &3948122334867949208 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Circles + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 4179371391357151474} + - {fileID: -6461985129190707182} + - {fileID: -2701421434816263238} + - {fileID: -644108254300868384} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &4179371391357151474 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 3948122334867949208} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.16666666666666666 + m_ClipIn: 0 + m_Asset: {fileID: 581980765139174905} + m_Duration: 0.41666666666666663 + m_TimeScale: 1 + m_ParentTrack: {fileID: 4179371391357151474} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.16666666666666666 + m_DisplayName: enter_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &4350005768353392531 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 758275327411311502} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.3333333333333333 + m_ClipIn: 0 + m_Asset: {fileID: 2921595501635262924} + m_Duration: 0.41666666666666674 + m_TimeScale: 1 + m_ParentTrack: {fileID: 4350005768353392531} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.3333333333333333 + m_DisplayName: enter_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &6319176095920718519 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 758275327411311502} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.08333333333333331 + m_ClipIn: 0 + m_Asset: {fileID: 685363172391209897} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: 6319176095920718519} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.08333333333333331 + m_DisplayName: enter_quit_slide + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &7057593053156110156 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: e304c92e8f6fa224cb38de6f7e75d943, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &7595589887998305822 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 758275327411311502} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0.4166666666666667 + m_ClipIn: 0 + m_Asset: {fileID: 516649734906522701} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 7595589887998305822} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0.4166666666666667 + m_DisplayName: enter_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &7960070878223035243 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 2004666627601121409} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 8336679900562273499} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 7960070878223035243} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &8336679900562273499 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: c55cca00f69821f4abce1c51b3a5e819, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &8745738078766204527 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 2004666627601121409} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -2531812989389365972} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 8745738078766204527} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Common/Animations/MainMenu EnterFrom Default.playable.meta b/Assets/Common/Animations/MainMenu EnterFrom Default.playable.meta new file mode 100644 index 0000000..ca2f096 --- /dev/null +++ b/Assets/Common/Animations/MainMenu EnterFrom Default.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 307ae7d8f4dcb8842a064af301714167 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/MainMenu ExitTo CourseMenu.playable b/Assets/Common/Animations/MainMenu ExitTo CourseMenu.playable new file mode 100644 index 0000000..0b8210e --- /dev/null +++ b/Assets/Common/Animations/MainMenu ExitTo CourseMenu.playable @@ -0,0 +1,1602 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8862609512150535950 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-7760151931934511102 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f38641deec023914a8d830f42330654e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-6598509297292300633 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Circles + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 1173479326806649973} + - {fileID: -3010792027217435242} + - {fileID: 8085811114252437081} + - {fileID: -6441785808545757162} + - {fileID: 5908694173847546634} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &-6441785808545757162 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (4) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -2331444508186733344} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -6441785808545757162} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_right + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-5899776333742599432 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 6151877941169156898} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -8862609512150535950} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -5899776333742599432} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-4966541568938090082 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: e1d5b7169d0d9e641b700ebc284f91d1, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-4530961276936474047 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-3238743624970913315 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Title + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 8324031387123106780} + - {fileID: 2139126816910514718} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &-3010792027217435242 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 3638874520196114021} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -3010792027217435242} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-2331444508186733344 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 523cb861bd5de1241b11afe1a6608e4e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-1313024316759358721 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3} + m_Name: Signal Emitter + m_EditorClassIdentifier: + m_Time: 0.4166666666666667 + m_Retroactive: 0 + m_EmitOnce: 1 + m_Asset: {fileID: 11400000, guid: e7f8a994d20fc3f4e86b8c89d0985feb, type: 2} +--- !u!114 &-779619219735296283 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: MainMenu ExitTo CourseMenu + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: -3238743624970913315} + - {fileID: 6151877941169156898} + - {fileID: -6598509297292300633} + - {fileID: 4509904291432811175} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &1173479326806649973 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -4966541568938090082} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 1173479326806649973} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_enlarge + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &1342019140867913866 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f69f707ae0df7e8429b39a10ede7512e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &2139126816910514718 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -3238743624970913315} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 5171623520093996275} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 2139126816910514718} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &2390825487676823868 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 42d8ffc35eb3bad439959a10d02816f1, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &2790252717313872206 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 6151877941169156898} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -779619219735296283} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 2790252717313872206} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &3557235052885036117 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 6151877941169156898} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -4530961276936474047} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 3557235052885036117} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &3638874520196114021 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f38641deec023914a8d830f42330654e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &4509904291432811175 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b46e36075dd1c124a8422c228e75e1fb, type: 3} + m_Name: Signal Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: + - {fileID: -1313024316759358721} +--- !u!114 &4790687436092278219 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 6151877941169156898} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 7552421223771827254} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: 4790687436092278219} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_quit_slide + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &5171623520093996275 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 42d8ffc35eb3bad439959a10d02816f1, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &5908694173847546634 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 7873309596201692183} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 5908694173847546634} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &6151877941169156898 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Buttons + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 3557235052885036117} + - {fileID: 2790252717313872206} + - {fileID: -5899776333742599432} + - {fileID: 4790687436092278219} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &7552421223771827254 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: cce2173a5fe35db47b4de921ae61c948, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &7873309596201692183 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 145c4b1bf19fd5b4f972c105a6069005, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &8085811114252437081 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 1342019140867913866} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 8085811114252437081} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_left + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &8324031387123106780 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -3238743624970913315} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 2390825487676823868} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 8324031387123106780} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Common/Animations/MainMenu ExitTo CourseMenu.playable.meta b/Assets/Common/Animations/MainMenu ExitTo CourseMenu.playable.meta new file mode 100644 index 0000000..b9cd7fc --- /dev/null +++ b/Assets/Common/Animations/MainMenu ExitTo CourseMenu.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9406fe9f4b6ff024a8b0251f02a9f1eb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/MainMenu ExitTo ListMinigames.playable b/Assets/Common/Animations/MainMenu ExitTo ListMinigames.playable new file mode 100644 index 0000000..a910f3c --- /dev/null +++ b/Assets/Common/Animations/MainMenu ExitTo ListMinigames.playable @@ -0,0 +1,1469 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8862609512150535950 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-7760151931934511102 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f38641deec023914a8d830f42330654e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-6598509297292300633 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Circles + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 1173479326806649973} + - {fileID: -3010792027217435242} + - {fileID: 8085811114252437081} + - {fileID: -6441785808545757162} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &-6441785808545757162 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (4) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -2331444508186733344} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -6441785808545757162} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_right + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-5899776333742599432 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 6151877941169156898} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -8862609512150535950} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -5899776333742599432} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-4530961276936474047 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-3238743624970913315 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Title + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 8324031387123106780} + - {fileID: 2139126816910514718} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &-3010792027217435242 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 3638874520196114021} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -3010792027217435242} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-2331444508186733344 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 523cb861bd5de1241b11afe1a6608e4e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-1313024316759358721 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3} + m_Name: Signal Emitter + m_EditorClassIdentifier: + m_Time: 0.4166666666666667 + m_Retroactive: 0 + m_EmitOnce: 1 + m_Asset: {fileID: 11400000, guid: 08675e63d7cce004b8d676459e6bd800, type: 2} +--- !u!114 &-779619219735296283 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: MainMenu ExitTo ListMinigames + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: -3238743624970913315} + - {fileID: 6151877941169156898} + - {fileID: -6598509297292300633} + - {fileID: 4509904291432811175} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &1173479326806649973 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 4728047619280726942} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 1173479326806649973} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &1342019140867913866 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f69f707ae0df7e8429b39a10ede7512e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &2139126816910514718 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -3238743624970913315} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 5171623520093996275} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 2139126816910514718} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &2390825487676823868 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 42d8ffc35eb3bad439959a10d02816f1, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &2790252717313872206 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 6151877941169156898} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -779619219735296283} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 2790252717313872206} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &3557235052885036117 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 6151877941169156898} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -4530961276936474047} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 3557235052885036117} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &3638874520196114021 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f38641deec023914a8d830f42330654e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &4509904291432811175 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b46e36075dd1c124a8422c228e75e1fb, type: 3} + m_Name: Signal Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: + - {fileID: -1313024316759358721} +--- !u!114 &4728047619280726942 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f38641deec023914a8d830f42330654e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &4790687436092278219 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 6151877941169156898} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 7552421223771827254} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: 4790687436092278219} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_quit_slide + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &5171623520093996275 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 42d8ffc35eb3bad439959a10d02816f1, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &6151877941169156898 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Buttons + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 3557235052885036117} + - {fileID: 2790252717313872206} + - {fileID: -5899776333742599432} + - {fileID: 4790687436092278219} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &7552421223771827254 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: cce2173a5fe35db47b4de921ae61c948, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &8085811114252437081 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -6598509297292300633} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 1342019140867913866} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 8085811114252437081} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_left + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &8324031387123106780 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -3238743624970913315} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 2390825487676823868} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 8324031387123106780} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Common/Animations/MainMenu ExitTo ListMinigames.playable.meta b/Assets/Common/Animations/MainMenu ExitTo ListMinigames.playable.meta new file mode 100644 index 0000000..ca0d4dc --- /dev/null +++ b/Assets/Common/Animations/MainMenu ExitTo ListMinigames.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c38fe7d5e65deb849ad603272b6cb219 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/MainMenu ExitTo Settings.playable b/Assets/Common/Animations/MainMenu ExitTo Settings.playable new file mode 100644 index 0000000..efc3523 --- /dev/null +++ b/Assets/Common/Animations/MainMenu ExitTo Settings.playable @@ -0,0 +1,1619 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-9055057456132405614 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 8345666252909093779} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 8235343148414851039} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -9055057456132405614} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-8871505846720781378 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone)(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-7474895082664999102 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f38641deec023914a8d830f42330654e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-7219411497493404509 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone)(Clone)(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: f69f707ae0df7e8429b39a10ede7512e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-6616596139522403256 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 5451587060519161791} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -3813913044951076850} + m_Duration: 0.25 + m_TimeScale: 1 + m_ParentTrack: {fileID: -6616596139522403256} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_quit_slide + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-6171563559054577944 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b46e36075dd1c124a8422c228e75e1fb, type: 3} + m_Name: Signal Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: + - {fileID: -2184383157542714934} +--- !u!114 &-5490095168883862555 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone)(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-4940363129666359713 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -528450089512025176} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 3324479411857042164} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: -4940363129666359713} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &-4269651558545598804 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a16748d9461eae46a725db9776d5390, type: 3} + m_Name: Markers + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &-3813913044951076850 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: cce2173a5fe35db47b4de921ae61c948, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &-2184383157542714934 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3} + m_Name: Signal Emitter(Clone)(Clone) + m_EditorClassIdentifier: + m_Time: 0.4166666666666667 + m_Retroactive: 0 + m_EmitOnce: 1 + m_Asset: {fileID: 11400000, guid: 93a1de2533e3bef448eeffa926ed86ac, type: 2} +--- !u!114 &-528450089512025176 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Circles + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 2514152892369494006} + - {fileID: 6079267839920973567} + - {fileID: 8267312918698752938} + - {fileID: 1394315781135015027} + - {fileID: -4940363129666359713} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &-8682895713290530 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone)(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: e1d5b7169d0d9e641b700ebc284f91d1, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: MainMenu ExitTo Settings + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: 8345666252909093779} + - {fileID: 5451587060519161791} + - {fileID: -528450089512025176} + - {fileID: -6171563559054577944} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: -4269651558545598804} +--- !u!114 &387928185338924814 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 3301a7147afd1244687764c9d82cdb07, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &709750372542851707 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 5451587060519161791} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -8871505846720781378} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 709750372542851707} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &883746247832735280 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 5451587060519161791} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 387928185338924814} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 883746247832735280} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &909078281928674083 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 5451587060519161791} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -5490095168883862555} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 909078281928674083} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_fade + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &1096787736882190270 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 8345666252909093779} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 1966798510071742935} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 1096787736882190270} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_title + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &1394315781135015027 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (4) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -528450089512025176} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: 8745028102597491502} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 1394315781135015027} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_right + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &1966798510071742935 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone)(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 42d8ffc35eb3bad439959a10d02816f1, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &2514152892369494006 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -528450089512025176} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -8682895713290530} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 2514152892369494006} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: enter_circle_enlarge + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &2695895246092268661 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3} + m_Name: Signal Emitter(Clone)(Clone) + m_EditorClassIdentifier: + m_Time: 0.4166666666666667 + m_Retroactive: 0 + m_EmitOnce: 1 + m_Asset: {fileID: 11400000, guid: e7f8a994d20fc3f4e86b8c89d0985feb, type: 2} +--- !u!114 &3324479411857042164 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone)(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 145c4b1bf19fd5b4f972c105a6069005, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &5451587060519161791 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Buttons + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: 883746247832735280} + - {fileID: 709750372542851707} + - {fileID: 909078281928674083} + - {fileID: -6616596139522403256} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &6079267839920973567 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -528450089512025176} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -7474895082664999102} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 6079267839920973567} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_down + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &8235343148414851039 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 42d8ffc35eb3bad439959a10d02816f1, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &8267312918698752938 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (3) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: -528450089512025176} + m_Children: [] + m_Clips: + - m_Version: 1 + m_Start: 0 + m_ClipIn: 0 + m_Asset: {fileID: -7219411497493404509} + m_Duration: 0.4166666666666667 + m_TimeScale: 1 + m_ParentTrack: {fileID: 8267312918698752938} + m_EaseInDuration: 0 + m_EaseOutDuration: 0 + m_BlendInDuration: -1 + m_BlendOutDuration: -1 + m_MixInCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_MixOutCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BlendInCurveMode: 0 + m_BlendOutCurveMode: 0 + m_ExposedParameterNames: [] + m_AnimationCurves: {fileID: 0} + m_Recordable: 0 + m_PostExtrapolationMode: 1 + m_PreExtrapolationMode: 1 + m_PostExtrapolationTime: Infinity + m_PreExtrapolationTime: 0 + m_DisplayName: exit_circle_slide_left + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 0 + m_InfiniteClipPostExtrapolation: 0 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 0} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!114 &8345666252909093779 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0fc6f5187a81dc47999eefade6f0935, type: 3} + m_Name: Title + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: + - {fileID: -9055057456132405614} + - {fileID: 1096787736882190270} + m_Clips: [] + m_Markers: + m_Objects: [] +--- !u!114 &8745028102597491502 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 030f85c3f73729f4f976f66ffb23b875, type: 3} + m_Name: AnimationPlayableAsset(Clone)(Clone) + m_EditorClassIdentifier: + m_Clip: {fileID: 7400000, guid: 523cb861bd5de1241b11afe1a6608e4e, type: 2} + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_UseTrackMatchFields: 1 + m_MatchTargetFields: 63 + m_RemoveStartOffset: 1 + m_ApplyFootIK: 1 + m_Loop: 0 + m_Version: 1 + m_Rotation: {x: 0, y: 0, z: 0, w: 1} diff --git a/Assets/Common/Animations/MainMenu ExitTo Settings.playable.meta b/Assets/Common/Animations/MainMenu ExitTo Settings.playable.meta new file mode 100644 index 0000000..93cf488 --- /dev/null +++ b/Assets/Common/Animations/MainMenu ExitTo Settings.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 70e33fe36bd6a1246b94c1356fa31623 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Quit.controller b/Assets/Common/Animations/Quit.controller new file mode 100644 index 0000000..eefbdea --- /dev/null +++ b/Assets/Common/Animations/Quit.controller @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Quit + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 4460077487221645680} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &4460077487221645680 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 0} diff --git a/Assets/Common/Animations/Quit.controller.meta b/Assets/Common/Animations/Quit.controller.meta new file mode 100644 index 0000000..f9af716 --- /dev/null +++ b/Assets/Common/Animations/Quit.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab0e4afacdd6ce34fb9a66804f0d4238 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Recent.controller b/Assets/Common/Animations/Recent.controller new file mode 100644 index 0000000..ba95639 --- /dev/null +++ b/Assets/Common/Animations/Recent.controller @@ -0,0 +1,72 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Recent + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 8757123139603803923} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1102 &8407739424026292010 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_color_fade + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: [] + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 8bfde7c49b608ab4c88377a71ca2a3c7, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1107 &8757123139603803923 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 8407739424026292010} + m_Position: {x: 200, y: 0, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 8407739424026292010} diff --git a/Assets/Common/Animations/Recent.controller.meta b/Assets/Common/Animations/Recent.controller.meta new file mode 100644 index 0000000..539d20e --- /dev/null +++ b/Assets/Common/Animations/Recent.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef147e3ac03990149bd4a8660eeec218 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Models.meta b/Assets/Common/Animations/Signals.meta similarity index 77% rename from Assets/Resources/Models.meta rename to Assets/Common/Animations/Signals.meta index 7f94823..0e664c8 100644 --- a/Assets/Resources/Models.meta +++ b/Assets/Common/Animations/Signals.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7992d1284c7de4b089f4155b3e4ada83 +guid: 718845c9c5a00c54080a32eac82364eb folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Accounts/ScriptableObjects/UserList.asset b/Assets/Common/Animations/Signals/goto_courses.signal similarity index 61% rename from Assets/Accounts/ScriptableObjects/UserList.asset rename to Assets/Common/Animations/Signals/goto_courses.signal index 257d266..49fe042 100644 --- a/Assets/Accounts/ScriptableObjects/UserList.asset +++ b/Assets/Common/Animations/Signals/goto_courses.signal @@ -7,11 +7,8 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} - m_Enabled: 0 + m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3f3d6d68c3c3db64e91cf5ec9537ccda, type: 3} - m_Name: UserList + m_Script: {fileID: 11500000, guid: d6fa2d92fc1b3f34da284357edf89c3b, type: 3} + m_Name: goto_courses m_EditorClassIdentifier: - storedUserList: - currentUserIndex: 0 - storedUsers: [] diff --git a/Assets/Common/Animations/Signals/goto_courses.signal.meta b/Assets/Common/Animations/Signals/goto_courses.signal.meta new file mode 100644 index 0000000..fc814d2 --- /dev/null +++ b/Assets/Common/Animations/Signals/goto_courses.signal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e7f8a994d20fc3f4e86b8c89d0985feb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Signals/goto_minigames.signal b/Assets/Common/Animations/Signals/goto_minigames.signal new file mode 100644 index 0000000..3950e81 --- /dev/null +++ b/Assets/Common/Animations/Signals/goto_minigames.signal @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d6fa2d92fc1b3f34da284357edf89c3b, type: 3} + m_Name: goto_minigames + m_EditorClassIdentifier: diff --git a/Assets/Common/Animations/Signals/goto_minigames.signal.meta b/Assets/Common/Animations/Signals/goto_minigames.signal.meta new file mode 100644 index 0000000..74e80c0 --- /dev/null +++ b/Assets/Common/Animations/Signals/goto_minigames.signal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 08675e63d7cce004b8d676459e6bd800 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Signals/goto_previous_scene.signal b/Assets/Common/Animations/Signals/goto_previous_scene.signal new file mode 100644 index 0000000..be4f5f3 --- /dev/null +++ b/Assets/Common/Animations/Signals/goto_previous_scene.signal @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d6fa2d92fc1b3f34da284357edf89c3b, type: 3} + m_Name: goto_previous_scene + m_EditorClassIdentifier: diff --git a/Assets/Common/Animations/Signals/goto_previous_scene.signal.meta b/Assets/Common/Animations/Signals/goto_previous_scene.signal.meta new file mode 100644 index 0000000..4f6d7a1 --- /dev/null +++ b/Assets/Common/Animations/Signals/goto_previous_scene.signal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 43d3b5349c78425499a459f42eed4e88 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Signals/goto_settings.signal b/Assets/Common/Animations/Signals/goto_settings.signal new file mode 100644 index 0000000..5c3b8f1 --- /dev/null +++ b/Assets/Common/Animations/Signals/goto_settings.signal @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d6fa2d92fc1b3f34da284357edf89c3b, type: 3} + m_Name: goto_settings + m_EditorClassIdentifier: diff --git a/Assets/Common/Animations/Signals/goto_settings.signal.meta b/Assets/Common/Animations/Signals/goto_settings.signal.meta new file mode 100644 index 0000000..92ed552 --- /dev/null +++ b/Assets/Common/Animations/Signals/goto_settings.signal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 93a1de2533e3bef448eeffa926ed86ac +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/Title.controller b/Assets/Common/Animations/Title.controller new file mode 100644 index 0000000..3df5f16 --- /dev/null +++ b/Assets/Common/Animations/Title.controller @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Title + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 5049321027851525001} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &5049321027851525001 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 0} diff --git a/Assets/Common/Animations/Title.controller.meta b/Assets/Common/Animations/Title.controller.meta new file mode 100644 index 0000000..c608116 --- /dev/null +++ b/Assets/Common/Animations/Title.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6b7d9f6f570023640b182154818df183 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_back_slide.anim b/Assets/Common/Animations/enter_back_slide.anim new file mode 100644 index 0000000..651abd2 --- /dev/null +++ b/Assets/Common/Animations/enter_back_slide.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_back_slide + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 50 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: -10 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.25 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 50 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: -10 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_back_slide.anim.meta b/Assets/Common/Animations/enter_back_slide.anim.meta new file mode 100644 index 0000000..6fa8fb3 --- /dev/null +++ b/Assets/Common/Animations/enter_back_slide.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 752d0f004af2172429eaf9c4baf8effe +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_button_fade.anim b/Assets/Common/Animations/enter_button_fade.anim new file mode 100644 index 0000000..bead528 --- /dev/null +++ b/Assets/Common/Animations/enter_button_fade.anim @@ -0,0 +1,242 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_button_fade + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Button Image + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_fontColor.a + path: Button Text + classID: 114 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Button Icon + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 1831205461 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 1152055402 + attribute: 4185109675 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 448099958 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Button Image + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_fontColor.a + path: Button Text + classID: 114 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Button Icon + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_button_fade.anim.meta b/Assets/Common/Animations/enter_button_fade.anim.meta new file mode 100644 index 0000000..4b704d6 --- /dev/null +++ b/Assets/Common/Animations/enter_button_fade.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e304c92e8f6fa224cb38de6f7e75d943 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_circle_big_slide_midleft.anim b/Assets/Common/Animations/enter_circle_big_slide_midleft.anim new file mode 100644 index 0000000..9cb5128 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_big_slide_midleft.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_circle_big_slide_midleft + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 270 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.25 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 270 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_circle_big_slide_midleft.anim.meta b/Assets/Common/Animations/enter_circle_big_slide_midleft.anim.meta new file mode 100644 index 0000000..c704057 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_big_slide_midleft.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b86b0f9bd6fa451488c24ba65ea3aad0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_circle_enlarge.anim b/Assets/Common/Animations/enter_circle_enlarge.anim new file mode 100644 index 0000000..964c2ba --- /dev/null +++ b/Assets/Common/Animations/enter_circle_enlarge.anim @@ -0,0 +1,305 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_circle_enlarge + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 260 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -160 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -250 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_SizeDelta.x + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_SizeDelta.y + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 1967290853 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 38095219 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 260 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -160 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -250 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_SizeDelta.x + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_SizeDelta.y + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_circle_enlarge.anim.meta b/Assets/Common/Animations/enter_circle_enlarge.anim.meta new file mode 100644 index 0000000..cb3ca9b --- /dev/null +++ b/Assets/Common/Animations/enter_circle_enlarge.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e1d5b7169d0d9e641b700ebc284f91d1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_circle_shrink.anim b/Assets/Common/Animations/enter_circle_shrink.anim new file mode 100644 index 0000000..74a3e92 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_shrink.anim @@ -0,0 +1,305 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_circle_shrink + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -160 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 260 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -250 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_SizeDelta.x + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_SizeDelta.y + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 1967290853 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 38095219 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -160 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 260 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -250 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_SizeDelta.x + path: + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_SizeDelta.y + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_circle_shrink.anim.meta b/Assets/Common/Animations/enter_circle_shrink.anim.meta new file mode 100644 index 0000000..6338cd7 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_shrink.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba7536156a6aa6647a7063b33638b17c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_circle_slide_left.anim b/Assets/Common/Animations/enter_circle_slide_left.anim new file mode 100644 index 0000000..b056728 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_slide_left.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_circle_slide_left + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -160 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -160 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_circle_slide_left.anim.meta b/Assets/Common/Animations/enter_circle_slide_left.anim.meta new file mode 100644 index 0000000..d9d77b7 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_slide_left.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 460ce3dd5a966464d9d44fbbc21865ba +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_circle_slide_right.anim b/Assets/Common/Animations/enter_circle_slide_right.anim new file mode 100644 index 0000000..2174a63 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_slide_right.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_circle_slide_right + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -375 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -375 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_circle_slide_right.anim.meta b/Assets/Common/Animations/enter_circle_slide_right.anim.meta new file mode 100644 index 0000000..c735890 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_slide_right.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1aff287d00868b74b828ed876fa8231f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_circle_slide_up.anim b/Assets/Common/Animations/enter_circle_slide_up.anim new file mode 100644 index 0000000..e2576e1 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_slide_up.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_circle_slide_up + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_circle_slide_up.anim.meta b/Assets/Common/Animations/enter_circle_slide_up.anim.meta new file mode 100644 index 0000000..dbf9370 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_slide_up.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 145c4b1bf19fd5b4f972c105a6069005 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_circle_small_slide_midleft.anim b/Assets/Common/Animations/enter_circle_small_slide_midleft.anim new file mode 100644 index 0000000..4cc1e15 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_small_slide_midleft.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_circle_small_slide_midleft + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 360 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 230 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.25 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 360 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 230 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_circle_small_slide_midleft.anim.meta b/Assets/Common/Animations/enter_circle_small_slide_midleft.anim.meta new file mode 100644 index 0000000..7892d33 --- /dev/null +++ b/Assets/Common/Animations/enter_circle_small_slide_midleft.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f6fd16e035ba19b4286f05948f2f4d9d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_course_item.anim b/Assets/Common/Animations/enter_course_item.anim new file mode 100644 index 0000000..2215df4 --- /dev/null +++ b/Assets/Common/Animations/enter_course_item.anim @@ -0,0 +1,368 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_course_item + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_fontColor.a + path: Title/Text (TMP) + classID: 114 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Thumbnail + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Progress/Slider/Background + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Progress/Slider/Fill Area/Fill + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 4112522401 + attribute: 4185109675 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 1101440069 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2341232062 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 204176860 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_fontColor.a + path: Title/Text (TMP) + classID: 114 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Thumbnail + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Progress/Slider/Background + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Progress/Slider/Fill Area/Fill + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_course_item.anim.meta b/Assets/Common/Animations/enter_course_item.anim.meta new file mode 100644 index 0000000..c141328 --- /dev/null +++ b/Assets/Common/Animations/enter_course_item.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 20b914049e2da0641a3179082f6e0834 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_quit_slide.anim b/Assets/Common/Animations/enter_quit_slide.anim new file mode 100644 index 0000000..b440cee --- /dev/null +++ b/Assets/Common/Animations/enter_quit_slide.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_quit_slide + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -50 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 10 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.25 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -50 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 10 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_quit_slide.anim.meta b/Assets/Common/Animations/enter_quit_slide.anim.meta new file mode 100644 index 0000000..bff7455 --- /dev/null +++ b/Assets/Common/Animations/enter_quit_slide.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e2b932f783a4e140ab54dbc89975636 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_text_fade.anim b/Assets/Common/Animations/enter_text_fade.anim new file mode 100644 index 0000000..ba11d67 --- /dev/null +++ b/Assets/Common/Animations/enter_text_fade.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_text_fade + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_fontColor.a + path: + classID: 114 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 4185109675 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_fontColor.a + path: + classID: 114 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_text_fade.anim.meta b/Assets/Common/Animations/enter_text_fade.anim.meta new file mode 100644 index 0000000..96ef80c --- /dev/null +++ b/Assets/Common/Animations/enter_text_fade.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8bfde7c49b608ab4c88377a71ca2a3c7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/enter_title.anim b/Assets/Common/Animations/enter_title.anim new file mode 100644 index 0000000..198fe8d --- /dev/null +++ b/Assets/Common/Animations/enter_title.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: enter_title + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -115 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -115 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/enter_title.anim.meta b/Assets/Common/Animations/enter_title.anim.meta new file mode 100644 index 0000000..5dcfcec --- /dev/null +++ b/Assets/Common/Animations/enter_title.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c55cca00f69821f4abce1c51b3a5e819 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_back_slide.anim b/Assets/Common/Animations/exit_back_slide.anim new file mode 100644 index 0000000..b8d5d26 --- /dev/null +++ b/Assets/Common/Animations/exit_back_slide.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_back_slide + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -10 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 50 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.25 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -10 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 50 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_back_slide.anim.meta b/Assets/Common/Animations/exit_back_slide.anim.meta new file mode 100644 index 0000000..5dbd9cd --- /dev/null +++ b/Assets/Common/Animations/exit_back_slide.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf71c1ac00fc2c8459e0403b4b7c91a9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_button_fade.anim b/Assets/Common/Animations/exit_button_fade.anim new file mode 100644 index 0000000..0dd7865 --- /dev/null +++ b/Assets/Common/Animations/exit_button_fade.anim @@ -0,0 +1,242 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_button_fade + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Button Icon + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Button Image + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_fontColor.a + path: Button Text + classID: 114 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 448099958 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 1831205461 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 1152055402 + attribute: 4185109675 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Button Icon + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Button Image + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_fontColor.a + path: Button Text + classID: 114 + script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_button_fade.anim.meta b/Assets/Common/Animations/exit_button_fade.anim.meta new file mode 100644 index 0000000..7ff46ed --- /dev/null +++ b/Assets/Common/Animations/exit_button_fade.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3301a7147afd1244687764c9d82cdb07 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_circle_big_slide_midleft.anim b/Assets/Common/Animations/exit_circle_big_slide_midleft.anim new file mode 100644 index 0000000..54268d1 --- /dev/null +++ b/Assets/Common/Animations/exit_circle_big_slide_midleft.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_circle_big_slide_midleft + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 270 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.25 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 270 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_circle_big_slide_midleft.anim.meta b/Assets/Common/Animations/exit_circle_big_slide_midleft.anim.meta new file mode 100644 index 0000000..49a0bba --- /dev/null +++ b/Assets/Common/Animations/exit_circle_big_slide_midleft.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f47c24f13799904b860d0cf234d8469 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_circle_slide_down.anim b/Assets/Common/Animations/exit_circle_slide_down.anim new file mode 100644 index 0000000..556d15b --- /dev/null +++ b/Assets/Common/Animations/exit_circle_slide_down.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_circle_slide_down + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -470 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_circle_slide_down.anim.meta b/Assets/Common/Animations/exit_circle_slide_down.anim.meta new file mode 100644 index 0000000..f6d3232 --- /dev/null +++ b/Assets/Common/Animations/exit_circle_slide_down.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f38641deec023914a8d830f42330654e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_circle_slide_left.anim b/Assets/Common/Animations/exit_circle_slide_left.anim new file mode 100644 index 0000000..f2223d2 --- /dev/null +++ b/Assets/Common/Animations/exit_circle_slide_left.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_circle_slide_left + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -160 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -160 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -535 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_circle_slide_left.anim.meta b/Assets/Common/Animations/exit_circle_slide_left.anim.meta new file mode 100644 index 0000000..900aadf --- /dev/null +++ b/Assets/Common/Animations/exit_circle_slide_left.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f69f707ae0df7e8429b39a10ede7512e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_circle_slide_right.anim b/Assets/Common/Animations/exit_circle_slide_right.anim new file mode 100644 index 0000000..f31a9c7 --- /dev/null +++ b/Assets/Common/Animations/exit_circle_slide_right.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_circle_slide_right + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -375 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -375 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_circle_slide_right.anim.meta b/Assets/Common/Animations/exit_circle_slide_right.anim.meta new file mode 100644 index 0000000..03d44c8 --- /dev/null +++ b/Assets/Common/Animations/exit_circle_slide_right.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 523cb861bd5de1241b11afe1a6608e4e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_circle_small_slide_midleft.anim b/Assets/Common/Animations/exit_circle_small_slide_midleft.anim new file mode 100644 index 0000000..7bcc39a --- /dev/null +++ b/Assets/Common/Animations/exit_circle_small_slide_midleft.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_circle_small_slide_midleft + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 230 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 360 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.25 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 230 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: 360 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_circle_small_slide_midleft.anim.meta b/Assets/Common/Animations/exit_circle_small_slide_midleft.anim.meta new file mode 100644 index 0000000..4c87fbe --- /dev/null +++ b/Assets/Common/Animations/exit_circle_small_slide_midleft.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da5b82de67e79d74a97b0cb839a98df7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_quit_slide.anim b/Assets/Common/Animations/exit_quit_slide.anim new file mode 100644 index 0000000..f50e86b --- /dev/null +++ b/Assets/Common/Animations/exit_quit_slide.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_quit_slide + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 10 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: -50 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.25 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 10 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.25 + value: -50 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_quit_slide.anim.meta b/Assets/Common/Animations/exit_quit_slide.anim.meta new file mode 100644 index 0000000..5cca540 --- /dev/null +++ b/Assets/Common/Animations/exit_quit_slide.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cce2173a5fe35db47b4de921ae61c948 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Animations/exit_title.anim b/Assets/Common/Animations/exit_title.anim new file mode 100644 index 0000000..4b6e51a --- /dev/null +++ b/Assets/Common/Animations/exit_title.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: exit_title + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -115 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -115 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 300 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Common/Animations/exit_title.anim.meta b/Assets/Common/Animations/exit_title.anim.meta new file mode 100644 index 0000000..6646a9e --- /dev/null +++ b/Assets/Common/Animations/exit_title.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 42d8ffc35eb3bad439959a10d02816f1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Fonts/Korolev Condensed W04 Bold SDF.asset b/Assets/Common/Fonts/Korolev Condensed W04 Bold SDF.asset index a889823..cee64aa 100644 --- a/Assets/Common/Fonts/Korolev Condensed W04 Bold SDF.asset +++ b/Assets/Common/Fonts/Korolev Condensed W04 Bold SDF.asset @@ -1,53 +1,6 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: ---- !u!28 &-2284082493848745064 -Texture2D: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Korolev Condensed W04 Bold Atlas - m_ImageContentsHash: - serializedVersion: 2 - Hash: 00000000000000000000000000000000 - m_ForcedFallbackFormat: 4 - m_DownscaleFallback: 0 - m_IsAlphaChannelOptional: 0 - serializedVersion: 2 - m_Width: 1024 - m_Height: 1024 - m_CompleteImageSize: 1048576 - m_MipsStripped: 0 - m_TextureFormat: 1 - m_MipCount: 1 - m_IsReadable: 1 - m_IsPreProcessed: 0 - m_IgnoreMasterTextureLimit: 0 - m_StreamingMipmaps: 0 - m_StreamingMipmapsPriority: 0 - m_VTOnly: 0 - m_AlphaIsTransparency: 0 - m_ImageCount: 1 - m_TextureDimension: 2 - m_TextureSettings: - serializedVersion: 2 - m_FilterMode: 1 - m_Aniso: 1 - m_MipBias: 0 - m_WrapU: 0 - m_WrapV: 0 - m_WrapW: 0 - m_LightmapFormat: 0 - m_ColorSpace: 0 - m_PlatformBlob: - image data: 1048576 - _typelessdata: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010406070b0e0e0c08080602000000000000020507080c0e0e0c08070502000000000000030608090c0e0d0b0706040100000000000000000000000000000000000406070f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0807050200000000000000000000000000000000000000000000000000010507070a0d0f1011100f0e0b080806020000000000000000000000000000000000000000000000000003080b0d0e1313131313131313130c0b090501000000000000000000000000000000000000000000000000000000000000000000040607090c0e0f1011100f0e0c090706040000000000000000000000000000000000000000000000000000000000000000000000020608080b0d0f0f0f0f0e0d0b08070502000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306070603000000000000000000000000000000000000000000000000000406070a0c0e101011100f0e0b08080602000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070b0f11121313131313131313130a09070400000000000000000000000000000000000000000000000000000000000000030608090c0e0f101110100e0c0907060300000000000000000000000000000000000000000000000000000000000000000000000000010407070a0b0c0d0d0d0c0b0a08070502000000000000000000000000000000000000000000000003080b0d0e1313131313131313130c0b09050103090d10121313131313131313131308070502000005080a0b131313131313131313100f0d0905000000000000000000000000000000000000000000000000020507080b0e1011121211110f0d0b070704010000000000000000000000000000000000000000000001070b0f1112131313131313131313100f0d0a05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010507070a0d0f1011100f0e0b0808060200000000000000000000000000000000000000000000000000000000000000000000000000000002070a0c0d13131313131313131313100f0d0a05000000000000000000000000000000000000000000000000000000030608090e0e0e0e0e0e0e0908060300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d101314181a1b191514120f0903000002090e111414191b1b191414110e09020000030a0f121515191b1a181413100d070100000000000000000000000000070c1012131c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1514120e090300000000000000000000000000000000000000000104080d111314171a1b1c1d1d1c1a181514120e090501000000000000000000000000000000000000000001080f14181a1b202020202020202020181815110c06000000000000000000000000000000000000000000000000000000000001070c10131416191b1c1d1d1d1c1b19161413100c070100000000000000000000000000000000000000000000000000000000000205090f121415181a1b1c1c1c1b19171414110e0804000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003060c10121312100c06000000000000000000000000000000000000000000070c10131316191b1c1d1d1d1c1a181514120e09040100000000000000000000000000000000000000000000000000000000000000000000000000000000050c12171b1d1e202020202020202020171614100b05000000000000000000000000000000000000000000000000000001050a0f121515181b1c1d1d1d1c1b19161312100c0600000000000000000000000000000000000000000000000000000000000000000306080d111314161819191a1a1918171514120e09050300000000000000000000000000000000000001080f14181a1b202020202020202020181815110c0e14191d1f202020202020202020201514120e090c111417182020202020202020201d1c1915100a03000000000000000000000000000000000000000004090e121415181a1c1e1e1f1e1d1c1a171413110d080300000000000000000000000000000000000000050c12171b1d1e2020202020202020201d1c1916100a03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104080d111314171a1b1c1d1d1c1a181514120e0905010000000000000000000000000000000000000000000000000000000000000000000000080e1317191a202020202020202020201d1c1a16110a030000000000000000000000000000000000000000000000040a0f1215151a1a1a1a1a1a1a1615130f0a04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c12181d20202427272622211f1a150c07060b141a1e20212527272521201e19140b06070c151a1f21222627272420201d18120c0400000000000000000000030b12181c1f202929292929292929292929292929292929292929292929292929292929292929292921211e1a140d05000000000000000000000000000000000001070d1113191d2021242728292a2a29272522211e1a15110d08020000000000000000000000000000000000020b131a202427272d2d2d2d2d2d2d2d2d2524221d1811090000000000000000000000000000000000000000000000000000050b1012181c1f2023262829292a2929282623201f1d1812100b050000000000000000000000000000000000000000000000000002090e12151a1f212225272829292828262421201e1914100c0701000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b0f12171c1f201f1c17110a0300000000000000000000000000000000030a0f12181c1f20232628292a2a2a29272522211e1a15100d070100000000000000000000000000000000000000000000000000000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d2423201c161008000000000000000000000000000000000000000000000002080d11151b1f21222527292a2a2a29282623201f1c17110f0a04000000000000000000000000000000000000000000000000000000040a0f1315191d202123252526272626252321211e1a13120f0b06000000000000000000000000000000020b131a202427272d2d2d2d2d2d2d2d2d2524221d18191f25292b2c2d2d2d2d2d2d2d2d2d21201e1a14171d2123242d2d2d2d2d2d2d2d2d292826211b140c040000000000000000000000000000000001070c10141a1e20212527292a2b2b2b2a29272421201d19130f0b0600000000000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d292926211c150d040000000000000000000000000000000000000000000000000000000000000000000000000000000001070d1113191d2021242728292a2a29272522211e1a15110d080200000000000000000000000000000000000000000000000000000000000000020a12191f2326272d2d2d2d2d2d2d2d2d2d2a2926221c150d04000000000000000000000000000000000000000000060e151b1f21222727272727272722211f1b150e0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080d161d24292c2d313434332f2e2b2620181211171f252a2d2e323434322e2d2a251f1711121820262b2e2f333434312d2c29241d160d080000000000000000030c151c23282c2d353535353535353535353535353535353535353535353535353535353535353535352e2d2a251f170f05000000000000000000000000000000060b13181d20252a2d2e3133353637363634312f2e2b26201d19130d07010000000000000000000000000000010b141d252b30333439393939393939393932312e29231b12090000000000000000000000000000000000000000000000050b10161c1d23292c2d30333435363736353433302d2c29241d1c160f0a0400000000000000000000000000000000000000000001070d141a1e20262b2e2f3133353536353533312e2d2a251f1d18120b06000000000000000000000000000000000000000000000000000000000000000000000000000001080d11171c1f23282c2d2c28231c150c030000000000000000000000000002080d151a1d23282c2d303335363737363634322e2d2b26201d18120c040000000000000000000000000000000000000000000000000000000000000000000000050f1820282f333738393939393939393939302f2c28211a1108000000000000000000000000000000000000000001070c14191e20262b2e2f3234363637363634322f2d2c28231c1b150e09030000000000000000000000000000000000000000000000040b10151b1f2224292c2d3031323333333332302e2d2a25201f1b17110a02000000000000000000000000010b141d252b30333439393939393939393932312e2923232a313538393939393939393939392e2d2a251f22282d30313939393939393939393635322d261e160c030000000000000000000000000000060b12181d1f252a2d2e31343637383838373533312d2c29241f1c17110a0200000000000000000000000000050f1820282f3337383939393939393939393635322d261f160d030000000000000000000000000000000000000000000000000000000000000000000000000000060b13181d20252a2d2e3133353637363634312f2e2b26201d19130d070100000000000000000000000000000000000000000000000000000000000a141c242a2f3233393939393939393939393635322d271f160d000000000000000000000000000000000000000006101820262b2e2f343434343434342f2e2b2620181007000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a1f282f35393a3e41413f3b3a373129241d1b222730363a3b3f41413f3b3a363027221b1d242931373a3c3f41403e3a39352f281f1a1109000000000000000b151e272e34383a424242424242424242424242424242424242424242424242424242424242424242423b3a36312921170d03000000000000000000000000020a11171d24292c3036393a3d404243444342413e3b3a37312d29251e18130c040000000000000000000000000008131d262f363c40414646464646464646463f3d3a342d241b1106000000000000000000000000000000000000000000060c161c21272c2f34383a3c3f414243444342413f3c3a38352f2c27211b150f0700000000000000000000000000000000000000040c12181f252a2d31373a3b3e404242424241403e3b3936302c29241d17110a020000000000000000000000000000000000000000000000000000000000000000000003090e13191c22282b2e34383a38342e261e150a000000000000000000000000040c131920262b2e34383a3d3f414343444342413e3b3a37312c29241d160d06000000000000000000000000000000000000000000000000000000000000000000010c16202a323a3f43454646464646464646463d3c38332c231a1005000000000000000000000000000000000000030b12181e252a2d31373a3c3f414243444343413f3c3a38342e2b26201a140d05000000000000000000000000000000000000000001070c161b20272b2e2f35393a3d3e3f4040403f3e3d3b3a36312d2b27221b140b08000000000000000000000008131d262f363c40414646464646464646463f3d3a342d2c353c4145464646464646464646463b3a3630292c33393d3e46464646464646464643413e3830281e140a000000000000000000000000020a11171d24292c30363a3b3e4143444545444442403e3a3935302b28221c140b060000000000000000000000010c16202a323a3f434546464646464646464643423e3831281f150a000000000000000000000000000000000000000000000000000000000000000000000000020a11171d24292c3036393a3d404243444342413e3b3a37312d29251e18130c0400000000000000000000000000000000000000000000000000000008121c262e363b3f404646464646464646464643423e3831281f0c03000000000000000000000000000000000000040e18222a32373b3c414141414141413c3b37322a22180e0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008121a232c31394045474b4d4e4c4847433c352f27262d333b4246474c4e4e4c4746423b332d26272f353c4347484c4e4d4b47454039312c241b1209000000000007121c2730394044464f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4846423b33291f14090000000000000000000000050b141c22282f35393a4146474a4d4e4f50504f4d4b4847423c39353029241d160d080000000000000000000000030f1a252f3841484c4e5353535353535353534b4a453f372d23180c01000000000000000000000000000000000000030a111721272c333839404547494c4e4f5050504f4e4c494745403938332b27201910090100000000000000000000000000000000060d161d242930363a3c4347484b4d4e4f4f4f4e4c4a4746413b39352f27221b140b0500000000000000000000000000000000000000000000000000000000000000060b0f151a1e24292d3338393f4446443f3830261c110600000000000000000000070e161e2429313739404546494c4e4f5050504f4d4b4847423c39352f281f17110a030000000000000000000000000000000000000000000000000000000000000007121d28323c444b50515353535353535353534a48443e352c21160b0000000000000000000000000000000000060d151d24293036393c4347484b4e4f5050504f4e4c4946443f3837322a251f170f09000000000000000000000000000000000000030b121821272c32373b3c414547494b4c4c4d4d4c4b4a4846423d3937332d261d19110a020000000000000000030f1a252f3841484c4e5353535353535353534b4a453f37353e474d51535353535353535353534846423b33363e45494b535353535353535353504e49423a30261b100500000000000000000000060c141c23282f35393b4246484b4d4f51515251504f4d4a4745413a38332d261d17110a0200000000000000000007121d28323c444b5051535353535353535353504e49423a31261c100500000000000000000000000000000000000000000000000000000000000000000000050b141c22282f35393a4146474a4d4e4f50504f4d4b4847423c39353029241d160d0800000000000000000000000000000000000000000000000000020e19242e3840474b4d53535353535353535353504e4a433a311e150b0000000000000000000000000000000000000a15202a343c4347484d4d4d4d4d4d4d4947433c342a20150a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050e1a242c353e434b5153575a5a5955534e454039312f383f444d5254585a5a5854524d443f382f313940454e5355595a5a5753514b433e362d241b0f06000000000c18232e39424a51535c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c54534d453b31251a0e02000000000000000000070f171d262d333a4145474c5254575a5b5c5d5d5c5a5855534d4746413a352f281f1a1109010000000000000000000814202b36414a53585a606060606060606060585651493f34291d11050000000000000000000000000000000000030c151c232833383d44484b515356595b5c5c5d5c5c5b595653514b48443d37322b221b130a010000000000000000000000000000060f181f282f353b4246484e5355585a5b5c5c5b5b595754524c47454039332d261d170e0600000000000000000000000000000000000000000000000000000001070d11171b1f262b2f35383f44464a5053504a42382e23170c000000000000000000071018202830353c43474b515356595b5c5d5d5d5c5a5855534d474540393128231c150c030000000000000000000000000000000000000000000000000000000000000b17232f3a444e565c5e60606060606060606057554f473e33281c10040000000000000000000000000000000810181f272f353b4146474e5355585a5c5d5d5d5c5b595653504a47433c363129211b120a01000000000000000000000000000000030d151d232932383d4347494c5254565858595a5959585654534d4a46443f382f2b231c140b02000000000000000814202b36414a53585a606060606060606060585651493f3c4750585e5f6060606060606060605f524d453b3e485055576060606060606060605c5a544c42382d211509000000000000000000070f181e262e34394045474d5254585a5c5d5e5e5e5d5c5a5754524c46443f382f28221c140b0300000000000000000b17232f3a444e565c5e6060606060606060605c5a544c42382d21160a000000000000000000000000000000000000000000000000000000000000000000070f171d262d333a4145474c5254575a5b5c5d5d5c5a5855534d4746413a352f281f1a110901000000000000000000000000000000000000000000000007131f2a36404a52585a606060606060606060605d5a544c4330271c120700000000000000000000000000000000030f1b26323c464e53555a5a5a5a5a5a5a55534e463c32261b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d17202c363e474f555d6064676766625f58514b433938414950575e6165676765615e565049413839434b51585f6266676764605d5550483e362d21180e03000004101c2834404a545c6068686868686868686868686868686868686868686868686868686868686868686868615e574d42362a1e1205000000000000000007111921292f383f444b5154565e61646668696a69696764625f5754524c45413a312c231b130a0100000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6c65625b51453a2e22150900000000000000000000000000000000030d151e262e343d44484f55555c6063666768696a6968676663605d55544f47433c342d251c140a00000000000000000000000000061018212a313940454d5254585f62646668686968686664615e5653514b443f382f2920180f0600000000000000000000000000000000000000000000000003090e13181b22272b31373a41454a5053545c605c544a3f34281c100300000000000000071019222a323a41454e53545c60636668696a6a69696765615f5753514b433e342e261e150c0300000000000000000000000000000000000000000000000000000000020f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c6361594f44382c201407000000000000000000000000000008111a222a313940454c5254585f62656769696a6969676562605c54534e46423b332d241c130a0100000000000000000000000000030c151f272f343d44484e5456565d60636465666666666563615e5757535049413d352e261d140b000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6c65625b5145414d58626a6c6c6c6c6c6c6c6c6c6c6c5e574d4245505a61646c6c6c6c6c6c6c6c6c69665e54493e3226190d0000000000000000071019212930383f444b5153575e616467696a6b6b6b6a686664605d5653504a423d332d261d150c03000000000000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c69665e54493e3226190d010000000000000000000000000000000000000000000000000000000000000007111921292f383f444b5154565e61646668696a69696764625f5754524c45413a312c231b130a01000000000000000000000000000000000000000000000a17232f3b47525c63666c6c6c6c6c6c6c6c6c6c69665e5442392e23180c0000000000000000000000000000000006121f2b37434e585f6267676767676767625f584e43372b1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008141e29323e48505961676d717474726e6a605d554b423f49535b60696e727474726e69605b53493f424b555d606a6f727473716d67615a50483e332a1f1409000006121f2c3844515c666d757575757575757575757575757575757575757575757575757575757575757575756e695e53463a2d21140700000000000000071119232b333b424a50555d6065686d7073757677767574716e6966615e56514b433d352d251c130a00000000000000000d1a2733404c58646e74797979797979797979726d62564a3d3124180b000000000000000000000000000000020b151f2730383f444f54596163676d6f7274757677767574726f6d67636059544e463f372e261c12090000000000000000000000050e18222a333c434b51575e61666a6e7173757575757473716e6865605d555049413a322921180e05000000000000000000000000000000000000000000040b10141a1d24292d33373c42474c51545b6063666d665c5044382c1f1206000000000000050f19222b343c444c52585f62666d707274767677767574716e6965605d5550443f3830261e150a0000000000000000000000000000000000000000000000000000000004111d2a3743505c687278797979797979797979706b6155483c2f2316090000000000000000000000000008111a232c343c434b51565e61666a6f7274757677767674726f6d66625f58534d453e362e251c1309000000000000000000000000000a151e27313940454f5458606267686d7071727373737271706e696863605b534f4740382f261d12080000000000000d1a2733404c58646e74797979797979797979726d62564a45515e6a747979797979797979797976695e52464955616c717979797979797979797670665a4e4135281c0f00000000000000071019222b333b424a50555d6065696e71747677787877777573716d6864605b544f443f382f271e150b00000000000000111d2a3743505c6872787979797979797979797670665a4e4235291c0f03000000000000000000000000000000000000000000000000000000000000071119232b333b424a50555d6065686d7073757677767574716e6966615e56514b433d352d251c130a000000000000000000000000000000000000000000000c1926323f4b58636e7379797979797979797979767066544a4034281c10040000000000000000000000000000000815212e3b47535f6a6f747474747474746f6a5f53473b2e2115080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1925303b44505a616b70797e80817f7b746d675d544a44505b656c737b7f81817f7b736c655b50444a545d676d747c7f81807e79706c625a50453c31261a0e02000713202d3a4653606d78818282828282828282828282828282828282828282828282828282828282828282827b6e6154483b2e211508000000000000060f19232b353d454d545b60676d72777a7d808182838382807e7b77736d68605d554f473f372e251c1208000000000000000e1b2734414e5a6774808686868686868686867f7265584b3f3225180c0000000000000000000000000000000a141d273139424a505960636b7076797c7f818283838382817f7c7975706b626058514940382e241b0f05000000000000000000020b17202a343c454e555d60696e73787b7e8081828282817f7d7a77726d67605b534c443b332920160c02000000000000000000000000000000000001070c10161c1f262a2f35383f44464d53555d60666c7076786d6053463a2d2013070000000000020b17212b343d464e565d606a6f74797c7f818283838382807e7b77726d67615a504a423830261c110600000000000000000000000000000000000000000000000000000005121e2b3845515e6b78848686868686868686867d7063574a3d3024170a00000000000000000000000007101a232c353e464e555d60686e73787b7e818283838382817f7c79746f6a615e57504840372e251b1107000000000000000000000006111c263039434b515960636a6f74777a7c7e7f7f80807f7e7d7b7875706c656059524a41382f241a0d0400000000000e1b2734414e5a6774818686868686868686867f7265584b46535f6c79868686868686868686867b6e6154484b5764717e8686868686868686868276695c504336291d10000000000000050f19222b343d454d545c60676d72767b7e8082848485848382807d7a76706c666059504a423930271c1207000000000000121e2b3845515e6b78848686868686868686868276695c504336291d10030000000000000000000000000000000000000000000000000000000000060f19232b353d454d545b60676d72777a7d808182838382807e7b77736d68605d554f473f372e251c1208000000000000000000000000000000000000000003101c28343f4a54667380868686868686868686868276665c5144382c1f12060000000000000000000000000000000915222f3c4855626f7c808080808080807c6f6255493c2f221609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36414c56616c717d858a8d8d8c8781796d665c51505a606c777f868b8d8d8b867f776c605a50515c666d7981878c8d8d8a857e716c62574d42372b1e1205000714202d3a4753606d79868f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f887b6f6255483c2f2215090000000000020c18212b353d474f575e666c727a7f83878a8d8e8f90908f8d8b88847f7a736d67605951493f372e241a0e050000000000000e1b2734414e5a6774818d939393939393938b7e7265584b3f3225180c000000000000000000000000000006111b262f39434b545c606b70777d8286898c8e8f8f908f8f8e8c8986827d776f6a625b524a40362d21170d0300000000000000000a141d29333c464e575f676d737b8084888b8d8e8f8f8e8e8c8a87837e79716c655e564d453b32281e130800000000000000000000000000000003090e12181d1f272c31363a4045495053575f62676d72787d827f7265584b3f3225180c00000000000a141d29333d464e585f686d747c8185898c8e8f9090908f8d8b88847f79716c605c544a42382e23170d03000000000000000000000000000000000000000000000000000005121e2b3845515e6b788491939393939393938a7d7063574a3d3024170a0000000000000000000000040d19222c353e474f585f676d737a8084888b8d8f9090908f8e8c8985817c756e69615a524940372d23190d03000000000000000000000c17232e38424b555c606b70777c818486898b8b8c8d8c8c8b898785817d78706b645c524a41362c1f160c01000000000e1b2734414e5a6774818d939393939393938b7e7265584b46535f6c79869293939393939393877b6e6154484b5764717e8a939393939393938f8276695c504336291d100000000000020b17212b343d464f575f666d72797e83878b8d8f90919191908f8d8a86827d78706b605b544a42392e23180f060000000000121e2b3845515e6b788491939393939393938f8376695c504336291d100300000000000000000000000000000000000000000000000000000000020c18212b353d474f575e666c727a7f83878a8d8e8f90908f8d8b88847f7a736d67605951493f372e241a0e050000000000000000000000000000000000000006121f2b3844505c6676839093939393939393939286796d6053463a2d2013070000000000000000000000000000000b1825313e4b5864717e8b8d8d8d8d8d8b7e7165584b3e3225180b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3946525e68717e8791979a9a9a938e82786d605455616c74808c92989a9a98928c80746c615554606d78828e939a9a9a9791887e71695f53463a2d211407000714202d3a4753606d7a86939b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b95887b6f6255483c2f22150900000000000a141e2a333d474f5960696e787f858c909597999b9c9d9c9c9a9795918c868079706b625b51493f362c20170d0200000000000e1b2734414e5a6774818d9a9f9f9f9f9f988b7e7265584b3f3225180c00000000000000000000000000000b17222d38414b555d666d737d83898f9299999a9b9c9d9c9b9a9999928f89837c726d635c52483f33291f14090000000000000006111b262f3b454e585f6a6e7980868d919697999b9b9c9b9b999795908b857e776d685f574d443a3025190d05000000000000000000000000040b10141a1d24292c33383b42464b51535b6063696e747a7f848a8b7f7265584c3f3225190c0000000006111b262f3b454e58606a6f7a81878e9297999b9c9d9d9c9c9a9895908b847e746d665c544a3f34281f150b010000000000000000000000000000000000000000000000000005121e2b3845515e6b7884919e9f9f9f9f9f968a7d7063574a3d3024170a00000000000000000000010c161f2a343e474f59616a6f7980868c9196989a9c9c9d9c9c9a9897928e88827b716c635b52493f352b1f150b01000000000000000003101c28343f4a545c676d747d83898d91939a979899999999989697918e8a847d736e645c52483e31281d1307000000000e1b2734414e5a6774818d9a9f9f9f9f9f988b7e7265584b46535f6c7986929f9f9f9f9f9f94877b6e6154484b5764717e8a979f9f9f9f9f9c8f8376695c504336291d1000000000000a141d29333d464f5960696e787f858b9095979a9c9d9e9e9e9d9b9999928f8a837d736c665c544a40342821170d0300000000121e2b3845515e6b7884919e9f9f9f9f9f9c8f8376695c504336291d1003000000000000000000000000000000000000000000000000000000000a141e2a333d474f5960696e787f858c909597999b9c9d9c9c9a9795918c868079706b625b51493f362c20170d020000000000000000000000000000000000000713202d3a4653606d7985929f9f9f9f9f9f9fa398887c6f6255493c2f2216080000000000000000000000000000000c1925323f4c5865727f8b989a9a9a988c7f7265594c3f3226190c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3b4754616e7a869299a1a9aca49f948c7f73665c5564717e8a929fa3aaaaa39f928a7d7064555c6673808c949fa4aca9a19a92867b6e6155483b2e221508000714202d3a4753606d7a8693a0a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a295887b6f6255483c2f2215090000000006111c26303c454f59606b6f7b838b92979da0a7a6a8a9aaa9a8a7a7a09d98928d847d726d635b51483e32291f140800000000000e1b2734414e5a6774818d9aa7acacaca5988b7e7265584b3f3225180c00000000000000000000000000030f1b27333f49535d676d78808890959c9fa3aba7a8a9aaa9a8a7aba39f9c9590877f736e635a50453b31251a0e030000000000000b17222d38414d575f6a6f7c838d92999ea1a8a6a8a8a8a8a7a6a7a09d97918b827a6e695f564c41362a22170c00000000000000000001070c10161c1f252a2f35393d44484d53555d60656c70767b80858b91968b7f7265584c3f3225190c000000000b17222d38414d57606a6f7c848e939a9fa2a9a7a9a9aaa9a8a7a7a09d96918a81786d665c50443e31271d12070000000000000000000000000000000000000000000000000005121e2b3845515e6b7884919eabacacaca3968a7d7063574a3d3024170a0000000000000000000007121d28313c464f59616b707c848d92989ea1a8a7a8a9aaa9a9a7a9a29f9a938f867e736e635b51473d31271d120700000000000000030e18212c3844505c666d79818890959a9e9fa4aca5a6a6a6a5a4a9a19e9b96918980746e645a50433a2f24180d010000000e1b2734414e5a6774818d9aa7acacaca5988b7e7265584b46535f6c7986929facacacaca194877b6e6154484b5764717e8a97a4acacaca99c8f8376695c504336291d100000000006111b262f3b454e58606b6f7b838b92979d9fa7a7a9aaababaaaaa8aba39f9c95908880786d665c51443f33291f140900000000121e2b3845515e6b7884919eabacacaca99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000006111c26303c454f59606b6f7b838b92979da0a7a6a8a9aaa9a8a7a7a09d98928d847d726d635b51483e32291f14080000000000000000000000000000000000000916222f3c4955626f7c8898a2aeacacacacb4aa988b7f7265584c3f3025190d0100000000000000000000000000000d192633404c5966737f8c99a6a7a6998d8073665a4d4033271a0d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c98a2abb3b6afa69f9285796d605d677683909da5aeb4b4aea49d908376675d606d7985929fa6afb6b3aca3998d8074675a4e4134271b0e000714202d3a4753606d7a8693a0adafafafafafafafafafafafafafafafafafafafafafafafafafafaea295887b6f6255483c2f221509000000000b17232e38424d57606b707d8590959ea1a9acb1b3b4b5b6b6b5b3b1acaaa29f9691877f726d635a50443b3025190e04000000000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3225180c0000000000000000000000000005121f2b3744505b656d79828d939aa0a7acaeb4b4b5b6b6b6b5b4b5aeaca7a099928c80736c62574d42362a1f14090000000000030f1b27333f49535e696f7c8591959fa3abacb2b3b4b5b4b5b4b2b1aca9a19e948f847b6e685e52463e33281c110400000000000000030b12181d1f272c3136394045474f54575f61676d72787d82878d92989e988b7f7265584c3f3225190c000000030f1b27333f49535e696f7c8591969fa4acadb3b4b5b6b6b6b5b3b1aca9a19e938e81786d605a5043392f23180c0000000000000000000000000000000000000000000000000005121e2b3845515e6b7884919eabb7b9b0a3968a7d7063574a3d3024170a000000000000000000010d18242f39434e58616b707d8691969fa3aaacb2b4b5b6b6b6b5b4b3adaba69e98928b80736d62594f43392f24180c0100000000000009151f2c38434f59606d78828d939aa0a7aaacafb6b2b2b1b2b2b1b2adaba8a09d928d80746c61554b4035291d11040000000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b46535f6c7986929facb9b9aea194877b6e6154484b5764717e8a97a4b1b9b6a99c8f8376695c504336291d10000000000b17222d38414d57606a6f7d8590959ea1a9abb1b3b5b7b7b8b7b6b5b5afaca7a09a938d81786d605b51453b31261a0e03000000121e2b3845515e6b7884919eabb7b9b6a99c8f8376695c504336291d10030000000000000000000000000000000000000000000000000000000b17232e38424d57606b707d8590959ea1a9acb1b3b4b5b6b6b5b3b1acaaa29f9691877f726d635a50443b3025190e0400000000000000000000000000000000000c1825323f4b5865727e8b98aab4bfb9b9b9b4a89b8e817568564c41362a1d110500000000000000000000000000010d1a2734404d5a6773808d9aa6b3a79a8d8174675a4e4134271b0e0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3643505d697682909caab4bdc0baada297887c6f62606d7a86939facb9bfbfb9ac9f93867a6d60626f7c8997a2adbbc0beb4ab9d9184776a5e5144372b1e11000714202d3a4753606d7a8693a0a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a295887b6f6255483c2f22150900000003101c28343f4a545f69707d8692979fa7adb3b8bcc0c1bfbebec0c0bcb8b4aea8a199938b7f726c61564d41362a20150a000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000005121e2a36424d57606c77828f949fa4acb1b9b9b4aeacaaa9aaacaeb4b9b9b1aba39f928b7e71695e53463b31261a0e020000000005121f2b3744505b656e7b849197a0a7aeb4b9b2adaba8a7a8abadb3b8b3ada69f9691847a6d615a5045392d20150a000000000000070d151d24292c32383b42464b5153596063696e747a7f848a8f939a9fa2aa988b7f7265584c3f3225190c00000005121f2b3744505b656e7b859297a1a8afb6bab9b8b3b1b0b1b5b9bbb8b2ada59d938d80746c61554b4034291c10040000000000000000000407090a0b0b0b0b0b0b0b0b0b0b0b0b121e2b3845515e6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000004101d2935404b555f6a707d879298a0a8aeb4b9bdc0c1bfbebec1c1bebab8b0aaa29f928c7f726b60554b4035291d12070000000000020e1a26313b4854606b74818e949fa4acb1b7b2adaba7a5a4a5a7abadb3b8b2aca49d928a7e71675d5145392c2014090000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000000030f1b27333f49535e696f7c8692979fa7adb3b8bcc0bfbcbbbabbbec2c0bbb9b1aca49f938e81746d62574d42362a1f1409000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d1003000000000000000000000000000000000000000000000000000003101c28343f4a545f69707d8692979fa7adb3b8bcc0c1bfbebec0c0bcb8b4aea8a199938b7f726c61564d41362a20150a0000000000000000000000000000000005111d2935414c566874818e9ba7b4c1d0c6c4b7aa9e918477685e5246392d20130700000000000000000000000000010e1b2834414e5b6774818e9aa7b4a89b8e8175685b4e4235281b0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2a3744515d6a7783909daab7c3c9beb3a996897d7063616e7a8799a3afbbc7c7bbafa399877a6e6163707d8996a9b3bec9c5b8ab9e9285786b5f5245382c1f12000714202d3a4753606d7a869396969696969696969696969696969696969696969696969696969696969695887b6f6255483c2f22150900000006121f2b3844505c666e7b859298a1a9b1b9bebfbab8b4b2b1b2b3b7b9bdbfbab2aba49f93887e70685e52463c32261b0f010000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000000714202d3a46525e69727f8c949ea6afb6bab2acaaa29f9d9c9d9fa3abadb3bbb5aea49f92867b6e61574d42362a1e1205000000030f1b27333f4953606c77828f96a1a9b1bab3ada8a19e9b9a9b9ea1a9adb3b9b0a8a1968f82756c6155493d32271b0f03000000000710191f272f35383d44484d53555d60656b70757b80858b91969c9fa4acaea5988b7f7265584c3f3225190c0000030f1b27333f4953606c77828f97a1a9b2bbbbb3adaba6a4a3a4a8acafb5bdb9afa59d928a7d70675c5145382c1f150a00000000000000050b10141617171717171717171717171717171e2b3845515e6b7884919eabb7bdb0a3968a7d7063574a3d3024170b0500000000000000000613202c3945515d676f7c869299a2aab2babfbebab8b4b2b1b1b4b8b9bec1bcb4aea49f93877d70675d5145392f24180d010000000006121e2b37424d57636f7c89939da6afb6b6aea9a19e9a9898989b9fa2a9afb7b8aea49e9285796d6053473b31261a0e0200000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000005121f2b3744505b656e7b859298a1a9b1b9bebdb9b7b3afaeaeafb1b6b7bbc2beb6afa59d938b7f72695f53463b31251a0e020000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d1006030000000000000000000000000000000000000000000000000006121f2b3844505c666e7b859298a1a9b1b9bebfbab8b4b2b1b2b3b7b9bdbfbab2aba49f93887e70685e52463c32261b0f010000000000000000000000000000000713202d3946525e687784919eaab7c4d1d2c5b9aca096877a6d6154473a2e21140600000000000000000000000000020f1c2835424f5b6875828e9ba8b5a99c8f8276695c4f4336291c100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101c2936434f5c6976828f9ca9b3bdc0b9ada197887b6f62606d7986929facb9bfbfb9ac9f9286796d60626f7c8897a1adb9c0bdb4aa9d9083776a5d5144372a1e11000714202d3a4753606d79868989898989898989898989898989898989898989898989898989898989898989887c6f6255483c2f221509000004101c2934404b55606d78839097a2aab3bbc0bcb4aeaca8a6a4a5a7aaacb2babfbdb5afa49a92867b6e61584e43372b1e13080000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000004101c2834404a54616e7b86929fa6b0bbb8b0a8a09e9892908f9092999ea2a9b3bbbaaea3998e8174695f53463a2d21140700000005121f2b3744505b65717e8a949fa9b2bbb3a9a29e96918f8d8e91979fa2a9b3bab2a89e948a7e7164584e43372b1f1306000000040f19222b31394045474f54575e61676d72777d82878d92989da0a8acafb6b2a5988b7f7265584c3f3225190c000005121f2b3744505b65717e8a949fa9b3bcb7aea9a19e9a9796989b9fa3abb2bab7aea49e9184796d6053473c32261b0f030000000000080f161c20222324242424242424242424242424242b3845515e6b7884919eabb7bdb0a3968a7d7063574a3d30241c16100800000000000005121e2a36424d57606d79849198a2abb4bcc0bbb3adaba8a5a4a5a7abadb3bbc0bfbaafa4999184796d60554b4035291d1004000000000814212e3a47535f697683909ca5afbbb7aea49c97918d8b8b8c8e92979ea5afb9b9ada2978c7f7265574d42362a1e120500000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000003101c28343f4a54606c77828f97a1aab3bbc0bbb2adaba6a3a1a1a2a5a9abb0babec0bbafa59f92867b6e61574d42362a1e12050000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d1312100b060705020000000000000000000000000000000000000004101c2934404b55606d78839097a2aab3bbc0bcb4aeaca8a6a4a5a7aaacb2babfbdb5afa49a92867b6e61584e43372b1e13080000000000000000000000000000000714212e3a4754616d7a8796a0acb8c5d2d5c9bdb2a8968a7d7063574a3d2d22170b0000000000000000000000000003101c2936434f5c6976828f9ca9b5a99d9083766a5d5043372a1d0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c97a2abb2b5afa69e9185786c605c6776828f9ca4aeb4b4aea49c8f8276665c606c7885919ea6afb5b2aba2988d8073675a4d4034271a0d000613202d394653606c777d7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c796d6053473a2d201407000006131f2c3845515c67727f8b95a0a9b3bcbeb6aeaaa29f9b9998989a9ea0a8aeb4bcc0b6aca2988e81756a5f53473a2f24190d0100000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000006121f2c3844515c6673808d98a2aeb8bcb0a69f96918a86838384868b9297a1a9b3beb4ab9f93877b6e6155483b2e2215060000000613202d394653606c7884919ea6b0bbb3a9a197928a84828182858b9297a2a9b3bab0a69d9083776a6054473b2e2215080000000a15202b343d434b5153596063696e73797e84898f93999fa2aaacb2b9b3adaba7988b7f7265584c3f3225190c00000613202d394653606c7884919ea6b0bbb7aea49d97918d8a8a8b8e9299a0a8b2bbb9ada1968b7f7265584e43372b1f13060000000008111a21272c2f303131313131313131313131313131313845515e6b7884919eabb7bdb0a3968a7d7063574a3d302c28211a110800000000000714202d3a46525e6973808d96a0aab4bdbdb5afa9a29f9b9897989a9ea1a9afb5bdc0b5aba1968c7f73675d5145392c201408000000000815222f3b4855626e7b88949fabb7baaea49c928c84817f7e7f81858e939ea6b0bcb3a99d908477695f53463a2d21140700000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000006121f2c3844505c66717e8b949fa9b3bcbeb6afa8a19e9996949495989c9fa6adb3bbc1baaea2988e8175695e53463a2d2114080000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362921201f1c171414110e0902000000000000000000000000000000000006131f2c3845515c67727f8b95a0a9b3bcbeb6aeaaa29f9b9998989a9ea0a8aeb4bcc0b6aca2988e81756a5f53473a2f24190d0100000000000000000000000000000a1724303d4a5763707d8a96a8b2bdc8d4d9cec0b3a6998d807366544a3f33281c0f0300000000000000000000000004101d2a3743505d6a7683909da9b6aa9d9184776a5e51442f24180d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a859299a1a8aba39f948b7f72665b5563707d89929fa2aaaaa29f92897d7063545b66727f8c949fa4aba8a19992867b6e6154473b2e2114080005121f2b3744505b656c6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6d675d5145392c1f130600000714202d3a4753606d7985929ea7b1bcbeb5aca49d98928e8c8b8b8d91969fa2aab4bcbeb4aa9e93887c6f62554c4135291d110400000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000713202d3a4653606d7985929eaab4beb4aa9f9490847e797776777a7e859197a1adb9bbafa4998b7f7265584c3f2d22170b0000000a1723303d4a5663707d8996a0acb8b9ada19791857e79757475797e859297a2adbab8aca095897c6f6256493c2f2316060000030f1b27323d464e555d60656b70757b80858b91959c9fa4abaeb3b5aeaca9a19e9a958b7f7265584c3f3225190c00000a1723303d4a5663707d8996a0acb8bcafa59d928d85807e7d7e82879196a0a9b3bdb2a89d9184776a5f53473b2e211508000000050f1a232b33383c3d3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e45515e6b7884919eabb7bdb0a3968a7d7063574a3d3c38332c231a100500000003101c28343f4a54616e7b86929fa8b2bcbeb5aba49f97928e8c8b8b8e92979fa4abb5bebdb2a89f9285796d6053473b3025190e020000000c1925323f4c5865727f8b98a6b0b4b4a99d928c807974727172747a818e949fabb7b8aca095887b6e6155483b2e22150800000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000713202d3a4653606d7884919ea6b0bbc0b6aca49f96918c898887888b90949fa2a9b3bcbfb4aa9f93877b6e6154483b3025190d0100121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362e2e2d2b282321201e1a140f0a040000000000000000000000000000000714202d3a4753606d7985929ea7b1bcbeb5aca49d98928e8c8b8b8d91969fa2aab4bcbeb4aa9e93887c6f62554c4135291d110400000000000000000000000000030f1c28333f4a546673808c99a6b3bfced9dccfc2b6a99c8f8376665b5044382b1f120600000000000000000000000004111e2b3744515e6a7784919daab7ab9e9285786b554b4035291d1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c3945525d68707d8791969a9a99928d82786c605454606b73808c92989a9a98928b80736b605454606c78828d93999a999691877e70695e52463a2d20140700030f1b27333f49535b6063636363636363636363636363636363636363636363636363636363636363636363605d554b4035291d10040005111e2a36414c5665717e8b97a1adb9c2b8aca39b928d86817f7e7f80848b9298a2aab4bfbcafa59b8e8174675d5145392c20130600000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000a1623303d495663707d8997a2adbcbaaea298908279716d6769676d717b85919eaab4bfb5ab9c8f82756953493f33271b0f030005111e2a36424d576874818e9ba8b2bdb2a89e91857b716d6667666d717c85929fabb8b8b1a7998c7f7366594c402d22170b000006131f2b37434e5860676d71777d82878d92979da0a7acafb5b1ababa39f9b97928d89837d6f6356493c302316090005111e2a36414c566774818e9aa8b2bdb4aa9e938d807973717071757c849197a1adb9b8aca096887c6f6255493c2f2216090000000b16212b353d44484a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a515e6b7884919eabb7bdb0a3968a7d7063574a4a48443e352c21160b00000006121f2b3844505c6673808d98a3aebac0b6aca499938c85817f7e7e81858c9399a4acb6c0baada2978b7e7265564c41362a1e11050000020f1c2935424f5c6875828f9ba7a7a7a7a89a8d81746d66656565676d7883909cabb5bcb1a7978b7e7164584b3e3125180b00000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d100005111d2935414c5664717e8a96a1adb8c2bbafa49a938c84807d7b7b7c7e838a9297a2aab4bfbbafa4998c807366564c41362a1e110500121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433b3b3a3a38342e2e2d2a251f1b150d080200000000000000000000000005111e2a36414c5665717e8b97a1adb9c2b8aca39b928d86817f7e7f80848b9298a2aab4bfbcafa59b8e8174675d5145392c2013060000000000000000000000000006121f2b3844505b6676828f9ca9b5c2cfdcdfd2c5b8ac9f9285796c605346392d20130600000000000000000000000003101c28343f4a546b7885919eabb8ac9f928679675d5145392c2013060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c56606b707d848a8d8d8c8780786d665b504f59636e737f868b8d8d8b867f736e63594f505b666d7880878c8d8d8a847d706c61564d42362a1e110500000b17222d38414950535656565656565656565656565656565656565656565656565656565656565656565653514b43392f24180c00000714202d3946525e687683909ca9b3bebbb0a69b918b807a7573717274787e869298a2aebac1b8ac9f92867a6d6054473a2d21140700000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000d192633404c5966737f8c99a9b3aeaeab9f92867a6d67605c555d6069717e8a98a2aebab8ab9e918578655b5044372b1f1205000714202d3a46525e697884919eabb8b9ada1968a7d7169605c545c606a727f8c98a9acacaca99c8f827669544a3f33281c0f03000815222e3b4754606a6f797e83898f92999fa2a9acb1b2adaba79f9d99928f8a85807c776f6b6054483b2f221509000713202d3946525e687884919eabb7baaea3988e81746d676463656a6f7b85929eabb8bdb2a8998c7f7266594c3f33261907000004101c27333d474f54565757575757575757575757575757575757575e6b7884919eabb7bdb0a3968a7d7063575757554f473e33281c100400000713202d3a4653606d7985929eaab4bfbbafa49a9387807a7572717274798087939aa4afbbbeb3a99c908376685e5246392d201407000004101d2a3743505d6a7683909a9a9a9a9a9a96877b6e615c5458555d66707d8a99a4afbbb3a69a8d8073675a4d4034271a0600000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000713202d3946525d6876828f9ca8b2bdbbb0a69f9388807973706e6e6f72767d859298a2aebac0b5ab9d908477685e5246392d20130700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504848484746443f3f3b3a36302b272019130c0400000000000000000000000714202d3946525e687683909ca9b3bebbb0a69b918b807a7573717274787e869298a2aebac1b8ac9f92867a6d6054473a2d211407000000000000000000000000000613202d394653606c7985929fabb8c5d2dedfd3c6baaea298887b6f6255483c2f22150800000000000000000000000006121f2c3844505c667985929facb8aea399867a6d6053473a2d20140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d19242f3a444f59606b70797d80807f7b746d665c544a47525c636d727a7e80807e7a726d635c52474a545c666d747b7f81807d79706b615a50443b3025190e02000006111b262f383f4446494949494949494949494949494949494949494949494949494949494949494949494745403931271d120700000814212e3b4754616e7a86939facb9c5b7aa9f948b7e736d68666565666c717d86929fa8b2bdbaaea3988a7d7164574a3e2e23180c00000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000f1c2835424f5b6875828e9ba1a1a1a1a19a8d8074685e55514b5157606d7985929facb8b9ac9f9286786c605346392d201306000814212e3b4754616e7b8796a1adb9b7ab9e9184786c6057504a5058616e7a87979f9f9f9f9f9e928578665b5044382b1f1206000916232f3c4956626f7c858b90959b9fa3abadb3aeaca8a19e9995908b86827d79746f6a6360594f44382c201307000714212e3a4754616d7a8796a1acb9b9ac9f92867a6e615d5557585f69727f8c99aab4bfb5a89b8f8275685c4f422f24180c00000714202c38444f596063646464646464646464646464646464646464646b7884919eabb7bdb0a3968a7d706464646361594f44382c20140700000a1623303d495663707c8997a1adbcc0b6ac9f93887e736d67656465676d737e88939facb6c0b9ac9f93877a6e6154473b2e211408000005111e2b3844515e6b77848d8d8d8d8d8d8d8d8477695e524a4b4c54606d7a86939facb9b5a99c8f8276695c4f432d22170b00000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000714212e3a4754616d7a86929facb9c4b7ab9f948b7f736d6663616162656c707c86929facb6c0b8aca095877a6d6154473a2e21140700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c555555545453504a4b4746423b373229241e160e07000000000000000000000814212e3b4754616e7a86939facb9c5b7aa9f948b7e736d68666565666c717d86929fa8b2bdbaaea3988a7d7164574a3e2e23180c000000000000000000000000000915222f3c4855626f7b8898a2aebac6d3dfdfd6cabfb4aa988b7e7165584b3e2f24190d0100000000000000000000000713202d3a4653606d798698a2aebab5ab94877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e28323d474f5960676d717374726e69605c544a42404a525b62686d717474716d68625b524a40424a545c60696e727473716d67605950483e32291f1409000000000a141d262d3337393c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3a39352f271f150b0100000b1724313e4a5764717e8a99a4afbbbeb3a99c8f82766c605d5658545b606b727f8b96a1adb9bfb4aa9b8e817468544b4034281c1004000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000101d2a3643505d69768390949494949494948a7d7064564c454045515c667784919daab7bbaea399877a6d6054473a2d211407000a1723303d4a5663707d8996a9b2bdb4a79b8e8174655b50443f46525e687885929292929292929286796c605346392d201306000a1724313d4a5764707d8a979da0a7acafafacaaa29f9b96918d88837f7a75706d66626058544f473d32271b0f03000a1623303d495663707c8996a8b2bdb6a99c8f8376685e524b4a4e57616e7b8898a2aeb1b1aa9e9184776b554b4035291d1004000916222f3c4854606b7071717171717171717171717171717171717171717884919eabb7bdb0a3968a7d71717171706b6155483c2f23160900000d192633404c5966737f8c99a9b3bebbafa49a8d81746c605d5558555c606c74818d9aa4afbbbbafa49a8a7e7164574b3e312418060000010d1a2734404d5a67738081818181818181817f7266574d423e45515d677885929fabb8b7aa9d9084776a53493f33271b0f03000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a99a3afbbbfb4aa9c8f82766d605c545554555a616a73808c9aa4afbbbcb1a7968a7d7063574a3d3024170a00121e2b3845515e6b7884919eabb7c2b6a99c8f837669626262626161605c545854524d47433d353028201910080000000000000000000b1724313e4a5764717e8a99a4afbbbeb3a99c8f82766c605d5658545b606b727f8b96a1adb9bfb4aa9b8e817468544b4034281c10040000000000000000000000000b1825323e4b5865717e8b98aab3becad6d3d2d3d0c1b4a79b8e817468564c4135291d110400000000000000000000000714212e3a4754616d7a8794aab4bfaea295887b6f6255483c2f2215090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c16202c353d474f555c6064676765615f57514a423938404951565e6165676765615e565149403839424a51575f6165676664605c554f473e362c20170d0200000000020b141b22272b2d303030303030303030303030303030303030303030303030303030303030303030302d2c29241d150d030000000e1a2734414d5a6774808d9aabb5c0b9ada297897c6f635a524c4b4a5059606d7984919eabb8c3b7aa9d908477665c5145382c1f1306000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000111e2a3744515d6a77838787878787878787877c6f6255493c404a54606a7884919eabb7baaea398877a6d6054473a2d211407000b1825313e4b5864717e8b97a4b1beb3a6998d80736653493f36414c566a77848585858585858585867a6d6154473a2e211407000a1724313d4a5764707d8a97a9acb1b6aca49f9c98928e8984807b77726d6864605c54544e48443d352b21160b00000b1825313e4b5864717e8b97a4b1beb3a79a8d807467564c413d46535f697985929fa4a4a4a49f928579675d5145392c1f1306000a1723303d4a5663707d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7e85929eabb8c0b3a6998d807d7d7d7d7d7063574a3d3024170a00030f1c2936424f5c6975828f9ca8b1b1b1ac9f93877b6e615a514b4b4b515a616e7b87939facb9c0b6ac9a8d8074675a4d412e23170b0000000d1926333f4c58646e737474747474747474726d63574d4a47464b556b7885919eabb8b8ab9e928578655b5044372b1f1205000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000d1a2633404d596673808c99abb5b1b1aea3988a7d70635b514b4848495058616e7a87939facb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c2b6a99c8f83766e6e6e6e6e6e6d6d666865615e57544e45413a322b221a110800000000000000000e1a2734414d5a6774808d9aabb5c0b9ada297897c6f635a524c4b4a5059606d7984919eabb8c3b7aa9d908477665c5145382c1f1306000000000000000000000004111d2935414c556774818e9aa7b4c1d0cbc7c5c7cbc4b7aa9d918477685d5245392c20130700000000000000000000000815222e3b4855616e7b8894a1aebbafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d1a232c353d434b5153575a5a5955534d444039302e373f444c5254585a5a5854524c443f372e303940444d5355595a5a5753514b433d352c241a0e05000000000000020a11171b1f2023232323232323232323232323232323232323232323232323232323232323232323201f1d18120b0300000000101c2936434f5c6976828f9ca9b5c2b8ab9e9285796c605346413e3f44505c6674818e9ba7b4c1b9ac9f9286796d6053463a2d201307000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000814212e3b4754616e7b7b7b7b7b7b7b7b7b7b786d605346424b515b666f7c8896a1adb9b8ac9f928579675d5145392c201306000c1926323f4c5965727f8c98a5b2bfb3a6998c807366594d40303b4f5b6772777979797979797979796d685d5246392d201307000a1724313d4a5764707d8a97a3b0bbafa49a938f8b86817d78736e6a65615e5653514b47433d38322b23190f0400000c1925323f4c5865727f8b98a5b2beb3a6998c807366594d4036424d576b78859197979797979798867a6d6053473a2d20140700111e2b3744515e6a77848a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a9297a1adb9c1b4a89c928d8a8a8a8a84786b5e5145382b1e1200030f1b27333f49536a7784919da4a4a4a4a49d908477695f5345403e4046535e697783909daab7c2b6a99c8f837669544a3f34281c100300000b1723303b47525c6467676767676767676766635b5a595754524c5e6b7885919eabb8b9ac9f9386796c605346392d201306000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000f1b2835424e5b6875818e9ba4a4a4a4a49f92867a6d605347403b3b3e46525e687784919daab7c0b3a6998d8073665a4d4033271a0d00121e2b3845515e6b7884919eabb7c3b6a99d90837c7b7b7b7b7b7b7a797775726e69626058524c443d342b231a100700000000000000101c2936434f5c6976828f9ca9b5c2b8ab9e9285796c605346413e3f44505c6674818e9ba7b4c1b9ac9f9286796d6053463a2d20130700000000000000000000000613202c3945515d677784919daab7c4c7c0bbb9bbc0c6b9ac9f93867a6d6054473a2d21140600000000000000000000000916222f3c4955626f7c8895a2afbbb0a3978a7d7064574a3d3124170a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a232b31394045474a4d4d4c4846423b342e27252d323a4146474b4d4d4b4746413a322d25272e343c4247484c4e4d4a47454039312b231a1108000000000000000000060b0f1213161616161616161616161616161616161616161616161616161616161616161616161413100c07010000000000111e2b3744515e6a7784919daab7c2b5a99c8f8276665b5044382f343f4a5465727f8c98a5b2bfbbaea399877b6e6154483b2e211508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000714202d3a46525e696e6e6e6e6e6e6e6e6e6e6d665c51444d545c606c7882909ca8b2bdb7aa9d9084776a554c4135291d1104000c1926333f4c5966727f8c99a5b2bfb3a6998c807366594d40333f4b5660676a6c6c6c6c6c6c6c6c6c615d564c4135291d1105000a1724313d4a5764707d8a97a3b0b9ac9f9387827e7a75706c66625f5854524c4645403937322c27211911070000000c1926333f4c5966727f8c99a5b2bfb3a6998c807366594d403145525e6b78848b8b8b8b8b8b8b8b877a6d6154473a2e21140700111e2b3744515e6a77849197979797979797979797979797979797979797979ea1a9b3bec5b9aea49c999797979184786b5e5145382b1e120005121f2b3744505b65798592979797979797978e817468574d42352f36424d576774808d9aa7b3c0b8ab9e918578665c5044382b1f1206000007131f2b36404a52585a5a5a5a5a535b6062656667676664615e565e6b7885919eabb8bbafa49986796d6053463a2d201307000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000101d2a3643505d6976839097979797979797908376675d5145392e2e36414c56697683909ca9b6c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4b8ab9f959088888888888887878684827e7b756f6a605d564e463d352b22190d04000000000000111e2b3744515e6a7784919daab7c2b5a99c8f8276665b5044382f343f4a5465727f8c98a5b2bfbbaea399877b6e6154483b2e21150800000000000000000000000714212d3a4754606d7a86939facb9c4bdb5afacafb5bdbbafa49a897d7063564a3d2d22170b00000000000000000000000a1623303d495663707c8996a3afbcb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000811191f272f34383a3e40413f3b3a363128231c1b20293036393a3e41413e3a39363029201b1c232831373a3b3f41403e3a38342f271f1a1108000000000000000000000000030506090909090909090909090909090909090909090909090909090909090909090909090706040000000000000000121f2c3845525f6b7885929eabb8c1b4a79b8e817468544a3f33282e3e4a5764717d8a97a4b0bdbfb5ab95887c6f6255483c2f221509000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000005111e2a36424d565e61616161616161616161605c544a50575e666d75808d949fabbabcb1a79a8d8073675a4d402f24190d01000d192633404c5966737f8c99a6b2bfb3a6998c807366594d403c3c444e565b5e5f5f5f5f5f5f5f5f5f54524c443a3024190d01000a1724313d4a5764707d8a97a3b0bbafa49a90837f7a75706c65615f5753514b48433d3a36302b26201810060000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333e4a5764717e7e7e7e7e7e7e7e7e7e7a6d6053473a2d20140700111e2b3744515e6a7784919da4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4abadb3bbc5cac0b6aea8a6a4a49e9184786b5e5145382b1e12000613202d394653606c79878b8b8b8b8b8b8b8b8b8073675a4d403125313f4c5965727f8c98a5b2bfb9ac9f9386796d6053463a2d2013070000030e19242e3840474c4d4e50565d61656c6f7273747473716d6862606b7885919eabb8c0b5a093877a6d6054473a2d211407000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000111d2a3744505d6a77838b8b8b8b8b8b8b8b8b817568554b4035292b3844505b667683909da9b6c1b4a79a8e8174675b4e4134281b0e00121e2b3845515e6b7884919eabb7c4bcb1a79f9d959595959595949992918e8b86827c746d6860584f473d342b1f160c010000000000121f2c3845525f6b7885929eabb8c1b4a79b8e817468544a3f33282e3e4a5764717d8a97a4b0bdbfb5ab95887c6f6255483c2f22150900000000000000000000000a1723303d4a5663707d8999a4afbbbbb2aba39fa3abb5c0b6ac998c7f736653493f33271b0f03000000000000000000000a1724313d4a5764707d8a97a3b0bdb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070d151d23292c2d313434322e2d2a261f18120e171e252a2d2e323434322e2d2a251e170e12181f262b2d2e323433312d2c29231d150d0800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e412d22303d4a5763707d8a96a3b0b5b5afa296897c6f6356493c30231609000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000020e1925303b444d525454545454545454545453514c525a61696e78818d929da6b0bcb8aca095897c6f6356493c3023160800000d192633404c5966737f8c99a6b2bfb3a6998c807366594d49494949494949515252525252525252524746413a32281e130800000a1724313d4a5764707d8a97a3b0bfb6ac9f95908b86817d78736e6964605d55544f4746423b37322a22180e0400000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333c4955616c717171717171717171716d675d5145382c1f130600111e2b3744515e6a7784919daab0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b8b9bec5cdd1c8c0b9b4b3b0ab9e9184786b5e5145382b1e12000613202d394653606c787e7e7e7e7e7e7e7e7e7e7c6f6255493c2f25313e4b5864717e8b97a4b1bebbafa499877a6d6154473a2e21140700000008121c262e363b4049515a62686d73787c7e808181807e7a756f6a6b7885919eabb8baada094877a6d6154473a2e211407000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d7e7e7e7e7e7e7e7e7e7d6f6356493c2f2a333b4653606c7985929fabb8c0b3a6998d8073665a4d4033271a0d00121e2b3845515e6b7884919eabb7c4c2b9b1aba9a1a1a1a1a1a1aba39f9d9b99928f87817a6f6a60594f463c31281e13080000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e412d22303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000030f1b27333f495366737f8c99abb5beb2a9a1999299a3afbbb5a99c8f8276655b5044372b1f1205000000000000000000000b1825313e4b5864717e8b97a4b1beb3a6998c807366594d4033261a0d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b12181c1f202427272622211e1a140c07050d13191e20212527272521201e19130d05070c151a1e212226272724201f1c18120b030000000000000000000000000000000000000000000000000406070a0d0e101011100f0e0b08070502000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3a8a8a8a8a296897c6f6356493c30231609000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000009141f29323b424647484848484848484848464f565d606c717b838e939da4aeb8b9afa59d9083776b6054483b2f22150900000d192633404c5966737f8c99a6b2bfb3a6998c8073665956565656565656565656565656565656565653514a42392e23180c00000a1724313d4a5764707d8a97a3aeb4b9b1a79f9d98928e8984807b76716d6763605954524d47433c342a20150a00000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333945505a6164646464646464646464605d554b4035291d100400111e2b3744515e6a7784919daab7bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdc5c6c9cfd6dad1cac4c1bfb7ab9e9184786b5e5145382b1e120006121f2b3844505b666c717171717171717171716f6a5f53473b2e25313e4b5864717e8b97a4b1bec0b5ab94877b6e6154483b2e2115080000000009151f2a333f49515b636c717a8084888b8c8d8d8c8a86827c746d7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1623303c4955616c707171717171717171716f6b6054483b2f323b45505a63707d8998a2aebac0b5ab988c7f7265594c3f3226190c00121e2b3845515e6b7884919eabb7c4cbc2bcb8b6aeaeaeaeaeaeb5aeacaaaba39f9a938e847c706b60584e433a2f24190d0400000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000005121f2b3744505b6575828f9ca8b5b9ada1979186929facb9b8ab9f9285796c605346392d201306000000000000000000000c1925323f4c5865727f8b98a5b2beb3a79a8d8074675a4d4134271a0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070c101314171a1a191514120e0903000002080d111314181a1a181413110d0802000003090e121415191b1a171413100c07010000000000000000000000000000000000000000000001070c10131417191b1d1d1d1d1c1a181514120e090400000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a969b9b9b9b9b9b96897c6f6356493c30231609000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000020d17202930363a3b3b3b3b3b3b3b3d434b515961686d757e8590959ea5aeb6bab1a79d93897d7063594f44382c20130700000d192633404c5966737f8c99a6b2bfb3a6998c80736662626262626262626262626262626262626262605c544a4034281c1004000a1724313d4a5764707d8a979fa3aaadb2b1abaaa29f9b96918c87827e79746f6b66615e56534e463c32261b0f03000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033333e4850555758585858585858585853514b43392f24180c0000111e2b3744515e6a7784919daab7c4c5beb9b8b0b0b0b0b0b0b0b0b0b0b0b0b8b9bec5cdd1c8bfb9b4b3b0ab9e9184786b5e5145382b1e1200030f1c28333f4a545b6064646464646464646464625f584e43372b25313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000000020e1a26313c45515b636d737e858d919798999a9a9999928f8780787885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000814202d3944505a61646464646464646464646360594f4338313a444d57616c76828f9caab4bebbafa3998a7d7064574a3d3124170a00121e2b3845515e6b7884919eabb7c4d1cdc8c4c3bbbbbbbbbbbbbfbbb9b7b5afaca49f9691867d706a60554c41352920150a00000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000613202d394653606c7985929eabb8b8ab9e918583909da9b6baada297887b6e6255483b2f221507000000000000000000000c1926333f4c5966727f8c99a5b2bfb4a79b8e8174685b4e4135281b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406070b0d0e0c08070502000000000000010507070b0e0e0b07070501000000000000020608080c0e0d0b0706040000000000000000000000000000000000000000000000040a0f12181c1f20232628292a2a2a29272521211e1a14100c070000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a8f8f8f8f8f8f8f8f897c6f6356493c30231609000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000000050e171f252a2d2e2e2e2e2f383f444f555d606b707a818a92979fa7afb7b9b1a8a0958e81746b6054473d32271b0f0300000d192633404c5966737f8c99a6b2bfb3a6998c80736f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6d665c5144382c1f1206000a1723303d4a5663707d888e92989ea1a8abb0b4aeaca8a19e9a938f8b85817c77726e69625f584e43372b1f1206000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40332c363e45494a4b4b4b4b4b4b4b4b4b4745403931271d12070000111e2b3744515e6a7784919daab7c4bbb3adaba3a3a3a3a3a3a3a3a3a3a3a3abadb3bbc5cabfb6aea8a6a3a39e9184786b5e5145382b1e1200000b17222d38424a50535858585858585858585855534e463c322625313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000006121e2b37424d57626d737f8b92979ea1a9a6a7a7aba39f9a938d827884919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d100004101c28333e4850555758585858585858585856544f463d333b434c565f69717e8a949fabbcc5b9ac9f92867a6d6054473a2d21140700121e2b3845515e6b7884919eabb7c4cfc7c0bbb9b8b8b8b8b8b9bbc0c1c4c0bbb6afa8a19892867c6f675d51453c31261b0f02000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000815222f3b4855626e7b8897a2adb9b5a89c8f82808d9aa7b4beb3a9978b7e7164584b3e2f24180d010000000000000000000d1a2733404d5a6673808d99a6b2b2b2a89b8f8275685c4f4235291c0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080e151b1d23292c2d303335363737363534312e2d2a251f1c18120b03000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272f3c4955626f7c828282828282828282827c6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000000000050d14191e20212129313a424a505960676d747d848e939fa2a9b1b9bbb0a7a0969083796d60594f44352b21160b0000000d192633404c5966737f8c99a6b2bfb4a79a8e817c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c796d6053463a2d201307000916232f3c4855616b707c81868c91969c9fa6acaeb4b2acaca49f9c98928e89847f7b756f6a5f53473b2e211508000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033262c33393c3e3e3e3e3e3e3e3e3e3e3a38352f271f150b010000111e2b3744515e6a7784919daab7beb3a9a19e9796969696969696969696969ea1a9b3bec4b9aea49c999696969184786b5e5145382b1e12000006111c262f383f44464b4b4b4b4b4b4b4b4b4b4947433c342a2025313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f2215080000000814212d3a47535f69727f8b919fa2a9adb2b3b4b4b5afaca49f948d8084919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000b17222c363e44494a4b4b4b4b4b4b4b4b4b4948433d343d454d565e686e7b85929fa6b0bbbeb3a99d908376685d5245392c20130700121e2b3845515e6b7884919eabb7c4c7bdb5afacabababababacafb5b5b9bbc0c0bbb2aaa29891847a6d60584e43372b1e1308000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000b1825313e4b5864717e8b97a9b3beb3a6998c807e8b97aab4bfb4a79a8e817467554b4035291d11040000000000000000000e1b2734414e5a6774818d9aa5a5a5a5a59c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020507080a0d0e0f0f0f0e0d0b08070502000000000000000000000000000000000000000000000000000000000000000000000000000000000000050d141920272b2f34383a3d40414343444342413e3b3a36312c28231d150c060000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272e3b4754606a6f757575757575757575756e6a5f53473a2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000000000002090e11172129323b434c545b606b6f79818a91969ea5adb3bbb5afa69e9590847b6e675d51473d3323190f040000000d192633404c5966737f8c99a6b2bfb5a99d938e8989898989898989898989898989898989898989877a6e6154473b2e211408000714202c38444f59616a6f747a7f848a8f949a9fa2aaacb2b6afacaaa29f9a96918c86827c6f6255483c2f221509000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40332622282d30313131313131313131312d2c29241d150d03000000111e2b3744515e6a7784919dabb5b9ada197928a8a8a8a8a8a8a8a8a8a8a8a9297a1adb9c1b4a89c928c8a8a8a8a84786b5e5145382b1e120000000a141d262d3338393e3e3e3e3e3e3e3e3e3e3c3b37322a221825313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000005121e2a36424d57616e7b86929fa4adb3b9bebebab8b3b1b6afa69f928686929facb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000005101a232c33393c3d3e3e3e3e3e3e3e3e3e3c3b38343f464f575e686d7a839098a2aeb8c2b9ada1978b7f7265564c4135291d110400121e2b3845515e6b7884919eabb7c4c0b5aba39f9e9e9e9e9e9fa3aba8acafb5bdc3bcb4aaa1968e81746a5f53473a3024190d010000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000004101d2935404b556774818d9aa7b4beb3a9968a7d7c8898a2aebab7aa9d908477675d5145392c2013060000000000000000000f1b2835424e5b6875818e989898989898989084776a5d5144372a1e110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004080e11141417191b1c1c1c1b1a181514120e0904010000000000000000000000000000000000000000000000000000000000000000000000000000070e171e252a3237394045474a4c4e505050504f4d4b4846423b38342e271e17110a02000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272b37434e58606268686868686868686868625f584e43372b1f1206000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000000000000030c162029333b444c565d666c737c848e929ea1a9afbabbb2aba39f948f837b6e695e554b40352b211107000000000d192633404c5966737f8c99a6b2bfbaafa59d9a9595959595959595959595959595959595959594877a6e6154473b2e2114080004101c27333d474f585f62686d72787d83888e92989ea1a8abb0b8b3aeaba8a09d99928b7f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033261a1c212324252525252525252525201f1d18120b03000000000f1c2936424f5c6975828f99a3afb8ab9e92857e7d7d7d7d7d7d7d7d7d7d7d85929eabb8bfb3a6998c807d7d7d7d7d706356493d3023160a000000020b141c22282b2d31313131313131313235362e2d2a251e1625313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000714212d3a46535e6975828f98a2aebabec2bbb3adaba7a4a3a5a8a399929298a3aebabaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000008111a22282d30313131313131313131313030394045505960696e7a839095a0aab3bebcb1a79e92857a6d6054473a3024190d0100121e2b3845515e6b7884919eabb7c4bbafa3999292929292929299979b9fa4abb1b9c3bcb2a89f93877c6f62564c4135291d11050000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000613202c3945515d677783909daab7b9ada197877b7985929facb8b9ac9f92867a6d6053473a2d2014070000000000000000000f1c2936424f5c6975828c8c8c8c8c8c8c8c8c84786b5e5145382b1e120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070c1014191e202124262829292928262421211e1a14110d08010000000000000000000000000000000000000000000000000000000000000000000000081119202930363c43474b515356595b5c5d5d5d5c5a5854534d464540393027221b140b020000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342727323c464e54555c5c5c5c5c5c5c5c5c5c55534e463c31261a0f02000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000a151e28323b454d565e686d787f8791969da5adb2bbb6afa8a099928c827a6e695e574d43392f23190f00000000000d192633404c5966737f8c99a6b2bfc0b7afa9a7a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a194877a6e6154473b2e21140800000b16212c353d464e53565e61666d71767c81868c91969c9fa6acaeb4b8b2acaba3988b7f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033261a111417171818181818181818181413100c070100000000000915222f3c4855626f7c87929faab4ada1978b7e717070707070707070707884919eabb7bdb0a3968a7d70707070706b6054483b2f22160900000000020b141b22272b2d312d3337393b3d3f41433a393630282025313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000815212e3b4854616e7b87939faab4bfc2b8b0a9a29f9a9797989c9fa39f9fa3aab4bfbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000000000810171c20232425252525252525252b333b434b515a626b6f7b8390959fa7b1bcbfb4aaa0958c7f72675d514539281e13080000121e2b3845515e6b7884919eabb7c4b9ac9f9287858585858586878a8e9399a0a7b1b9c3bbafa4998e8175685d5246392d2013070000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000714202d3a4753606d7a86929facb9b8ab9e9185787683909ca9b6bbafa399897c706356493d302316090000000000000000000b1724313e4a5764717e7f7f7f7f7f7f7f7f7f7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b12181d1f252a2d2e3133343536353533312e2d2a25201d19130b06000000000000000000000000000000000000000000000000000000000000000000081119232b323b41464e54555c60636668696a6a69686764615e5753514b433e332d261d140b0200000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427202b343c4347494f4f4f4f4f4f4f4f4f4f4847433c332a20150900000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000000000006111c26303a444d575e686e7a828c9299a0a8afb9bbb2aca49f9691877f776d685e574d453b31281d110800000000000d192633404c5966737f8c99a6b2bfc5bcb4aeababababababababababababacafb5afafafada194877a6e6154473b2e211408000005101a232c343c43474c52545c60646a6f747a7f848a8f949a9fa2aaacb2b7b5a5988b7f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033261a0f1315161616161616161616161313100c070000000000000815212e3a47535f6a74818e98a2aeb3a99e9184796d636363636363636b7884919eabb7bdb0a3968a7d706363636360594f44382c201307000000000a141d262d3337393d3f3f4446484a4c4e504746413a322825323f4b5865727e8b98a5b1bebbaea194887b6e6155483b2e2215080003101c28343f4a5466737f8c99a4afbcc4bab0a69f97928d8a8a8b8f9399a2aaaeb4bcc6baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d100000000000050b1014161718181818161d2429353d454d555c606c717d8590959fa7b1b9c0baaea3989083786d60554b413529160c020000121e2b3845515e6b7884919eabb7c2b6a99c8f827878787878797a7d82879095a0a7b1bdc0b5ab9f92867a6d6154473a2e2114070000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000a1623303d495663707c8999a3afbbb5a89c8f827574808d9aa7b3c0b5ab998c7f7266594c3f31261a0e0200000000000000000a1723303d4955616c71727272727272727272726d62564a3e3124180b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d151d24292c3036393b3d404142424241403e3b3a36312c29241e17110a02000000000000000000000000000000000000000000000000000000000000061019232b353d444c52586062676d707374767677767574716e6965605c554f443f382f261d140a00000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342719222b32373b3c424242424242424242423b3a37312a21180e0300000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000000000000c17232e38424c565e696e7a838f949fa3abb2bab6afa8a09a938d847c726c655d564d453b33291f160c0000000000000d192633404c5966737f8c99a6b2bfbeb4aaa29f9e9e9e9e9e9e9e9e9e9e9e9fa3abb5c0baada194877a6e6154473b2e21140800000008111a222a32373a41464a5053585f62686d72787d82888e92989ea0a8abb0a5988b7f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033261a1b1f2223232323232323232323201f1c18120b030000000006121f2b37434e58616e7a85929fa8b2ada1968c7f73685e575757575e6b7884919eabb7bdb0a3968a7d7063575756544f473d33271c100400000006111b262f383f44464a4c4950535557595b5d54524c443a3025333f4c5966727f8c99a5b2bfbfb4aa94877a6e6154473b2e2114080006121f2b3844505c667683909dabb5c0bdb2a89f949085807e7d7e82879298a2aebac5cebaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d100000000000000004080a0a0b0b0f171f282f353f474f575e676d747e879197a0a7b1b9bfb6aea49f92867c6f665c50433a2f241804000000121e2b3845515e6b7884919eabb7c2b6a99c8f83766b6b6b6b686e70757c839095a0abb5c0baaea3998b7e7164584b3e2f23180c0000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000c1926333f4c5966727f8c99abb5c0b3a6998c8073717e8b97aab4bfb5a89c8f827569574d42362a1e120500000000000000000814212d3945505a616465656565656565656565625b51463a2e221509000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c12181f272f35393b4146474a4c4e4f4f4f4e4d4b4846423b39352f27221b140b0400000000000000000000000000000000000000000000000000000000030c18222b353d474f565e616a6f75797d7f818383838382807e7b77716d676159504941382f261b1106000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b1920272b2e2f353535353535353535352f2e2b2620180f060000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000003101c28343f4a545d686e7b8490959ea6afb5bab2aca49f96918880796f6a605b534c433b332921170d040000000000000d192633404c5966737f8c99a6b2bfbaaea2989291919191919191919191919299a3afbbbaada194877a6e6154473b2e2114080000000008101820262b3036383f44464e53565d61666d70767c81868c91969c9fa6a5988b7f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40332621272c2e2f3030303030303030302d2c28231d150c03000000030f1b26313c46525e68737f8c96a1acb2a89f92867a6e61584e4a515e6b7884919eabb7bdb0a3968a7d7063574a4948443d352b21160b000000000b17222d38414950535759535b606163656869615e564c41362d36424d576774818e9aa7b4c1baaea398877a6d6054473a2d211407000713202d3a4653606d7985929facb8c5b9aca19690827a74717072757d86929fa9b3bec9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000000000000000000000710192129313a4045515960696e79818b9299a1a9b1b9bfbbaea49d928b7f726a5f544a3f31281d1307000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695f5f565e61646a6f79839099a4afbbbfb4ab9b8e817468554b4034291c100400131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000005121e2a36424d576875828f9ba8b5beb3a9978a7d706e7b8898a2aebab8ab9e928578695f53463a2d211407000000000000000005111d28333e48505557595959595959595959585651493f34291e12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d161d242931394045474c525457595b5c5c5c5b595754534d4745413a332d261d160e050000000000000000000000000000000000000000000000000000000b151e2a343d474f5960686e757c8185898c8e8f9090908f8d8b87837e79706b605b534941382d22170b020000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0f151b1f22222929292929292929292922211f1a150e06000000000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f3225190c00000000000000000000000000020d17212c3844505c666d7a849196a0a7b0bbb7afa8a19a938d847d746d6760585049413a312921170f0a040000000000000d192633404c5966737f8c99a6b2bfb8ab9f9286848585858585858585858487929facb9baada194877a6e6154473b2e2114080000000000060e151b1e252a2e34383c43474c52545c60646a6f747a7f848a8f949a9f988b7f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033262b32383b3c3d3d3d3d3d3d3d3d3d3a38342e271e150b000000000a15202a36414c56606d7984919ea7b1aea2988d81746a5f5347515e6b7884919eabb7bdb0a3968a7d7063574a3d3b38332b23190f05000000030f1b27333f49535b60646668656c6e707274766d685e52463d393c46525e697783909daab6c3b8ac9f928579675d5145392c201306000915222f3c4855626f7b8898a2aebabfb4ab9e9184796d686464656b727f8b97a1adb9c6baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000000000000000000081119222a333b434b515b636b707b838e939fa3abb3bbbdb5aea49c928d80736d62584e42382e1f160c01000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c524c5254585f676e7b87939facb9c3b7aa9d908477675c5145382c1f130600131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000714212d3a46535f697885919eabb8b9ada197877b6e6c7985929facb8b9ada197887b6e6155483b2e2215070000000000000000000c17222c363e45494a4c4c4c4c4c4c4c4c4c4c4a463f372d23180d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d161f282f353e434b5153565e61646667686968686664615e5754524c443f382f2820170e050000000000000000000000000000000000000000000000000007121c27303c464f59606b6f7a81888e9298999b9c9d9d9c9b9a9795908b847d736c655b53493f33271d140a0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e0a0f1315161c1c1c1c1c1c1c1c1c1c1514120f090300000000000e1b2734414e5a6774818d9aa7b4bfb2a5998c7f7266594c3f3326190c0000000000000000000000000009141f2a36424d57606d78828f96a0a8b1b9b6ada59e9691888079706b605d554e443f382f2823221f1b150f0700000000000d192633404c5966737f8c99a6b2bfb3a6998c80787878787878787878787884919eabb8baada194877a6e6154473b2e211408000000000000040a0f13191c23282b31373a41464a5053585f62686d72787d82888d92988b7f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40332b343d4348494949494949494949494645403930271d1207000000040d1925303b45515c67717e8a959fabb4aa9f92877c6e62594f515e6b7884919eabb7bdb0a3968a7d7063574a3d302c27211911070000000005121f2b3744505b656c70727577797b7d7f81837a6d61594f4746474d57616e7b87939facb9c4b7aa9d9184776a554c4135291d1104000a1724313d4a5764707d8a97aab4bfbaaea3998b7e71675e565759606d7985929eabb8c5baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000000000000000008111a232b343c454d555d606d727d8590959da5aeb4bdbbb3aba39f928c80776c605b51463c30261c0d0400000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504146474e555f6a75828e9ba8b5c1b9ac9f9286796d6053473a2d20140700131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000815222e3b4855616e7b8897a1adb9b8ab9e91857869667683909ca9b6beb3a9978a7e7164574b3e2f23180c00000000000000000005101a242c33393d3e3f3f3f3f3f3f3f3f3f3f3e3a342d251b110600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c161f283139404550555d6065686e7073747575757473716e6965605d565049413a322920170d030000000000000000000000000000000000000000000000000c18232e39424e58606b707d858e939b9fa2aaa7a9a9aaa9a8a7a79f9d96918a80776c655b50443d2f261c110600000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e00030608090f0f0f0f0f0f0f0f0f0f08080602000000000000000e1b2734414e5a6774818d9aa7b4bfb3a6998c807366594d4033261a09040000000000000000000000020e1a25303a46535f69737f8c949fa8b2bab5ada49c938e847d746d676059514b433d332d30302f2e2b2720191007000000000d192633404c5966737f8c99a6b2bfb3a6998c80736b6b6b6b6b6b6b6b6b7885919eabb8baada194877a6e6154473b2e211408000000000000000002080d11171c1f262b3035383f44464e53565d60666c70767b81868c8b7f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033323d464e545656565656565656565653514b42392e23180c0000000008141e2934404b55606c7883909da5afafa3998f82756b60544a5e6b7884919eabb7bdb0a3968a7d7063574a3d30241c160f0700000000000613202d394653606c777e7f818385888a8c8e8d80746b6059545354575f6973808c9aa4afbbc2b5a89c8f8275695c4f422f24190d01000b1825313e4b5864717e8b97a4b1beb9ac9f92867a6d60554c4a515c6674818d9aa7b4c0baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000000000000000007101a232c353d464e575e676d757f8792979fa7afbabfb9b1a9a199928b80746c655b50493f342a1e150a0000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043393c434e5764717e8b97a4b1bebbafa399887c6f6255493c2f22160900131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000b1824313e4b5764717e8a97a9b3beb5a89c8f8275696774808d9aa7b3c0b3a79a8d807467554b4034291c100400000000000000000008121a22282d303132323232323232323232312e29231b130900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141e28313a434b515a62676d72767a7d7f8182828281807e7b77726d68605b534c443b32291f150b010000000000000000000000000000000000000000000004101c2834404a545f6a707d8691979ea5acaeb4b4b6b6b6b6b5b3b1aba8a09e928d81776c60594f42382d22170b00000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e01000000000202020202020202020200000000000000000000000e1b2734414e5a6774818d9aa7b4c0b4a79a8d8174675a4e4131261a13100c0700050000000000000005121e2a36424d57616e7b86929fa6b0bab7ada39c928c817a706b605d554f45403d3d3d3d3d3d3c3b37322b22190f040000000d192633404c5966737f8c99a6b2bfb3a6998c8073665e5e5e5e5e5e5e6b7885919eabb8baada194877a6e6154473b2e2114080000000000000000000000060b10151b1e24292e34383c43474c52545b60646a6e747a7f847f7265584c3f3225190c000d192633404c5966737f8c99a6b2bfb3a6998c807366594d403338434e586062636363636363636363605c544b4034281c1004000000020c18232f3944505b656f7c89939eaab4ab9e94897d70665b505e6b7884919eabb7bdb0a3968a7d7063574a3d3024170b0500000000000005121f2b3744505b6578858c8e90929896989b93877d706b6360606163696e7b86929facb6c0beb3a9998c7f7366594c403326190800000c1825323f4b5865727e8b98a5b1beb6aa9d908377675d5143404a5464717e8b97a4b1bebaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000000000000050f19222c353d474f585f696e79818c9399a1a9b1b9beb9aea79f9792877e736e605b53493f372d22180c030000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336313c4855616e7b8894aab4bfc0b5ab96897d7063564a3d3023170a00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000004101c2934404b556774808d9aa7b3bfb3a6998c80736664717e8a97aab3beb6aa9d908377675c5145382c1f1306000000000000000000000810171d2123242626262626262626262524221e181109010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c26303a434c555d606c71797e83878a8c8e8f8f8f8e8c8a87837f7a726c655d564c443b31271d12070000000000000000000000000000000000000000000006121f2c3844515c666f7c869298a1a9afb8bab9b7b3b0b0b1b5b9bbb8b2aca49c938c80736b60544a3f33281c0f03000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e01000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b6a99c8f837669584e43372b201f1c181216110b0300000000000714202d3a46525e6975828e98a3aeb8bbafa59c918c7f756d686059514b4a4a4a4a4a4a4a4a4a4947433d342b20150a0000000d192633404c5966737f8c99a6b2bfb3a6998c8073665952525252525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000000000000000000030a0f13191c23282b31373a41454a5053585f62686d72797a6d6154473a2e211407000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333b4854606a6f7070707070707070706d665c5145382c1f13060000000007121d27333f4953606b75818e98a3aeb0a69d9083786c60555e6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000030f1b27333f49536a7683909b9d9fa2aaa5a49992857d75706d6c6d6f747b849198a2aebec7baada297897d706356493d3023160a00000c1926333f4c5966727f8c99a5b2bfb5a89b8e827568554b403c4955626f7c8895abb5c0baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000000000000030c17212b343d474f59606a6f7b838e939fa4abb3bbbbb3ada49d9590857d716c635c504941382d251b1006000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4753606d7a8698a3aebabdb0a4978a7e7164574a3e3124170b00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000006131f2c3845515c677683909da9b6beb3a9978a7d7064626e7b8898a2aebab9ac9f9286796d6053473a2d2014070000000000000000000000050c11141717191919191919191919191815120d060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17232e38424c555d676d757e858b90939a999a9b9c9b9b999795908c857f776d685e564c43392f24180c04000000000000000000000000000000000000000004101c2934404b55606d78839098a2aab3bbbab2acaba6a4a3a5a8acafb6beb9aea59f93887d6f665b5044382b1f1409000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e00020507080c0c0c0c0c0c0c0c0c0c08070502000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9e9185786a5f5347392f2d2c28231d221c150d05000000000815212e3b4854616e7b86929faab4beb3a99e938c7f736d605d564f515356565656565656565656544e463d32271b0f0300000d192633404c5966737f8c99a6b2bfb3a6998c807366594d454545525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000000000000000000000002080d11171c1f262b3035383f44464e53565d60666c6d685d5246392d201307000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333c4956626f7c7c7c7c7c7c7c7c7c7d796d6053463a2d20130700000000010b17222d38414f59616e7b86929fa9b3aca0958b7e71675d5e6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000b17222d424e5b6875818e9ba8acaeb4b5aba2979287817d7a797a7c80869196a1aab4bfc0b6ac9f9285796d6053463a2d20130700000d192633404c5966737f8c99a6b2bfb4a79b8e8174685b4e413a4754616d7a8799a3afbbbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d100000000000000a151e29333d464f59616b707c8590959ea5afb5bdb9b1a9a29e928d837b6f6b625a52443f382f261b120900000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3845515c677985929facb8beb1a4988b7e7165584b3e3225180b00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000714202d3a4753606d7986929facb9b9ada197877b6e61606c7985929fabb8bbaea399897c6f6356493c302316090000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c0b09060100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a545d676d79818b91979d9fa4aca7a8a8a8a7a6a7a09d97928b827a6e685e554b40352921160a000000000000000000000000000000000000000006131f2c3845515c67727f8c95a0aab3bcb6aea8a19e999797989c9fa4acb2bbbbafa49a9183786c6053463b30251a0e020000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e090e121415191919191919191919191414110e090200000000000e1b2734414e5a6774818d9aa7b4c0b9ada196887b6e62554b413b3a38342e332d271f170d030000000c1825323f4b5865727e8b99a3afbcb9ada2978e81756d635b524c545c606363636363636363636260584e43372b1f130600000c1926333f4c5966727f8c99a5b2bfb3a6998c807366594d403845525e6b7885919eabb8baada094877a6d6154473a2e211407000000000000000000000000000000000000060b10151b1e24292d33383c43474c52545b60615d564c4135291d1105000d192633404c5966737f8c99a6b2bfb3a6998c807366594d403845525e6b78848989898989898989877a6d6154473a2e211407000000000006111b262f3d46535e6973808d97a1adb1a79e9184796d60566b7884919eabb7bdb0a3968a7d7063574a3d3024170a000000000000000006192633404c5966737f8c99a6b2babfbdb3a9a299938e89878687898d9298a1a8b2bcc6bbafa49a8e8174665c5144382c1f120600000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e41394653606c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b404b556c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000000000006111c26303b454f59616b707d869197a0a7afbbbfbaaea79f97928a80786e696059504840332d261d140a0000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362934404b556c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000091623303c4956636f7c8999a3aebbb8ab9e928578695e5b6576838f9ca9b6bfb5ab988c7f7265594c3f30251a0e020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c16202b3844505c666d79838e939ea1a9acafb6b4b5b5b5b4b3b1aca9a29e948f837a6e675d51453d32271b0f04000000000000000000000000000000000000000714202d3a4753606d7985929ea7b1bcb6aea49c96918d8a8a8b8f939aa1a9b2bcb6aca0958a7e7164574d42362a1e12050000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0d141a1e21222525252525252525252521201e19140d05000000000e1b2734414e5a6774818d9aa7b4c0bdb2a9998c7f72675d514c47464540393e3931291f150b0000020e1b2835414e5b6874818e9babb5c0b8ab9e92857a6d605b5245515c666d7070707070707070706f6a6054473b2e22150800000c1926323f4c5965727f8c98a5b2bfb3a6998c807366594d4036414c566b7885929eabb8bbafa499877a6d6054473a2d2114070000000000000000000000000000000000000000030a0f13191c22282b31373a41454a505354524c443a3024190d01000c1926323f4c5965727f8c98a5b2bfb3a6998c807366594d4035414c566b7885919696969696969a877a6d6054473a2d2114070000000000000a141d2a36424d57606d7a85929ea7b1ada1968c7f73685e6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000b1724313e4a5764717d8a97acb6c0cac5bbb3aba49f9b96939394969a9fa3aab2bac4bcb3a99f93877c6f62544a4034281c100400000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413744505b657885929fabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b45515d677986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb5a99c8f8276695c4f4336291c1000000000000c17232e38424d57606b707d869298a1a9b1b9bcb4aea49d9590857d736d665e574f473f3627221b140b020000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336232f45525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000c1926323f4c5965727f8c98abb5bfb5a89c8f82756957536773808d9aa6b3c0b5a89b8e827568574d42362a1e1205000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e2a36424d57606d78828f959ea5adb3b9bab9b4b1b0b1b4b8bab8b3ada69f959083796d60594f43382c20150a00000000000000000000000000000000000003101c28343f4a5464717e8a97a1adb9bbaea49c928c84807d7d7e82879196a1aab4beb1a79c908376695e52463a2d2014070000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b171f262a2d2e323232323232323232322e2d2a251f170e050000000e1b2734414e5a6774818d9aa7b4c0c4b8ab9e9184796d605d555453514b4f4a433b31271c11050003101d2a3643505d697683909ca9b6c0b3a79a8d8074685d52494653606d787d7d7d7d7d7d7d7d7d7c6f6256493c2f23160900000b1825323e4b5865717e8b98a4b1beb3a6998c807366594d403946525e687985929facb8b9ac9f9386796d6053463a2d2013070000000000000000000000000000000000000000000002080d11171c1f262b2f35383f44464746413a32281e130800000c1825323f4b5865727e8b98a5b1beb3a69a8d807367544b403845525d687885929fa3a3a3a39f9386796d6053463a2d201307000000000000020b1a25313b45515d67727e8b95a0acb2a99f92867a6e616b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000915222f3c4855626f7b889aa4afbbc8c4bab2acaaaca8a3a09fa0a2a7acaeb4bcc2bbb3aaa1978e81756a5f5342392e23180c0000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e41333f495f6b7885929eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4bfb2a5998c7f7266554c4753606d7a8699a3aebbbbaea295887b6f6255484b5565727e8b98a5b1beb5a89b8e8275685b4f4235281c0f0000000003101c28343f4a545e696f7d869298a2aab2bbbab2aaa29f928d837b706c605c544d453d352d2417110a02000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000005111e2a36424d576875828e9ba8b5bfb3a6998c807366595764717e8a97a9b3beb8ab9e918478695e52463a2d20140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1925303a46535f69737f8c949fa7afb9bcb4aeaca8a4a3a4a7acaeb4bcb9b0a79f958e81746b6054483c31261b0f03000000000000000000000000000000000006121f2c3844505c6675828f9ca9b3beb3a99d928c807973717072757c849198a2aebab7ab9f94877b6e6154483b2e2115080000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342717212931363a3b3f3f3f3f3f3f3f3f3f3f3b3a36302920170d0200000e1b2734414e5a6774818d9aa7b4c0c6b9ada1978d80746d676361605c545b554d43392d22160a0004111e2a3744515d6a7784909daab7beb1a4978b7e7164564c414854616e7b8789898989898989898276695c4f4336291c1003000a1724303d4a5763707d8a96aab4beb3a79a8d807467564c413d4754616e7a8798a3aebab8ab9e918578665c5044382b1f120600000000000000000000000000000000000000000000000000060b0f151a1e24292d3338393a3935302820160c0200000a1724303d4a5763707d8a96aab4beb5a89b8e8275665c5147464a54606d7a86939facafafab9e918578665c5044382c1f12060000000000000009141f2935414c55606d7883919da6b0aea2988e81746a6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000714202d3a4753606d7a86939facb9c6bdb2a8a09ea0a8afadacadafb3b9babfbab8b0a9a29891857a6d61584e4330271c12070000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e412d45525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0b4a79b8e8174675d545359626f7c8995abb5bfbdb1a4978a7e71645b53535c6774818d9aa7b4c0b4a79a8e8174675b4e4134281b0e000000020d17202c3844505c666e7b859298a2aab4bcb9b1a8a198928a80786e696159514a423b332b231b12060706040000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000714202d3a46525e697884919eabb8beb3a9978a7d70645755616e7b8897a2adbab9ada196877b6e6154483b2e2115070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d2935414c56616e7b86929fa6b0b9b8b0aaa39f9b9896979a9fa2aab0b8b9b1a79d92897c6f63584e43372b1f120600000000000000000000000000000000000713202d3a4653606d7985929facb8b9ada2978d80736d666464656b6f7c86929facb8bcb0a6988b7e7165584b3e3225180b0000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271f29333b4246484c4c4c4c4c4c4c4c4c4c4746423b32291f140900000e1b2734414e5a6774818d9aa7b4c0c9beb2a99d928d807a73706e6d666a665f554a3e33261a0e0004101d2a3743505d6a7683909da9b6bdb0a4978a7d7164564d4c4e5763707c89969696969696968e8275685b4f4235281c0f02000815222f3b4855626e7b8898a2aebab5a99c8f8276685e524b4a4e5863707d8a96aab4bfb6a99c90837669544a3f34281c1003000000000000000000000000000000000000000000000000000000030a0f13191c22282b2d2e2d29241e160e040000000815222f3b4855626e7b8898a2aebab8ab9e9285796d60595352545c66717d8a9aa4afbbb6a99c90837669544a3f34281c100300000000000000030d19242f3a44505c66707d8a949fabb4aa9f92877c6f6b7884919eabb7bdb0a3968a7d7063574a3d3024170a000000000000000006131f2c3845515d677884919eabb7c4b9aca09691969ea5acaeb4b3b4b4b3b4aeaca69f9792867d6f685e52463c311e150b000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0b8ab9f92857a6d666060616b74818d9aa7b4c0c2b5a99c8f82766d626060656d7985919eabb8c0b3a69a8d8073675a4d4034271a0d00000008131e2a36424d57606d78839097a1aab4bcb9b1a79f9691867e746d665e574f444039302920191818181313100c07000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000814212e3b4754616e7b8796a1adb9b9ada197877b6e615453606c7985929fabb8bdb2a8978a7d7164574a3e2e23180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3946525e6874818e99a3aeb8b9b0a69f98928e8b8a8b8e92989fa6b0b8b9afa59c8f83766a5f53473a2e21150700000000000000000000000000000000000915222f3c4855626f7b8898a2aebab8ab9e9285796d605c545759606a73808d9aa6b3c0b4a79a8e8174675b4e4134281b060000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342726313b454d53555858585858585858585854524d443b3025190e02000e1b2734414e5a6774818d9aa7b4c0cfc4bbaea49d928d85807d7a79797771665b4f4236291d1000030f1c2936424f5c6975828f9ca8b5bfb3a6998c8073685e5659585f6973808d99a3a3a3a3a39a8d8074675a4d4134271a0e01000613202d394653606c7985929fabb8b8ac9f92867a6d615c5456575f6a74818e9ba7b4bfb4ab9a8d8174675a4e412e23170b00000000000000000000000000000000000000000000000000000000000001080d11171c1f2021201d19130c04000000000613202d394653606c7985929fabb8b9ada1978b7f726b63605e61666d7883909dacb6beb3a99a8d8073675a4d402e23170c00000000000000000008131e28343f4a54616b76828f99a3afafa3998f82766b7884919eabb7bdb0a3968a7d7063574a3d3024170a000000000000000004101d2935404b556976828f9ca9b5c2b7aa9e91848e939b9fa2aaa7a8a7a6aaa39f9b948f857d706b60564c41342a200c03000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0baada2978e8178706d6c6e737d87929facb9c5c3b7aa9e948b7f756f6d6d6f77808d97a1adb9c0b5ab988b7e7265584b3f3225180c0000010d1925303a46525e69727f8c959fa9b3bcbab1a79f9590847c716c605c544d453e342e27252525252525201f1c18120b0300000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000b1724313e4a5764717d8a97a8b2bdb8ab9e928578695e52505b6576838f9ca9b6c0b3a69a8d807367544a4034281c10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212e3a4754616d7a86929fabb4bcb1a79f948f86817e7d7e81868f949fa6b0beb7ab9f94887c6f6255483c2f23180c00000000000000000000000000000000000b1824313e4b5764717e8a97aab4bfb4a89b8e8175675d514a4a4f58636f7c8996abb5c0b6a99d9083766a5d50432d22170b0000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272a36424d575f6165656565656565656565615e564d42362a1e1105000e1b2734414e5a6774818d9aa7b4c0c5bebab8aea49d97928d8987868583776a5d5044372a1d1100010e1b2834414e5b6774818e9aacb6c0b8ab9e91847a6e696666676a6f7b85929fabb0b0b2a8988b7e7265584b3f3225180c000006121f2b3844505b6675828f9caab4baaea3988e81746d66646364696e7c87929facb9baaea3998a7d7164574a3e31241706000000000000000000000000000000000000000000000000000000000000000000060b0f12131413110d0802000000000006121f2b3844505b6675828f9ba9b3beb3a99f92867d746f6d686d7178818e959fabbebaada2978a7d7063574a3d30241706000000000000000000010b17232e38424f59626f7c87929faab3ab9e94897d707884919eabb7bdb0a3968a7d7063574a3d3024170a0000000000000000000c18242f414d5a6774808d9aa7b3bdb0a4978a7e81898e9298999a9b9a9a9898928f89827b706b60594f443a3022180e00000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0beb3a99e938e837d7a797b80879299a3afbbc6bfbbb0a69b918b817c79797c828d929da9b3bebbafa499897c6f6256493c2f231609000005111e2a36414c56616e7b86929fa7b1bbbdb2a89f9590837a6f6a615a514a423b333131313131313131312d2c28231d150c03000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000004101c2834404a546773808d9aa6b3c0b5a99c8f827669574d49536773808d9aa6b3c0b6a99c908376665c5144382c1f12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e8b98a3aebdb8ab9f958f827b75717071747a828f949facb6bbb0a6998d807366554b4034291c1004000000000000000000000000000000000c1926323f4c5965727f8c98a5b2bfb2a5998c7f7266554b403d4754606d7a8799a4afbbb7ab9e9184786b5e493f33271b0f0300000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272d3a46535f696e727272727272727272726e695e52463a2d201407000e1b2734414e5a6774818d9aa7b4c0bcb4aeabacafa9a19e9a9694989184776a5e5144372b1e1100000b1825313e4b5864717e8b9aa4afbbb9ada19790827b75737273767c849197a2adbab9ada196887c6f6255493c2f2216090000030f1c28333f4a5465717e8b98a2aebab4aa9d938d807973707071747b849199a3aebbb9ac9f92867a6d6154473a2e21140700000000000000000000000000000000000000000000000000000000000000000000000306060707050100000000000000030f1c28333f4a5464717e8b97a2adbabaaea3989288817c7a797a7e838e939da7b1bcb4aa9f9285796d6053473a2d2014070000000000000000000006111c26303e47535f6a74818e98a2aeb0a69d9083787884919eabb7bdb0a3968a7d7063574a3d3024170a000000000000000000071925323f4c5865727f8b98a5b2beb2a5988c7f747c8285898c8d8e8e8d8b8986827d766e6960594f473d32291e100600000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0c5bcafa59e9490898686888d9299a3abb5c0bdb5aeaca9a39b938e888686898f949da4aebbc4b9ac9f9386796d6053473a2d20140700000713202d3946525e6874818e98a2aeb9c0b5aba1969083796d685f58504440393b3e3e3e3e3e3e3e3e3e3e3a38342e271e150b000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000006121f2c3844515c667683909ca9b6bfb3a6998c807366594d4a5764717e8a97a9b3beb8ac9f9286796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b556875828e9baab4beb3a99d9083796e69656364686e78828f9aa4afbbb6aa9d908377675c5145382c1f1306000000000000000000000000000000000d1a2733404d5a6673808d99a6b3beb1a5988b7e7265584b3f3945525d687986939facb9b8ac9f928579655b5044372b1f120500000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272e3b4855616e7b7f7f7f7f7f7f7f7f7f7f7b6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb4aaa29f9fa4abadaba6a3aa9d9184776a5e5144372b1e1100000814212e3b4754616e7a87939facb9beb2a99f949086827f7f8083889196a0a9b3beb4aa9e9184786c605346392d2013060000000b17222d3a4753606d7a85929fa8b2bcafa59d928d84807d7d7e81869196a0abb5bbafa59b8e8275685d5246392d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d3a4753606d7985929fa8b2bdb4aaa39a938e898686878a90959da5afb9baaea2988d8073675c5145382c1f130600000000000000000000000a141e2b37434e58616d7a85929fa8b2aca0958b7e7884919eabb7bdb0a3968a7d7063574a3d3024170a0000000000000000000a1723303d4a5663707d8996aab4bfb4a79a8e81746f75797d7f808181807f7c7975706b615f574f473d352b20170d0000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0bbb3adaba69f9c96999399999fa3abb5bdbfb5aba39f9c9fa59e9b999399969c9ea6aeb6c0bdb2a89c8f8276675d5145392c20130600000714212e3a4754616d7a86929faab4bfbbafa39991847a6e675e564e463e4246474b4b4b4b4b4b4b4b4b4b4645403930271d12070000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362834404b546c7885929fabb8beb2a5988b7f7265584c3f3225190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000713202d3a4653606d7986929facb8beb3a9978a7d7064574a4855616e7b8897a2adbabaaea398897c6f6256493c2f231608000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c677784919eaab7b9ada297897c6f675e5757565e666e7b87939facb9b9ac9f9286796d6053473a2d201407000000000000000000000000000000000e1a2734414d5a6774808d9aa7b3beb1a5988b7e7265584b3f35414c566c7986929facb9b9ac9f9386796c605346392d20130600000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a8b8b8b8b8b8b8b8b897d6f6356493c30231609000e1b2734414e5a6774818d9aa7b4baaea298929399a4afb8b3b0aa9d9184776a5e5144372b1e1100000714202d3946525e6876828f9ca5afb9bbb0a69f98928e8c8c8d90949da0a8b2bbbaaea2988c8073655b5044372b1f12050000000613202c3945515d6773808d96a1abb5b7aea49d96918d8a898b8e9298a0a8b2bcb3a99e93897c6f62564c4135291d1105000000000000000001040607060603000000000000000000000000000000000000000000000000000000000000000000000006131f2c3945515d67737f8c96a0abb4bcb4aca49f9b96999399979da0a7afb7b9b0a69f92867b6e61554b4034291c10040000000000000000000000020c1a26313c46525e68727f8c96a1acb1a79e91847a84919eabb7bdb0a3968a7d7063574a3d3024170a0000000000000000000815212e3b4854616e7b8798a2aebab6a99c90837669676d707274757473726f6d67636059534d453d352b23190e050000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb3a9a19e9fa2a9aba49fa4abacaeb5bdc1bbaea3999290949fa9aba49fa4aba9aab0b8c0c0b9ada1968a7e7164554b4035291d110400000b1825323e4b5865717e8b99a3aebcc0b5ab9f92877c6f685e554c443c444d52545858585858585858585853514b42392e23180c0000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3845515c667985929facb8beb1a5988b7e7265584b3f3225180c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000916232f3c4956626f7c8998a3aebab9ada197877b6e61544846535f697885929fabb8bfb4aa988b7f7265584c3f3025190d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7986939facb9b8ab9e9285796c60554d4a4c545f697783909daab7bbafa399887b6f6255483c2f221509000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f2f46535f6c7986929facb9bbafa49a86796d6053463a2d20130700000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a9698989898989896897c6f6356493c30231609000e1b2734414e5a6774818d9aa7b4b8ab9f928687939fa9b1bab7aa9d9184776a5e5144372b1e11000005111e2a36414c56626f7c89939ea7b1b9b8b0aaa39f9b99999a9c9fa6acb2babaafa59f92857a6e6153493f33271b0f0300000004111d2935404b55606d7a849199a4afb5b6aea8a19e999796979b9fa3aab2bab3aaa1978e81756a6054443a3024190d0100000000000001070d11131413120f0b0600000000000000000000000000000000000000000000000000000000000000000004101d2935404b55606d79849199a3abb4bcb6afaca7aba49fa4abaaabb1b9bbb1a79f948c7f72685e5243392f23180c000000000000000000000000000a15202a36414c56606d7984919ea7b1ada1978c7f84919eabb7bdb0a3968a7d7063574a3d3024170a0000000000000000000613202d394653606c7985929facb8b8ab9e928578685d606366676867676563605d55544f46423b332b23191107000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4b9ada197929297a2adafacafb5b9bbbfbeb9b0a69f9287839097a1a9afacafb5b5b7bbc2bdb9afa59e9184796d6053473a2f24180d0100030f1c28333f4a546875828e9babb4bfbbafa3998d80736a60564c433a424d565e6164646464646464646464605c544b4034281c100400121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798698a2aebabeb1a4978b7e7164584b3e3125180b00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000c1925323f4c5865727f8b98aab4bfb8ab9e928578695e5346424d576976828f9ca9b6c1b4a89b8e817568564c41362a1e1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b889aa4afbbb6aa9d908377665b50433d424d576875828f9ba8b5c0b5ab96897d7063564a3d3023170a000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9c0b6a09386796d6053463a2d20130700000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3a5a5a5a5a296897c6f6356493c30231609000e1b2734414e5a6774818d9aa7b2b2aa9e9184828f96a0a7aeb4aa9d9184776a5e5144372b1e110000010d1925303b4754606a75818e95a0a7afb7bcb4aeaca8a6a5a6a9abb0b8b9b3aea59e938b7f72685e5241382d22170b00000000010d18242f3a45525d68707d87939fa3abb2b9b2adaba6a3a3a4a7acaeb4b8b1aaa29892857a6e61584e4332281e1308000000000000040c13181d2020201f1c17110d0701000000000000000000000000000000000000000000000000000000000000000c18242f3945515d676f7d879299a3aab1b8bbb9b4b5afacafb5b6b8bab5afa79f958f82786d60564d4131271d120700000000000000000000000000030d1925303a45515c67717e8a959fabb2a99f928585929fabb8bdb0a3968a7d7063574a3d3024170a00000000000000000005121f2b3744505b657784909daab7b9ada197877a6d605456595a5b5b5a585653514b48443d3631292119110700000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b2b2ab9e928585929fa4abb1b7b9bab8b7b3ada69e948d807a859197a0a8aeb4b7b9b9b8b7b2ada59d938a7d70675d5145392c1d1307000006121f2b3844505b667885919eabb8c4b9ac9f92867b6e61584e443b3a46525e696e717171717171717171716d665c5145382c1f130600121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362e3b4855616e7b8894aab4bfbdb0a3978a7d7064574a3d3124170a00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000005111e2a36414c566875818e9ba8b4c1b5a99c8f827669574d42404d5a6673808d99a6b3c0b7aa9e918477685e5246392d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3c4855626f7b8895acb6c0b6a99c90837669544a3f31414e5b6874818e9ba7b4bdb0a4978a7d7164574a3e3124170b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413025313d4a5764707d8a97a3b0b2b2afa295887c6f6255493c2f221609000e1b2734414e5a6774818d9aa6a6a6a69e91847b8491959fa2aaaa9d9184776a5e5144372b1e1100000008141e2b37434e58606d798390959ea5abb0b5b8b8b5b2b2b3b6b8b6b3adaaa29f938e81756d62564c412f261b1106000000000007131d2935414c56606b727f8b9299a1a8adb2b6b7b3b0b0b1b4b8b5b1aca79f9892867d6f685e52463d3220160c020000000000040d161d24292c2d2d2b28221c18130e0903000000000000000000000000000000000000000000000000000000000007121d2935404b55606b717e879298a0a7acb1b5b7b8b9b9b9b8b6b4aeaba39f9590837a6d665c50443b301f150b01000000000000000000000000000008131e2834404b55616c7683909da5afaea298929297a2adbabdb0a3968a7d7063574a3d3024170a000000000000000000030f1b27333f49536875828e9ba8b5beb3a995897c6f62564a4c4d4e4e4d4c494745403938322a2625221e18110a010000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa6a6a6a69e91847e8a9399a0a7aaacaeacaaa9a19e948f82786f7c8591969fa2aaabacadabaaa8a19e938e81746c61554b4035291d0c0100000613202d394653606c7986929facb9c2b5a89c8f8275685e52463d323b4754616e7b7e7e7e7e7e7e7e7e7e7e796d6053463a2d20130700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433639414c5664717e8a97a4b0bdbdb2a895897c6f6256493c2f23160900121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413025313d4a5764707d8a97a3b0bdbbafa295887c6f6255493c2f221609000000000713202d3946525e687784919eaab7c0b3a6998d8073665a4d403e4a5764717d8a97a9b3beb9aca096877a6e6154473b2e211406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d50432d414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000121e2b3845515e6b7884919eabb7c2b5a89b8f827568564d41362c303e4b5864717e8b97a4b1bebdb2a894887b6e6155483b2e221508000e1b2734414e5a6774818d9999999999999184777b838c92989b9d9d9184776a5e5144372b1e11000000020f1b27323d45515d676e7b838e939c9fa6a8abadb3aeaeb4aeaca9a9a19e98928b81786d605b51443b301d140a000000000000010d19242f3a434f59626d727f8791969ea1a9a9abadb3b6afacaba9a7a09d9590867d706b60564c41342b200e040000000000010c161f282f35393a3938332d29241d1a14100b04000000000000000000000000000000000000000000000000000000010d18242f39434f59616c717e8690959da0a7a8aaabacafacaba9aba39f99928d837a6d685d544a3f32291f0d03000000000000000000000000000000020c18232e3943505a626f7c89939eaab4aaa29f9fa2a9b3bebdb0a3968a7d7063574a3d3024170a000000000000000000000b17222d404d596673808c99a6b3beb1a4978b7e7164584b3f414241403f3c3a38352f36363632312e2a231c130a0000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9999999999999184777f8790959b9d9fa39f9d9b97918b82796d6a6f7c848d92989b9e9fa29e9d9b96918a81776c605a5043392f24180c0000000714212e3a4754616d7a8799a3afbbc0b3a6998d807366564d4134313d4a5764707d8a8b8b8b8b8b8b8b8b867a6d6053473a2d20140700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504341464b525e6874818e9ba7b4c1b9aca196877a6d6154473a2e21140700121e2b3845515e6b7884919eabb7c2b5a89b8f827568564d41362c303e4b5864717e8b97a4b1bebdb2a894887b6e6155483b2e221508000000000714212e3a4754616d7a8796a0acb9beb3a9978a7d7064574a3d3b4855616e7b8897a1adb9bdb2a8978a7d7064574a3d2e23170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000111d2a3744505d6a7783909daab6c3b7aa9d908477685e52463c393a424d576673808c99a6b3bfb9ada196877a6d6054473a2d211407000e1b2734414e5a6774818c8c8c8c8c8c8c8c84776e7980858b8e90929184776a5e5144372b1e11000000000a16202935404b555e696e79818a8f94999c9fa2a9a2a1aaa29f9c9a97928d857e756d665c51493f32291e0b020000000000000008131e28313d47515b626d727d848c91969a9d9ea2a9a1a49f9e9c9995908b837b706b60594f443b3022190f00000000000007131d28313a40454746443f38352f2a261f1c16100c07010000000000000000000000000000000000000000000000000007121d28313d46505a616c717c838b9095999b9d9f9fa39f9e9d9a99928e8780786d685e564c42382e20170d000000000000000000000000000000000007121d27303e4754606a75818e98a3aeb4aeacabadb3bbc5bdb0a3968a7d7063574a3d3024170a00000000000000000000061824313e4b5764717e8a97a4b1bdb3a6998d8073665a4d43434343434343434343434343433f3e3a352d251c110700000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818c8c8c8c8c8c8c8c8477727d838a8e91929892918e8a857e776d675f6a6e7980868b8f91929792918e8a847e746c655b50483e31271d12070000000814212e3b4754616e7a8794aab4bfbeb2a5988b7f7265584c3f3134404b5465727e8b979797979797979286796c605346392d20130600121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504f4c52555c616e7a86929facb9c4b7ab9e918478685e5246392d20130700111d2a3744505d6a7783909daab6c3b7aa9d908477685e52463c393a424d576673808c99a6b3bfb9ada196877a6d6054473a2d211407000000000a1724313d4a5764707d8a97a8b2bdb9ada197877b6e6154483b3a46535f697885929eabb8c0b3a6998d807366544a3f34281c10030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000f1c2835424f5b6875828e9ba8b5c1b8aca095877b6e61564d4745474b545f6976828f9ca9b6c2b8ab9e918478685d5245392c201306000a1724303d4a5763707d7f7f7f7f7f7f7f7f7f72676d737a7e8184858684776a5e5144372b1e1100000000040d18242f39434d575e676d757d82888c8f9297949595949892908d8a85807b716c605c544a40372d20170d0000000000000000010c161f2b353f49515b626b70797f84898d90929794949a93918f8c88837e776e6960594f473d32291e10070000000000010d18242f3a434b515353504a45413a36312c271f1d18120e09020000000000000000000000000000000000000000000000010c161f2b343e48505a616a6f787e83888c8f919293999292908d8a86817c736d665e564c443a30261c0e050000000000000000000000000000000000000b151e2b38434e58616e7b86929fa9b3bab8b8babec5cdbdb0a3968a7d7063574a3d3024170a000000000000000000000916232f3c4956626f7c8995a9b3beb5a89b8f827568544a4f4f4f4f4f4f4f4f4f4f4f4f4f4f4c4a463f372d23180d01000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000a1724303d4a5763707d7f7f7f7f7f7f7f7f7f726b6f787d818486868584817e79716c655d585f676d737a7e828486868584817d79716c605b53493f362c1f150b010000000714212d3a4754606d7a8798a2aebabfb2a6998c7f7366574d43403f45515c6674818e9aa4a4a4a4a49e918478655b5044372b1f120500121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5c5c565e61676d75828f98a3aebabfb4aa9b8e817568564c41362a1d1105000f1c2835424f5b6875828e9ba8b5c1b8aca095877b6e61564d4745474b545f6976828f9ca9b6c2b8ab9e918478685d5245392c20130600000003101c28343f4a546673808d99a6b3c0b8ab9e928578695e53463a36424d576976828f9ca9b5c2b6a99c8f8376665c5044382b1f12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000c1926333f4c5966727f8c99a9b3bebcb1a7998c7f72685f57535153555d666e7b87939facb9c2b5a89c8f827569564c4135291d1104000916232f3c4855616b707373737373737373726d6260686d7175777879796d6053463a2d201307000000000007121d28313b454d555d606b70767c7f82858687888887868583807d79736e69625a514a42392e251b0e05000000000000000000040d1a232d373f49515960676d72797d80838586878787868582807c77716c655f574f473d342b20170d00000000000004111d2935404b555d60605b54514b46423b38332c29241d1a140f0a0400000000000000000000000000000000000000000000040d19222d363e4850585f666d71777c7f8284858686868583817e7a746e6a605c544c443a32281e140a00000000000000000000000000000000000000030c1b27323d46535e6973808d97a1adb9c3c5c6cad0c9bdb0a3968a7d7063574a3d3024170a000000000000000000000714212d3a4754606d7a8797a1adb9b7aa9d918477665c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c595751493f352a1e1206000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e4134404b556b7885929eabb8baada194877a6e6154473b2e211408000916232f3c4855616b707373737373737373726d62656c7074777979797775716d67605b534e555d60686d7275787979787774716d67615a504941382d231a0d03000000000713202c3945525d687985929facb8c2b5a89c8f8275695f554e4c4a5058606d7985919eabb1b1b1a99c8f83766953493f33271b0f0300121e2b3845515e6b7884919eabb7c2b6a99c8f8376696969696a686e7279818e949eaab4bfbaaea3988a7e7164574b3e3025190d01000c1926333f4c5966727f8c99a9b3bebcb1a7998c7f72685f57535153555d666e7b87939facb9c2b5a89c8f827569564c4135291d110400000006121f2b3844505c6676838f9ca9b6c2b5a99c8f827669574d423631404d5a6673808d99a6b3c0b8ac9f9285796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000091623303c4956636f7c8997a1adb9c3b8ab9f92867a6e6962605d5f61676d78828f99a4afbbbcb1a7988c7f7265594c3f2f24190d01000714202c38444f596163666666666666666665625b565d6064686a656c6d665c5145382c1f13060000000000010c161f29333b434b515961636a6f7275787a7a7b7b7a7a797673706d67615e575044403930271c1309000000000000000000000008111b252d373f474f555d60666d707376787a7a7b7a797876736f6a64605b534d453d352b22190e050000000000000613202c3945515d676d6c66605d55534d48443d38352f2a251f1b16100c0700000000000000000000000000000000000000000007101b242d363e464e545c60646a6f72757778797979787674716d68625f58514b423a322820160c0200000000000000000000000000000000000000000a16202a36424d57606d7a85929ea7b1bcc8d3d6dbc9bdb0a3968a7d7063574a3d3024170a000000000000000000000613202c3945525d687885919eabb8b9ac9f9286796d6969696969696969696969696969696965635b51463a2e221609000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845515c677985929facb8baada194877a6e6154473b2e211408000714202c38444f596163666666666666666665625b5b6063686a666d666a6864605c555049434b51565e6165686b666d666a6864605d5550443f382f261b1108000000000004111d2935414c566a7784909daab7c3b9ac9f92867b6e67605859545c606a727f8b97a1adb9bfb4aa9a8d8073675a4d402d22170b0000121e2b3845515e6b7884919eabb7c2b6a99c8f83767676767676787a7e848e939ea6b0bcc0b6ac9f92867a6d6054473a2d2114080000091623303c4956636f7c8997a1adb9c3b8ab9f92867a6e6962605d5f61676d78828f99a4afbbbcb1a7988c7f7265594c3f2f24190d010000000713202d3a4653606d7985929facb8c0b3a6998d8073665a4d4031313d4a5764707d8a97a9b3bebaaea298887c6f6255483c2f2215080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000713202d3a4653606d7985929eacb6c0baaea29891847b746f6d67696e7279818e949fabb5c0b8ab9f95887b6e6155483b2e221508000004101c28333e474f555759595959595959595856514c5254585b535b60605c544b4034281c1004000000000000040d172029313940454f55585f626669676d6e6f6e6e6d67696764605c55524d453e342e271e150b0100000000000000000000000009131b252d353d434b51545c6063676a676d6e6e6d6d666966626058535049413c332b23191007000000000000000714202d3a4753606d7979726d67615f57544f4745403936302c271f1c18120d08020000000000000000000000000000000000000009121b242c343c424a5053585f6266686a6c666d666b6a6764605d56534e454039302820160e04000000000000000000000000000000000000000000040e1a25313b45515d67727e8b95a0acb8c2cfd9d6c9bdb0a3968a7d7063574a3d3024170a0000000000000000000004111d2935414c56697683909ca9b6bbafa399887c7676767676767676767676767676767676726d63574a3e3125180c000000000d192633404c5966737f8c99a6b2bfb4a79a8e8174675b4e413a4653606d7986939facb9baada194877a6e6154473b2e2114080004101c28333e474f555759595959595959595856515053575b545c605c545b5753514b443f3940454c5254585c545c605c545b5753514b433e332d261d140a000000000000010d19242f414e5b6774818e9aaab4bfbbaea3999083796f6a676666666d717c86929fa9b3bebaaea2988a7d7063574a3d302417060000121e2b3845515e6b7884919eabb7c4b8ab9f928582828282828384878b91969ea5afb8c1bbafa49a8e8174685d5245392c20130700000713202d3a4653606d7985929eacb6c0baaea29891847b746f6d67696e7279818e949fabb5c0b8ab9f95887b6e6155483b2e221508000000000916222f3c4955626f7c8898a2aebabeb3a9978a7d7164574a3e312e3b4854616e7b8797a1adb9bfb4aa988b7e7265584b3f3024190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000006121f2b3844505c6674818d9aa4afbbbeb4aaa0969186817c7a78797b7f848e939ea6b0bdbdb2a89d908376695f53463a2d2114070000000b16212c353e44484a4c4c4c4c4c4c4c4c4b4a464145474b4e49505353514b42392e23180c0000000000000000050e171f282f353e44484e535559555d6061626261605d555a5753514b46423b3328231c150c03000000000000000000000000000109131b232b313940454a5053565a555d60616161605c545955544e46443f382f2a2119110700000000000000000a1724313d4a5764707d847f7a746e6963605953514b46423b38322c28231c19130f0a0300000000000000000000000000000000000009121a222a30383f44464e5355595c5e5f5c605c545d5a5754524c47433c342e271e160e05000000000000000000000000000000000000000000000009141f2935414b55606d7883909da6b0bdc7d1dcc9bdb0a3968a7d7063574a3d3024170a00000000000000000000010d19242f414e5b6774818e9aa7b4c0b5ab9d908382828282828282828282828282828282827f7265594c3f3226190c000000000d192633404c5966737f8c99a6b2bfb4a89b8e817568544a3f3b4855616e7b889aa4afbbbaada194877a6e6154473b2e21140800000b16212c353e44484a4c4c4c4c4c4c4c4c4b4a4644464a4e4a5053504a4e4b46454039332f353a4146474b4f4a5053504a4e4a474540393127221b140b0200000000000000081724313e4a5764717d8a98a2aebabfb5ab9f9590837c7774737375797e859298a2aebbc0b5ab9f9285796d6053473a2d2014070000121e2b3845515e6b7884919eabb7c4baada297928f8f8f8f8f909196989ea0a8afb7c1bdb3a99f93877c6f62564c4135291d1104000006121f2b3844505c6674818d9aa4afbbbeb4aaa0969186817c7a78797b7f848e939ea6b0bdbdb2a89d908376695f53463a2d211407000000000c1825323f4b5865727e8b98aab4bfb9ada297877b6e6154483b2e2d3a46535e697885929eabb8c1b4a79b8e817468564c4135291d110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000003101c28343f4a54626e7b87939faab4bebcb2a8a098928d88868586888c91969ea5afb8c2b8aca0968a7e7164574d42372b1e120500000005101a232c33383c3d40404040404040403f3d3a35393a3e423f44464645403930271d1207000000000000000000050d161d242933383c4347494c4b51535455555453514b4d4a464540393630292018120b03000000000000000000000000000000010911191f272f35383f44464a4d4b515354545453514a4d4947433c37332d261d180f070000000000000000000a1724313d4a5764707d8a8b85807b75706b65605d55524d48433d38342e2a251e1b150f0b0600000000000000000000000000000000000810181e262e34383c4347484c4f514a5153514a504e4b4745413a373128231d150c05000000000000000000000000000000000000000000000000030d18242f3a44505c66707d89949eabb5c0cbd7c9bdb0a3968a7d7063574a3d3024170a0000000000000000000000081926323f4c5965727f8c98a5b2bfb8ab9f95908f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8e8175685b4e4235281b0f020000000c1926323f4c5965727f8c98a5b2bfb6a99c8f8376665b50443d4a5663707d8996acb6c0baada194877a6e6154473b2e211408000005101a232c33383c3d40404040404040403f3d3a37393d413f4446443f423e3a38342e2724293035393a3f423f4446443f413e3a38352f271f17110a0200000000000000000714202d3a4753606d7985929faab3bebdb1a79f95908983817f8082858b9297a2aab4bfbbafa3998e8174675d5145382c1f13060000121e2b3845515e6b7884919eabb7c4beb3a9a29f9c9c9c9c9c9d9ea1a8aaacb2bac1beb5aba1978e81756a5f53443a3024190d01000003101c28343f4a54626e7b87939faab4bebcb2a8a098928d88868586888c91969ea5afb8c2b8aca0968a7e7164574d42372b1e120500000005111d2935414c566874818e9ba7b4c1b8ab9e928578695e53463a2d2a36424d576976828f9ca9b5c2b7aa9d918477685d5246392d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000000b17232e3847535f6a75818e98a2aebac0bab2aaa29f9a9597929299989ea1a9afb7c1b9afa59e9184796d6053463c31261a0e020000000008111a21282c2f30333333333333333332312e292c2d312d3337393a38342e271e150b0000000000000000000000040c121821282c32373b3c3f40454747484847474540403d3a38342e2a251f170e0700000000000000000000000000000000000000070d151d24292e34383a3d40404547474847464440403c3b37322b27221b140b06000000000000000000000a1724313d4a5764707d8a98928d87827d77716d67615e57544e4644403936302b261f1c17110d0801000000000000000000000000000000060c141c23282b31373a3c3f4244404446444043413e3a39352f2b262018120b03000000000000000000000000000000000000000000000000000007131d28343f4a54606b76828f99a3afbbc5d0c9bdb0a3968a7d7063574a3d3024170a00000000000000000000000a1724303d4a5763707d8a96abb5bfbcb1a79f9d9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9b8e8175685b4e4235281b0f020000000b1825323e4b5865717e8b98a4b1beb8ab9f9285796c605347464f596673808c99a6b3bfbaada194877a6e6154473b2e21140800000008111a21282c2f30333333333333333332312e2b2d302e34383a38342e312d2c28231d181e25292d2e322e34383a38342e312d2c29241d150d060000000000000000000006131f2c3945515d6774808d98a2aebac1b9b1a7a09d95908d8c8c8e92979fa2a9b3bcbcb2a89f92877b6e62554b4035291d10040000121e2b3845515e6b7884919eabb7c4c5bbb3adaba9a9a9a9a9a9abacb2b7b9bdc3bcb4aca39992857a6d61584e4332281e1308000000000b17232e3847535f6a75818e98a2aebac0bab2aaa29f9a9597929299989ea1a9afb7c1b9afa59e9184796d6053463c31261a0e020000000713202d3946525d687784919daab7c2b5a99c8f827669574d42362a2531404d596673808c99a6b3bfb9ac9f93867a6d6154473a2e21140600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000006111c2b37434e58616e7b86929fa4aebbc0bcb4aeaca7a9a29f9fa3ababadb2bbc1b9b1a79e938a7d70665c5144382a1f14090000000000000810161c20232426262626262626262524221d20212522272b2d2d2c28231d150c0300000000000000000000000001070d161c20262b2e2f2f35383a3b3c3b3b3a38352f312d2c28231d1a140d05000000000000000000000000000000000000000000030b12181c23282c2d302f35393a3b3b3a3a38342e2f2e2b271f1b17110a0200000000000000000000000a1724313d4a5764707d8a979f99938f89837e79736e6962605853514a46413a37312b28221c19130c04000000000000000000000000000000020a11171c1f262b2e2f33352e34383a38342e34312d2c29241e1a150c0700000000000000000000000000000000000000000000000000000000010b17232e38424f59626e7c87929fa9b3becac9bdb0a3968a7d7063574a3d3024170a00000000000000000000000815222f3b4855626e7b8899a3aebbc2b9b1aba9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a89b8e8175685b4e4235281b0f020000000b1724313e4a5764717d8a97a4b0bdbaada297897d70635c535356606b7783909daab6c3baada194877a6e6154473b2e211408000000000810161c20232426262626262626262524221f202423282c2d2c282324201f1c18120c13191d20212523282b2d2b282324201f1d18120b03000000000000000000000004101d2935404b55616e7a85929fa5afb8c1b9b1aca7a09d9a99999b9fa2a9adb3bbbcb4aaa1968d81746a5f5343392f24180c000000121e2b3845515e6b7884919eabb7c4cdc5bebab8b5b5b5b5b5b6b7b9bdc4c4bdb9b1aaa39a92877d70685e52463c3120160c020000000006111c2b37434e58616e7b86929fa4aebbc0bcb4aeaca7a9a29f9fa3ababadb2bbc1b9b1a79e938a7d70665c5144382a1f1409000000000714212e3a4754616d7a86939facb9c0b3a6998d8073665a4d40312524313d4a5764707d8a97a9b3bebbafa49a8a7d7063574a3d2d22170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000000000f1a26313c46535e69717e8b929da4afb5bdbfbab8b4b3adabacaeb5b8b9bdbebab0a7a0958e81756b61544a403428180e0300000000000000050b10141617191919191919191918181511131418171b1f20201f1c18120b03000000000000000000000000000000050b10151b1f212224292c2d2e2f2f2e2d2c292424201f1c18120e0902000000000000000000000000000000000000000000000001070c11171c1f202324292c2d2e2e2e2d2c282322221f1b150f0b06000000000000000000000000000a1724313d4a5764707d8a97aba49f9c95908b85807b756f6a64605c54524c47433c38332d29241e160d0800000000000000000000000000000000060b10151b1f2122262923282c2d2c2823272421201d19130f090300000000000000000000000000000000000000000000000000000000000006111c26303d47535f6a74818d97a2adbabfbfbdb0a3968a7d7063574a3d3024170a00000000000000000000000713202d3a4653606d7986929facb9c5c2bcb8b6b5b5b5b5b5b5b5b5b5b5b5b5b5b4a89b8e8175685b4e4235281b0f020000000a1623303d495663707c8996a8b2bdbeb3a99c9082766e63606061686f7c89959fabb8c4baada194877a6e6154473b2e2114080000000000050b101416171919191919191919181815121317171c1f201f1c17181313100c0702080d11131418171c1f201f1c17171413100c0701000000000000000000000000000c18242f3946525e68727f8b939ea6afbabfbcb8b1acaaa7a6a6a8abadb3babebbb3aaa29891847a6d60574e4231271d1207000000121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbfbebebeb9b8b2ada8a09892887f716b61564c41342a200e040000000000000f1a26313c46535e69717e8b929da4afb5bdbfbab8b4b3adabacaeb5b8b9bdbebab0a7a0958e81756b61544a403428180e03000000000a1724303d4a5763707d8a9aa4afbbbeb3a9978a7d7164574a3e3124212e3b4854616e7b8797a1adb9c0b6ac998c80736653493f33271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000000000915202a36424d57616c73808d929fa3abb1b8bdc3c0bebab8b9bbbfc3beb9b3ada69e959083796d60594f42392e231806000000000000000000000407090a0d0d0d0d0d0d0d0d0c0b09040707060b0f12131313100c0700000000000000000000000000000000000000040a0f131516181d1f2021222221201f1d18171313100c070000000000000000000000000000000000000000000000000000000000060c10121317181d1f20212121201f1c181615130f0a030000000000000000000000000000000a1724313d4a5764707d8a97a3afaca7a09d97928d86817c76716d66615e56534e46443f38352f281f1a11080000000000000000000000000000000000030a0f121515191c181c1f201f1c181b181413110d08010000000000000000000000000000000000000000000000000000000000000000000a141e2b37434e58616d7a85929fa8b2b2b2b2b0a3968a7d7063574a3d3024170a000000000000000000000006121f2c3844505c667784919daab7bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb4a89b8e8175685b4e4235281b0f020000000714212d3a4754606d7a8796a0acb9c5b7ab9f948d8076706d6c6e717a84919ea7b1bcc8baada194877a6e6154473b2e211408000000000000000407090a0d0d0d0d0d0d0d0d0c0b090506060c10121312100c060706040000000001050707060b10121312100b060706040000000000000000000000000000000007121d2a36414c56626d75818e949ea5aeb4babfbcb8b7b4b2b3b5b8babebcb8b0a9a29892867c6f685d52453c311f150b01000000121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b1b1b3adaba8a19e9591867e716d62594f443a3022180e000000000000000915202a36424d57616c73808d929fa3abb1b8bdc3c0bebab8b9bbbfc3beb9b3ada69e959083796d60594f42392e23180600000000030f1b27333f49536673808c99acb6b2b2ada297887b6e6155483b2e22202d3a46525e697885919eabb2b2b2a99c8f8276655b5044372b1f1205000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000000030e1a25313b45505a606c77808c9299a0a7acb2b7b9bbc0bcc0bbb9b7b3ada9a29f948f837a6e675d51473e30271c12070000000000000000000000000000000000000000000000000000000000000305060706040000000000000000000000000000000000000000000000030608070c101314141515141413100c07070604000000000000000000000000000000000000000000000000000000000000000000030607070c1013141415141312100c0708060300000000000000000000000000000000000a1724313d4a5764707d8a97a3b5b9b1aca9a19e99928e89837e79736d68625f5853504a45413a312c231a1005000000000000000000000000000000000000030608090c070c10121312100c070b070604010000000000000000000000000000000000000000000000000000000000000000000000020c1a26313c46525e68727f8c96a0a5a5a5a5a5a3968a7d7063574a3d3024170a000000000000000000000003101c28343f4a546975828f9ca8b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a89b8e8175685b4e4235281b0f020000000713202c3945525d687784919eaab7c4bbb0a69c928d827d7a797a7e849196a0acb9c3cdbaada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000003060706030000000000000000000000000000000306070603000000000000000000000000000000000000000000010e1925303b44515b606d79828e939fa2aaaeb4b8b9bdbdbdbdc0bbb9b7b1aca69f9792867d706a60564c41332a200d0300000000121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a4a9a19e9b96918b847c716c625a50473d32291e100600000000000000030e1a25313b45505a606c77808c9299a0a7acb2b7b9bbc0bcc0bbb9b7b3ada9a29f948f837a6e675d51473e30271c12070000000005121f2b3744505b6576828f9ca5a5a5a5a59e928578695f53463a2d211e2a36424d576975828f9ca5a5a5a5a59f9285796c605346392d201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000000000009141f29333e44505b656c747f8790959ea0a8aaacafb5afb5afacaaa9a19e97928b82796e685e554b40352c1e150b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406070809080807060400000000000000000000000000000000000000000000000000000000000000000000000000000000000000040607080807070604000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3abacb2b8b3adaba39f9b95908a847f7a746f6a64605b54524c433e352c21160b000000000000000000000000000000000000000000000000000406070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a15202a36414c56606d79849198989898989898968a7d7063574a3d3024170a0000000000000000000000000c17232e404d5a6773808d9aa5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a59b8e8175685b4e4235281b0f0200000004111d2935414c566875818e9ba8b2bdc2b8aea49c948f898686878b9196a0a8b2bbc1cabaada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008141e29323f45515c676d79818b92989fa2aaabadb2b0b0b0b6afacaaa7a09d948f857d706b61584e433a2f21180e0000000000121e2b3845515e6b78849198989898989898989898989898989898979697918e8a847f786f6a615a50483f352c20170d00000000000000000009141f29333e44505b656c747f8790959ea0a8aaacafb5afb5afacaaa9a19e97928b82796e685e554b40352c1e150b00000000000613202d394653606c788592989898989898988f827669574d42362a1e1a2530404d596673808c9898989898989897887b6e6255483b2f221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000000000030d172127333f49535b606d727d838b91969a9d9fa3aba3aba39f9d9a97928c857e756d675e564d43392f231a0c03000000000000000000000004080a0a131313131313131313100f0d0a050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a92999ea0a8acaeb4b5afaca79f9d96918c86817c76706c66605d564f473e33281c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030d1925303a45515c67717e8a8c8c8c8c8c8c8c8c8a7d7063574a3d3024170a000000000000000000000000061825323e4b5865717e8b9898989898989898989898989898989898989898989898988e8175685b4e4235281b0f02000000010d19242f3d4a5663707d8996a1adb9c2c0b6aea69f9c96999399989ea1a9a8aab0b8c1baada194877a6e6154473b2e211408000000000001070b0f1112131313131313131313100f0d0a050000000004080a0a13131313131313131313130908060300000000000000000000000000000000000000000000000000020d17202934404b555c676d757e868d92989b9ea1a9a3a4a3aca49f9d9a95908a827b706b61594f463d31281e0f060000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8b8b898785817d79726d66605850483f362d231a0e05000000000000000000030d172127333f49535b606d727d838b91969a9d9fa3aba3aba39f9d9a97928c857e756d675e564d43392f231a0c0300000000000915222f3c4855626f7b888c8c8c8c8c8c8c8c8c8073665a4d4031261a1724313d4a5764707d8a8c8c8c8c8c8c8c8c8b7e7165584b3e3225180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000e1a2734414d5a6774808d9aa7b3beb1a5988b7e7265584b3f3946535f6c7986929facb9bbaea39986796d6053463a2d2013070000000000000000050f17222d384149505b636b6f787e84898d9092999596959992908e89857f7a716c605d554d443b31271d110800000000000000000000050b101416172020202020202020201d1c1a16110a030000000000000000000000000000000000000000000003070909131313131313131313130f0e0c0904000000000004080c0e0f131313131313131313130b0a08040000000000000000000000000000000000000000000000000002070a0c0d1313131313131313130d0c0a06020000000000000000000815222e3b4855616e7b82868c91969b9fa2aaabb0b8b1aba9a19e98928e88827d78726d6861594f44382c2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e2834404b55616c727f7f7f7f7f7f7f7f7f7f7b6e6155483b2e221508000000000000000000000000091623303c4956636f7c898c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8175685b4e4235281b0f02000000000813202d394653606c7884919ea6b0b9c2c0b8b0aba9aba49fa4ababa69e9c9ea6b0bbbaada194877a6e6154473b2e21140800000000050c12171b1d1e2020202020202020201d1c1916100a03050b1014161720202020202020202020201615130f0a04000000000000000000000000000000000000000000000000050e18232f39434b555c606d727a80858b8e919695969797969a93918d89837e766e6960594f473e342b1f160c0000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7e7c7b7875706d66605c544e463e362d241b11080000000000000000000000050f17222d384149505b636b6f787e84898d9092999596959992908e89857f7a716c605d554d443b31271d11080000000000000815222e3b4855616e7b7f7f7f7f7f7f7f7f7f7f7c6f6255483c2f221514212e3a4754616d7a7f7f7f7f7f7f7f7f7f7f7d6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000d1a2734404d5a6773808d9aa6b3beb1a5988b7e7265584b3f3845515c677986929facb9b9ac9f928679665c5044382b1f120600000000000000000006111b262f383f44515960666d71787c80838688898989888684817d79726d68625a514c433b32291f150b000000000000000000000810171c2023242d2d2d2d2d2d2d2d2d2a2926221c150d0400000000000000000000000000000000000000040a0f131516202020202020202020201c1b18150f09020002090f14181b1b20202020202020202020171714110c0500000000000000000000000000000000000000000000070d1316191a202020202020202020191916120d0700000000000000000814212d3a47535f696e757b7f84898e92989c9fa6abadb2b2adaaa39f9b948f8a847f7a706b6155483c2f23160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c18232e3943505a626d727272727272727272726e695f53463a2d2114070000000000000000000000000714212d3a4754606d797f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7d7063574a3d3024170a000000000006121f2b3844505b66717e8b949ea7b0b9bec2bbb7b5b5afacafaea49d948f949eaab7baada194877a6e6154473b2e211408000000060f161d23272a2b2d2d2d2d2d2d2d2d2d292926211c150d10171c2023242d2d2d2d2d2d2d2d2d2d2d22211f1b150e0700000000000000000000000000000000000000000000000007121d273139434b515b62686e747a7e828587888a8a8a89888684807c77716c615e574f473e352c22190d040000000000000b1724313d4a56626c71727272727272727272727272727272727271706e696864605c54514a423c342d241b12090000000000000000000000000006111b262f383f44515960666d71787c80838688898989888684817d79726d68625a514c433b32291f150b000000000000000814212d3a47535f696e727272727272727272726f6a5f53473a2e211513202d3946525d686d727272727272727272726f6b6054483b2f221509000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb2a5988c7f7265594c3f3a4753606d7a8699a3afbbb8ab9f9285786c5f4a3f34281c1003000000000000000000000a141d262d333f474f545c60656c6f7477797b7c7c7c7b7a7774706d66605d565045413a312920170d0300000000000000000008111a22282d30313939393939393939393635322d271f160d030000000000000000000000000000000000070f161b1f22232d2d2d2d2d2d2d2d2d2d282725201b140c030b131a202527282d2d2d2d2d2d2d2d2d2d2423211c17100800000000000000000000000000000000000000010a12191e2325262d2d2d2d2d2d2d2d2d2625231e19120a0100000000000006121e2b37424d575f61696e72777c81858b9094999ea1a8acaeb4aeaca69f9c96918c867d7063574a3d3024170a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d27303e48515b6265656565656565656565615f574d42362a1e12050000000000000000000000000613202c3945515d676d7272727272727272727272727272727272727272727272727272706b6155483c2f2316090000000000030f1c28333f4a54626c76828f959fa6adb3b6b7b8b7b6b4aeaaa29f928d828f9ca8b2b2ada194877a6e6154473b2e2114080000050f1820282f3337383939393939393939393635322d261f161a21282d303139393939393939393939392f2e2b26201810070000000000000000000000000000000000000000000000010b151f273139404551565e61676d7175787a7c7d7d7d7d7b7a77746f6b64615a534d453d352c231a1007000000000000000915212e3a45505a626565656565656565656565656565656565656463615e575753514a444039302b221b12090000000000000000000000000000000a141d262d333f474f545c60656c6f7477797b7c7c7c7b7a7774706d66605d565045413a312920170d030000000000000006121e2b37424d575f6165656565656565656565625f584e43372b1f12111d2935414c565d61656565656565656565656360594f44382c201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000b1825323e4b5865717e8b98acb6c0b3a79a8d8074675a5047464b55626e7b8895abb5c0b7aa9d9084776a5d51442e23170b0000000000000000000000020b141b2227353d424a50535b606367666d6e6f706f6e6d676763605c54524c443f352f281f170e0500000000000000000005101a232c33393c3d46464646464646464643423e3831281f150a0000000000000000000000000000000007101921272c2e2f393939393939393939393534312c251e150c151d252c3134353939393939393939393931302d28221a12080000000000000000000000000000000000000a131c242a2f323339393939393939393933322f2a231c130a000000000000020e1a26313c454d53575e61666b6f747a7e83888d91969b9fa3aaacb1b0aba8a09e988b7f7265584c3f3225190c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b151e2c363f4951565859595959595959595955534d453b31261a0e0200000000000000000000000004111d2935414c555d6065656565656565656565656565656565656565656565656565656361594f44382c2014070000000000000b17222d3842505a616e7a8390949ea1a9a9aaabaaa9aaa29f98928b807d8996a3a6a6a6a194877a6e6154473b2e21140800010c16202a323a3f434546464646464646464643423e3831281f232c33393c3d46464646464646464646463c3b37322a22180e040000000000000000000000000000000000000000000000030d151f272f343f444c52555d606468686d6f707170706f6d6767636059555046423b332b231a1108000000000000000005111d29343f485056585959595959595959595959595959595958585654534d4a46444039342e271e19100900000000000000000000000000000000020b141b2227353d424a50535b606367666d6e6f706f6e6d676763605c54524c443f352f281f170e050000000000000000020e1a26313c454d53555959595959595959595955534e463c31261b0f0d1924303a444c52545959595959595959595956544f473d32271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000a1623303d495663707c899aa4afbbb7aa9d9184776c61595353555d67727f8b98a5b1beb5a89b8f8275685c4f4235291c06000000000000000000000000020a1117232b30383f4449505356545c606162636261605c555653514a45413a3229241e160d05000000000000000000000b17222c363e44494a535353535353535353504e4a433a31271c11050000000000000000000000000000040f19222b32383b3c4646464646464646464642413d3730271e141d272f373d4042464646464646464646463e3c39332c241a10050000000000000000000000000000000007121c252e353b3f40464646464646464646403e3b352e251c120700000000000009151f2a333c42474d5254596063676d71767b8084898e92989da0a7b1b7b2acaa988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c1a242d373f464a4b4c4c4c4c4c4c4c4c4c4846423b33291f140900000000000000000000000000010d19242f3a434c5154595959595959595959595959595959595959595959595959595957554f473e33281c100400000000000006111c262f3f46525e686e7a828b91979a9c9d9e9e9d9a98928e867e737d8996999999999994877a6e6154473b2e2114080007121d28323c444b5051535353535353535353504e49423a31262c353e44494a53535353535353535353534947433c342a20150a000000000000000000000000000000000000000000000000030d151d2329323b41464c515458565e61626364646362605d5556544f49453e36312921191108000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4b4b494846423d3a38342e28231c150c07000000000000000000000000000000000000020a1117232b30383f4449505356545c606162636261605c555653514a45413a3229241e160d050000000000000000000009151f2a333c4247484c4c4c4c4c4c4c4c4c4c4847433c342a20150a08131e28323a4146474c4c4c4c4c4c4c4c4c4c4948443d352b21160b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000714212d3a4754606d7a86939facb9b8aca0958a7e716b62606061676d7984919eaab7bdb2a8998c7f7266594c3f3326190c00000000000000000000000000000610191e262e34383f4446494a5153555656565553514b4a46444039352f282019130c040000000000000000000004101c28333e485055576060606060606060605d5a544c43382d22160a00000000000000000000000000000a16212b343d434849535353535353535353534f4d48413930251b252f3941484d4e535353535353535353534a49453e362c22170c000000000000000000000000000000020d19242e3740474b4d5353535353535353534c4b4640372e23190d020000000000030e18212a31373b4246474f54555d6064696e73787d81868b9095a0acb8bdb2a5988b7f7265584c3f3225190c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008121b252d343a3d3f3f3f3f3f3f3f3f3f3f3b3a36312921180d03000000000000000000000000000008131e28313a4145474c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a48443e352c21160b00000000000000000a141d2a36414c565e686d787e85898d8f919291908d8a86817b72707d898c8c8c8c8c8c8c877a6e6154473b2e211408000b17232f3a444e565c5e6060606060606060605c5a544c42382d333e474f5557606060606060606060606055534e463c32261b0f03000000000000000000000000000000000000000000000000030b1218202930363a4145474b4c525455575757565553514b4948443d39332a251f170f07000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3e3d3b3a36312d2c28231c18120b030000000000000000000000000000000000000000000610191e262e34383f4446494a5153555656565553514b4a46444039352f282019130c040000000000000000000000030e18212a31373a3b3f3f3f3f3f3f3f3f3f3f3c3a37312a22180e04020c1620283035393a3f3f3f3f3f3f3f3f3f3f3c3b38322b23190f0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000613202c3945515d677683909dabb4bdb1a89f92867d746f6d6c6e7179818f96a0acb9b9aca196897c6f6256493c2f231609000000000000000000000000000000070c151c23282d3337393c40444648494949484745403d3a38342e29241e160d080100000000000000000000000814202d3944505a61646c6c6c6c6c6c6c6c6c69665e544a3e32261a0d00000000000000000000000000030f1b27323d464e5456606060606060606060605b59534b41372c202c37414b53595b60606060606060606060575550483e33281c1104000000000000000000000000000007131e2a3540495257596060606060606060605957514940352a1e1206000000000000060f181f262b30363a3d43484b5153575f61666c70757a7f83909daab6beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009131b23292e31323232323232323232322e2d2a261f180f06000000000000000000000000000000010c161f282f35393a3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3d3c38332c231a10050000000000000000020b1925303b444c565d666c71797d808384858483817e7a746e696e7b7f7f7f7f7f7f7f7f7f796d6053473a2d201407000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c69665e54493e3239444f5961646c6c6c6c6c6c6c6c6c6c6c625f584e43372b1f13060000000000000000000000000000000000000000000000000001070e171e252a2f35393a3e414647494a4a4a4a484745403c3b38322d28221a140d050000000000000000000000000009121b22292e3132323232323232323232323232323232323231302e2d2a25201f1c18120c07000000000000000000000000000000000000000000000000070c151c23282d3337393c40444648494949484745403d3a38342e29241e160d080100000000000000000000000000060f181f262b2d2e323232323232323232322f2e2b26201810060000040e161e24292d2e32323232323232323232302f2c27211911070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000004111d2935414c5566727f8c99a3aebabaaea2989287817c7a797a7e848f939ea8b2bdb3a99e9184786c605346392d20130600000000000000000000000000000000030a11171b22272b2d2e34383a3b3c3d3c3b3a38342f2d2c28231c19130c04000000000000000000000000000a1623303c4955616c707979797979797979797670665a4e4235291c0f0000000000000000000000000007131f2c38434e5860626c6c6c6c6c6c6c6c6c6c68655d53483d311d313d48535d65686c6c6c6c6c6c6c6c6c6c64615a5045392d21140800000000000000000000000000000a16232f3b47525b63666c6c6c6c6c6c6c6c6c66635b51463b2f23160a000000000000060f171f262a3036393d43474b5153575f61666d70757a7f83919daab7beb2a5988b7f7265584c3f3225190c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000911181d22242526262626262626262622211e1a140d060000000000000000000000000000000000040d161e24292c2d3232323232323232323232323232323232323232323232323232302f2c28211a11080000000000000000000008141e29323b444c545b60676d7074767778777674716d68615e696e7373737373737373736d675d5145392c20130600111d2a3743505c6872787979797979797979797670665a4e42353c4955616c707979797979797979797979766a5f53473b2e211508000000000000000000000000000000000000000000000000000000050d14191e24292c2d3036393a3c3d3e3d3d3c3a39352f2f2c27211d170e09030000000000000000000000000000000911181d2124252626262626262626262626262626262625252321211e1a1312100c07000000000000000000000000000000000000000000000000000000030a11171b22272b2d2e34383a3b3c3d3c3b3a38342f2d2c28231c19130c0400000000000000000000000000000000060e151a1e21222626262626262626262622211f1b150e0600000000040c13191d2021262626262626262626262322201b160f07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000010d19242f3a4754616d7a86929fa9b3bdb3aaa299928d898686878b91959ea5afbab9ada1978c7f72655b5044372b1f1205000000000000000000000000000000000000060c11171b1f2023282c2d2e2f302f2e2d2c2923201f1c18120d080100000000000000000000000000000a1724313d4a5764707d8686868686868686868276695d5043362a1d10000000000000000000000000000915222e3b4854606a6f79797979797979797979756f65594d392e2334404d59656f7579797979797979797979716c6155493c3023170a00000000000000000000000000000c1925323f4b57636d73797979797979797979736d63574b3e3225190c0000000000030d17212931363a4146474e54555d6064696e73797d82868c9195a0acb8c0b2a5988b7f7265584c3f3225190c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c121518181919191919191919191514120e090300000000000000000000000000000000000000040c13191d202126262626262626262626262626262626262626262626262626262423201c1610080000000000000000000000020d172029323a424a50555c606367696a6b6b6a6764605d56575e61666666666666666666605d554b4035291d100400121e2b3845515e6b78848686868686868686868276695c504337434e5864707e86868686868686868686867c6f6255493c2f2216090000000000000000000000000000000000000000000000000000000002080d13191d2021252a2d2e2f303131302f2d2c292422201b16110c06000000000000000000000000000000000000060c11151718191919191919191919191919191919191818161514120e09060400000000000000000000000000000000000000000000000000000000000000060c11171b1f2023282c2d2e2f302f2e2d2c2923201f1c18120d080100000000000000000000000000000000000003090e121415191919191919191919191515120f0a0400000000000002080d111314191919191919191919191615130f0b0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000813202d3946525e6874808d97a1abb5bcb3aba39f9a95999399979da0a8afb7b9afa59e92857a6d6053493f33271b0f030000000000000000000000000000000000000000060b0f1213181c1f202223232322201f1c181312100c0700000000000000000000000000000000000a1724313d4a5764707d8a93939393939393908376695d5043362a1d10000000000000000000000000000916232f3c4956626f7c86868686868686868686817568554b40342834404a54687581868686868686868686867e7164574a3e3124170800000000000000000000000000000d1a2633404d596673808686868686868686867f7366594c403326190d000000000009141f29333b42464c5254586062676d71767b80848a8f92999da0a7b1b9b5afa5988b7f7265584c3f3225190c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000106090b0c0c0c0c0c0c0c0c0c0c080705020000000000000000000000000000000000000000000001080d1113141919191919191919191919191919191919191919191919191919171614100b0500000000000000000000000000050e1720282f383f444b5153565a5c5e5f5e5d5a5754524c4d535459595959595959595953514b43392f24180d0100121e2b3845515e6b788491939393939393938f8376695c50433a47535f6a76828f93939393939393938f82766a5f53473b2e21150800000000000000000000000000000000000000000000000000000000000001080d111314191d202122242424232220201d1815130f0b040000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0b0a08070502000000000000000000000000000000000000000000000000000000000000000000000000060b0f1213181c1f202223232322201f1c181312100c070000000000000000000000000000000000000000000000020608080c0c0c0c0c0c0c0c0c0c0908060300000000000000000000010507070c0c0c0c0c0c0c0c0c0c09090703000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000005111e2a36414c56616d7a859299a4afb5bdb5aeaca7aba49fa4abaaacb1babab0a79e938b7e71685d5241382d22170b00000000000000000000000000000000000000000000000305070c10121315161616151413100c070604000000000000000000000000000000000000000a1724313d4a5764707d8a979f9f9f9f9f9c908376695d5043362a1d10000000000000000000000000000c1825323f4b5865727e8b9393939393939393918477675c5145382c3844515c6677849093939393939393938d8073665a4d403025190e02000000000000000000000000000d1a2633404d596673808c939393939393938c7f7366594c403326190d00000000020e1a26313b454d53565e61656a6f74797e83888d91969b9fa3abacb1b3adaba39f988b7f7265584c3f3225190c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010406070c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0a09070400000000000000000000000000000000050e161d262d33394045464a4d50515251504e4b4745414246484c4c4c4c4c4c4c4c4c4745403931281d12070000121e2b3845515e6b7884919e9f9f9f9f9f9c8f8376695c5043414c55626e7b88949f9f9f9f9f9fa095897d7063584e43372b1f13060000000000000000000000000000000000000000000000000000000000000000010406080d1113141617171717151413110d07070300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000305070c10121315161616151413100c0706040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000010d1925303a46525e68707d87939fa3abb2b8bbb9b4b5afacafb5b7b8bab4aea69f958f81756c62564c412f261b110600000000000000000000000000000000000000000000000000000004060708090a090807060400000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3acacaca99c908376695d5043362a1d1000000000000000000000000004101c2834404a546774818e9a9f9f9f9f9f9f9f9286796d6053463a2d3a4653606d7986929f9f9f9f9f9f9f9c8f827569564c41362a1e1105000000000000000000000000000d1a2633404d596673808c999f9f9f9f9f998c7f7366594c403326190d0000000005121e2a36424d575f61686d72777c81858b9094999ea1a9acaeb5b1aba9a19e99928e897e7165584b3e3225180b0000000000000002060808131313131313131313131308070502000000000000000000010507071313131313131313131313080705020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040b141c22282e34383a3d414344454443413e3a3935363a3b4040404040404040403a39352f281f160c010000121e2b3845515e6b7884919eabacacaca99c8f8376695c504345515d6774818d9aa6b0acacb2a89d9083776b6054463c32261b0f0300000000000000000000000000000000000000000000000000000000000000000000000001050707090a0b0a0a09070604010000000000000000000000000000000000000000000000000001070b0f111213131313131313131313131313131313131313131313131313131212100c080200000000000000000000000000000000000000000000000000000000000000000004060708090a090807060400000000000000000000000000000000000000000000000000000001070b0f1112131313131313131313100f0d0a05000000000003070b0d0e131313131313131313131309080603000000000000000000000000000000000000000000000000000406070a0d0f11121211100f0c0906050300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004080c0e0f121212121212121210100d0a05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000008131e2935414c56616b727f8b9299a0a8acb2b5b7b8b9b9b9b8b6b4aeaaa39f948f83796d605a50433a2f1d140a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b9b6a99c908376695d5043362a1d1000000000000000000000000006121f2c3844515c667783909daaacacacacafa399887c6f6255483c2f3c4855626f7b8899a3aeacacacacab9e918578685e5246392d201407000000000000000000000000000d1a2633404d596673808c99a6acacaca6998c7f7366594c403326190d000000000714212d3a46535f696e757a7f84898e92989c9fa6abadb2b5aeaca79f9d97928c86817d716c62564a3d3124170b000000000003090f12141520202020202020202020201414110e0802000000000002080d11131420202020202020202020201514120e090200000000000000000000000000000000000000000406070a0d0e0f0f0e0b08080602000000060606060606060606000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a11171d23282c2d3034363738383734312d2c292a2d2e3333333333333333332d2c29241d160d04000000121e2b3845515e6b7884919eabb7b9b6a99c8f8376695c503f4953606d7a85929facb8b9b9aca1968a7e7164594f44342a20150a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050c12171b1d1e20202020202020202020202020202020202020202020202020201f1e1c18130d06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050c12171b1d1e2020202020202020201d1c1916100a030001080e13171a1a20202020202020202020201615130f0a04000000000000000000000000000000000000000001070c101314171a1c1e1e1f1e1d1b191613120f0b06000000000000000000000000000000000000000000000000000000000000000000000000000000000002090f14181b1b1e1e1e1e1e1e1e1e1d1c1a16110a0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000020d1925303a444f59626d727f8791969ea0a8a8aaacacafacaba9aaa29f98928c82796d675d51483f31281e0b0200000000000000000000000305060707070707070707070707070707070707070707070707070707070707060300000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000713202d3a4653606d7986929facb9b9b9c0b5ab978a7e7164574b3e313e4b5764717e8a97abb4bfb9b9b9ada197877a6e6154473b2e211408000000000000000000000000000d1a2633404d596673808c99a6b3b9b2a6998c7f7366594c403326190d000000000815222e3b4855616e7b81868c90959a9fa2aaabb0b8b3adaba39f9b95908b85807b756f6b625a50453a2e21150900000000060e151a1f21222d2d2d2d2d2d2d2d2d2d2c21201e19140d05000000050c13191d20212c2d2d2d2d2d2d2d2d2d2c21201e1a140d050000000000000000000000000000000001070c101314171a1b1c1c1b181514120e09090a1313131313131313130807050200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b12181c1f202327292b2c2b2a272421201d1e212126262626262626262620201d18120c0400000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5044505b65727f8b98a2aebabeb3a99e9184786d6053463d3320180e0400000000000001070b0f1112131313131313131313131313131313131313131313131313131313130f0e0c08040000000000000000000000000000000000000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c2b28241f18100700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d292926211c150d040b131a1f2426272d2d2d2d2d2d2d2d2d2d2d22221f1b150f070000000000000000000000000000000000030a0f12181d1f202427292a2b2b2b2a282623201f1b17110d080200000000000000000000000000000000000000000000000000000000000000000000000000030b131a202527282b2b2b2b2b2b2b2b2a2926221c150d04000000000000000000000000000000000000000001010100000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000008131e28323e47515b626d727d848b9196999c9d9f9fa39f9e9c9a98928d867f786d675d554b40362d1f160c00000000000000000000060b0f1213131313131313131313131313131313131313131313131313131313131312100c060000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000916222f3c4955626f7c8899a3aebac7d1c0b3a6998d8073665a4d402f404d596673808c99a6b3bfd1c9beb3a9968a7d7063574a3d30241708000000000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d8a92999da0a7abaeb3b9b1aba9a19e99928e89837e79736e6963605950483f34291d1105000000060f1820262b2e2f39393939393939393939392e2d2a251f170e0500050e161e252a2d2e39393939393939393939392e2d2a251f170f050000000000000000000000000002090e12181c1f202426282928272522211e1a1516172020202020202020201414110e080200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070c101313171a1d1e1f1e1d1b181413111214151919191919191919191413100d07010000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504653606c7884919daab4bfb9ada1978b7f72665c5044382b1f1207000000000000050c12171b1d1e202020202020202020202020202020202020202020202020202020201c1b18140f09020000000000000000000000000000000000000000000000000000050f1820282f33373839393939393939393939393939393939393939393939393939393938353029221910060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050f1820282f3337383939393939393939393635322d261f160d141d242b30333439393939393939393939392f2e2b2720191007000000000000000000000000000002080d151a1d24292c2d303335373838383735322f2d2b27221b19130c060000000000000000000000000000000000000000000000000000000000000000000000020b151d252c31343538383838383838383735322d271f160d0000000000000000000000000000030506090b0d0e0e0e0d0b0907060300000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000000020c16202c353f49515b626b6f787f84888c8f919293999291908d8a86817b736c665d554b43392f241b0d040000000000000000020a11171b1f2020202020202020202020202020202020202020202020202020202020201f1c17110a03000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000b1825313e4b5864717e8b97abb4bfcbcfc2b5a89c8f827569554c4135404b556875828f9ba8b5c2cecfbfb2a5998c7f7266594c3f2f24190d010000000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d8a97a3abacb1b8b5aeaca79f9d97918c86817c77716d67615e57544f473f362d22180c010000030e18212a31373a3b46464646464646464646463b3936302920170d020c1620283036393a46464646464646464646463b3a36302921170d020000000000000000000000050d141a1d23292c2d303334353534322e2d2b261f22232d2d2d2d2d2d2d2d2d21201e19140d0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406070a0e10111211100e0b0706040507080d0d0d0d0d0d0d0d0d0706040100000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504d5763707d8996a0acbcbfb4aa9e9285796d60544a3f34281c10030000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d282725201a130c03000000000000000000000000000000000000000000000000010c16202a323a3f434546464646464646464646464646464646464646464646464646464544413b342b22180d02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c16202a323a3f434546464646464646464643423e3831281f0c1d262f363c3f4146464646464646464646463c3b37322b22190f04000000000000000000000000040c131920262b2f35393a3d40424445454443423f3c3937332d29251e17110a0300000000000000000000000000000000000000000000000000000000000000000009131d272f373d4042454545454545454543423e3831281f10060000000000000000000000060b0f121315181a1b1b1b1a18161312100c060000000000000000000000000000000000000916232f3c4956626f7c8995a2afb2b2a99c908376695d504336414e5b6874818e9ba7b2b2b1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000040e1a232d373f49515960666d72777c7f8284858686868583807d7a746e69605b544b433a31281d12090000000000000000020b141b22272b2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c28231c150c070000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000030f1c28333f4a546774808d9aa7b3c0d1d1c4b7ab9e918478675d51453945515d677784919eaab7c4d1cec1b5a89b8e827568554c4135291d11040000000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d8a97a3b5b8b3adaba39f9b95908a85807b756f6b64605c55524d48433d352d241b11060000000915202a333c43474853535353535353535353534746413b32291f1408131e28323a41464753535353535353535353534846423b33291f140900000000000000000001090f171f252a2f34383a3d40414242413e3b3a37312c2f303939393939393939392e2d2a251e170e05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50535f6975828f9ca8b2bdbaaea2988c8073675d5142382e23170b0000000000050f1820282f333738393939393939393939393939393939393939393939393939393939393534312c251e150c02000000000000000000000000000000000000000000000007121d28323c444b5051535353535353535353535353535353535353535353535353535352514c463d34291f130800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d28323c444b5051535353535353535353504e49423a3126151e2f3841474c4d53535353535353535353534947433c342b20150a0000000000000000000000070e161e24293137394045474a4d4f51515251504e4c4946443f38353028231c150c0500000000000000000000000000000000000000000000000000000000000000040f1a252f3941484d4e5151515151515151504e4a433a3122180e040000000000000003090e11171b1f20222526272827272523201f1c17110f0a040000000000000000000000000000000916232f3c4956626f7c8995a2a6a6a6a69c908376695d504336414e5b6874818e9ba6a6a6a6a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000008111b252d373f474f545c60656a6f73757779797979787674716d67615e57504a423a31281f160c0000000000000000000a141d262d3337393a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a38342e261e19100700000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000006121f2b3844505b667683909ca9b6c3cfd2c5b9aca196877a6d6054473a4753606d7a86939facb9c6d2d1c4b7aa9e918477675d5145392c2013060000000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d8a97a3b1aba9a19e99928e89837e79736e6863605953514b46423b38322b231b1209000000020f1a26313c464e5355606060606060606060605f54524d443b3025190e1925303a444c52545f6060606060606060605f54524d453b30251a0e0200000000000000020a131b21293036394045474a4d4e4f4f4e4b4847423c383c3d4646464646464646463b3936302920170d02000000000000000106090b0c131313131313131313130a09070400000000000000000000000004090d0f0f131313131313131313130706040000000000000000000000000000000306070f1010101010100e0d0b0703000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c4b55616e7b87939facb9c0b5ab9f92867a6d61554b4030261c110600000000010c16202a323a3f43454646464646464646464646464646464646464646464646464646464642403d372f271e130900000000000000000000000000000000000000000000000b17232f3a444e565c5e60606060606060606060606060606060606060606060606060605f5d574f463b3024180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17232f3a444e565c5e6060606060606060605c5a544c42382d1d2730414a52585a606060606060606060606055544e463c32271b0f03000000000000000000081019202830353c43474b5153575a5c5d5e5e5e5d5b595653504946413a342e261e170e060000000000000000000000000000000000000000000000000000000000000814202c37414b53595b5e5e5e5e5e5e5e5e5d5b554c43342a20150a000000000001070d141a1b22272b2d2f313334343433322f2d2c28231c1b150d0802000000000000000000000000000916232f3c4956626f7c8995999999999999908376695d504336414e5b6874818e999999999999978b7e7164584b3e3125180b0000000000000000000000000000000000000000000009131b252d353d424a515358606266696a656c6d666b696764605d55534d443f382f281f160d04000000000000000006111b262f383f44464646464646464646464646464646464646464646464646464646464646443f38302b22190f04000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000613202d394653606c7985929facb8c5d2d5c9bdb2a896897c6f6356493c4956626f7c899aa4afbbc8d4d2c6b9ac9f93867a6d6054473a2d2114070000000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d8a97a3a79f9d97918c86817c76716d66615e56544f4645403936302c27211910090000000006121f2b37434e585f626c6c6c6c6c6c6c6c6c6c6c615e564d41362a1c111d2a36414c565e616c6c6c6c6c6c6c6c6c6c6c615e574d42362a1e1205000000000000010a141c252d333b42464b515357595b5c5b5a5855534d4644484a5353535353535353535346413b32291e1408000000000000060d1215181920202020202020202020171613100b05000000000000000002091015191b1c202020202020202020201413100c070100000000000000000000060c1012131c1c1c1c1c1c1c1a1a17130e080100000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c515d6773808d99a4afbbbbafa3998d8174685e5243392f1e140a000000000007121d28323c444b5051535353535353535353535353535353535353535353535353535353534f4d4841392f251a0f04000000000000000000000000000000000000000000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6961574c4135281c100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c69665e54493e32232e3942525c64676c6c6c6c6c6c6c6c6c6c6c6260584e43372b1f1306000000000000000008111a222b323a41464e53555d606366686a6b6b6b6a686562605b53524c443f38302920180f0600000000000000000000000000000000000000000000000000000000000c1825313d48535d65686b6b6b6b6b6b6b6b6a665e55463c32261b0f03000000040c13181f262a2d3337393c3e40414141403e3c3a38342e2b262019130d050000000000000000000000000916232f3c4956626f7c898c8c8c8c8c8c8c8c8376695d504336414e5b6874818c8c8c8c8c8c8c8c8b7e7164584b3e3125180b000000000000000000000000000000000000000000000109131b232b30394044464e5455595c535b60605c545d5a5753514b46423b332d261d160d040000000000000000000b17222d38414950535353535353535353535353535353535353535353535353535353535353504a423c342b20150a000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000815222f3b4855626e7b8898a2aebac6d3dacebeb1a4988b7e7165584b3e4b5865717e8b98acb6c0ccd8d4c8bbafa49a897c6f6356493c302316070000000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d8a979f9b95908a857f7a756f6a64605c54524d48433d38342e2a251f1b160f0700000000000814212e3a47535f6a6e79797979797979797979796e685e5246382e2317202d3946525e686d79797979797979797979796e695e52463a2d2014070000000000000a131c262e373f454d52555c6063666768686765615f57535154566060606060606060605f524c443b3025190e02000000010911181e2224252d2d2d2d2d2d2d2d2d2d2322201c160f08000000000000030c141b212528292d2d2d2d2d2d2d2d2d2c201f1c18120b0300000000000000030a11171c1f20292929292929292726241f1a130b02000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c53606d7985929fabb5c0b9ac9f92877b6e61564c4131271d0c0200000000000b17232f3a444e565c5e606060606060606060606060606060606060606060606060606060605b59534b41372c20140800000000000000000000000000000000000000000000111d2a3743505c68727879797979797979797979797979797979797979797979797979797873695d5144382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111d2a3743505c6872787979797979797979797670665a4e42352834404b54646e747979797979797979797979766a6054473b2e2215080000000000000008111a232c343d444c52585f62676d707375777878777675726f6c65615e56504a423b322a21180f06000000000000000000000000000000000000000000000000000000010e1b2734404d59656f757878787878787878767166584e43372b1f13060000060d161d24293136383f4446484b4d4e4e4e4d4b4946443f3837322a251e170e0700000000000000000000000814212e3b4754616e7b7f7f7f7f7f7f7f7f7f7e7164584b3e313d4a5763707d7f7f7f7f7f7f7f7f7f7c6f6255483c2f2215090000000000000000000000000000000000000000000000000910191e272e34383c4347494c4f49505353504a504d4a47454039363128221c140b04000000000000000000030f1b27333f49535b6060606060606060606060606060606060606060606060606060606060605c544e463c32271b0f030000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000b1824313e4b5764717e8a97aab4bfcad6dacdc0b3a79a8d8074675a4d414d5a6773808d9aa6b3c0d2ddd8ccc0b6ac988b7f7265584c3f2e23180c0000000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d8a99928e89837e79736e6862605853514b46413b38322c28231d1a140f0a040000000000000815222f3b4855626e7b88868686868686868686877a6e61544a3f34281c27333f4953616d7a86868686868686868686877b6e6154483b2e2115080000000000060f1c252e38404951575e61676d707374757574716e6964605c60636c6c6c6c6c6c6c6c6c6c5e564c41362a1e110500000009131b23292e313239393939393939393939302f2c272119110800000000020c151e262c313536393939393939393939392d2c29231d150d030000000000030c151c23282c2d363636363636363433302b241d140b000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5965727e8b97a2adbdbbb0a69b8e8175695f53443a301f150b0000000000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c68655d53483d3125180c00000000000000000000000000000000000000000000121e2b3845515e6b7884868686868686868686868686868686868686868686868686868685786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b78848686868686868686868276695c5043362c3845515c66748086868686868686868686867c6f6255493c2f221609000000000000060f1a232c363e464f565d616a6e74797d80828484858483817f7c78736d68605c544d443c332a21180d040000000000000000000000000000000000000000000000000000020f1b2835424e5b687581848484848484848483766a5f53473b2e21150900060f181f282f353b42464950535558595a5b5a5a585653504a47433c36302920191007000000000000000000000714202d3a46525e696e737373737373737373716c6156493d303c4855616b707373737373737373736f6a5f53473a2e21150800000000000000000000000000000000000000000000000000070c151c23282c32373b3c40423f444646443f43413e3a39352f2a251f17110a020000000000000000000005121f2b3744505b656c6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6660584e43372b1f13060000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000010d1a2734404d5a6773808d9aa6b3c0d0dbdccfc2b6a99c8f837669564c414c566976828f9ca9b5c2cfdcddd2c1b4a79b8e817468554b4034281c100400000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d8a8c86817c76716d66615e56544e4645403936302c271f1c18120e090200000000000000000814212e3a47535f6a76828f93939393939393998c7f73665c5044382b1f2b3744505b65727f8c98939393939393938e8175695e52463a2d20140700000000030e18212d37404a525b62696e74797d80818282817e7b77716d666b7079797979797979797976685e5246392d201407000006111b252d343a3e3f464646464646464646463d3c38332b23190f0500000009141e2730373d4142464646464646464646463a38342f271f150b01000000000a151e262e34383a42434343434343413f3c362f261d0f060000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c606b7783909da9b3beb7ab9f94887c6f62574d4232291e0d03000000000000111d2a3743505c68727879797979797979797979797979797979797979797979797979797979756f65594d4034271b0e00000000000000000000000000000000000000000000121e2b3845515e6b7884919393939393939393939393939393939393939393939393939285786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b788491939393939393938f8376695c5043362d3a4653606d79859293939393939393939083776a6054473b2e2215080000000000030c18212c353e48505960686d747c81858a8d8f90919191908e8c8984807a726d665e564e463c332a1f160c0100000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c91919191919191887c6f6255493c31261a0e060f18212a313a41454d53535b60626466676767666562605c54534e46413a322b2219100700000000000000000005111e2a36424d575e6166666666666666666664615a5045392d38444f596163666666666666666666625f584e43372b1f12060000000000000000000000000000000000000000000000000000030b12181c1f272b2e2f332d3337393a38342e34312d2c29241d1a140b060000000000000000000000000613202d394653606c787979797979797979797979797979797979797979797979797979797979766a6054473b2e2215080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000005121e2a36424d576976828f9ca9b5c2cfdcded1c5b8ab9e928578685e5246525e687885919eabb8c4d1deddd0c3b7aa9d908477675c5145382c1f130600000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000a1724313d4a5764707d847f7a746f6a64605c54524c47433d38342e2a251f1b16100c07000000000000000000000006121f2b37434e5863707d8a95a09f9f9f9f9f9e9184786d6053463b31262d394653606c7884919e9f9f9f9f9f9f95897c6f62574d42362a1e1205000000000915202a333f49525c646d727b81868a8c8e8f8e8d8b88837e786e707d8686868686868686867a6e6154473b2e21140800010d18232d373f464a4c535353535353535353534a48443d352b21160b000004101b26303942494d4f535353535353535353534745403931271d120700000006111c2630383f44464f4f4f4f4f4f4f4d4c4740382f21180e0300000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696363707d8995a0acbbbcb1a79c8f82766a6054453b3120170c00000000000000121e2b3845515e6b7884868686868686868686868686868686868686868686868686868686868175685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919e9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9285786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919e9f9f9f9f9f9c8f8376695c50433636414c5664707d8a97a19f9f9f9f9fa2988b7e7165584e43372b1f130600000000000a151e2a333e47505a616b6f7a81878e9298999b9d9e9e9e9d9b9896918c867f786e695f584e453b31281e130800000000000000000000000000000000000000000000000000000815222f3b4855626e7b88969e9e9e9e9e998c807366574d42372b1e120d18212a333c434b51575f61656c6f717374747473716f6d66625f58524c443d342b23190e050000000000000000020e1a25303b454d5254595959595959595959585650483e3428333e474f555759595959595959595955534e463c31261b0f0300000000000000000000000000000000000000000000000000000000070c10151b1f22222622272b2d2d2c2823272420201d18120e0903000000000000000000000000000a1724313d4a5764707e86868686868686868686868686868686868686868686868686868686867c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000714212d3a46535e697885929eabb8c5d1dedfd2c6b9ada197877a6e61544754616d7a8797a1adb9c6d2dfdfd2c5b9ac9f9286796d6053463a2d20130700000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000714212d3a4754606d7a79736e6862605853514a46413b37322c28231d19140f0a0400000000000000000000000000020f1a26313c4653606c7884919da9b3acacada1968a7d7063574d42362a36424d5763707d8996a0acacacb2a89d9083766a6054453b30251a0e02000000020e1a26313c45515b646e737f868e9298999a9b9b9a9895908b837b707d8993939393939393877a6e6154473b2e2114080006121e29343f495156586060606060606060606056544f473d33271c1004000915212c37424c545a5c6060606060606060605f53514b43392f23180c0000000c17232e38424a50535c5c5c5c5c5c5c5a58524a40332a1f150900000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f837670707075828f9ba7b1bcb8aca095897d7063584e43332a1f0e0500000000000000121e2b3845515e6b78849193939393939393939393939393939393939393939393939393938e8175685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabacacacacacacacacacacacacacacacacacacacacab9f9285786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabacacaca99c8f8376695c5043363946525e6875828f9ba9b3acacacab9f92857a6d6053473c32271b0f030000000006111c26303c454f59616c707d848e939a9fa2aaa8aaababaaa9a8a8a19e98928c827b6e6a5f574d433a2f24190d05000000000000000000000000000000000000000000000000000814212e3a47535f6a7784919eaaababaa9d918477695f53473a2e2114151f2a333c454d555d60696e74787b7e80818181807e7c79746f6a615e564e463d352b20170b02000000000000000009141f29333b4246474c4c4c4c4c4c4c4c4c4b49453e362d222c353e44484a4c4c4c4c4c4c4c4c4c4847433c342a20150a00000000000000000000000000000000000000000000000000000000000000040a0f13151619171b1f20201f1c171a171413100d07010000000000000000000000000000000a1724313d4a5764707d8a939393939393939393939393939393939393939393939393939393887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000815212e3b4854616e7b8797a1adb9c6d2dfded5c9beb3a996897d7063564a5663707c8996a9b3bec9d5dedfd3c7bbafa399887c6f6255493c2f22160600000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000613202c3945525d686d6d66615e56544e4644403936302b271f1c18120e08020000000000000000000000000000000009151f2b3744505b65727e8b97a2adbabdb2a89c8f8275695f5346392e3a46525e6975828f9ba8b2bdb9ada1968a7e7164584e4333291f14090000000006121e2b37424e57636d73808c92989fa2aaa7a8a8a7a7a09d9590857c7d89969f9f9f9f9f94877a6e6154473b2e211408000915222e3a46515b62656c6c6c6c6c6c6c6c6c6c6360594f44382c201307000d1925313d49545e65696c6c6c6c6c6c6c6c6c6c6a5c554b4034291c10040003101c28343f4a545c606969696969696967645c52453c31261a0e00000000000000000000000000000000121e2b3845515e6b7884919eabb7c3b7aa9d90837d7d7d7d7d87929facb9bdb2a89d9083776b6155463c3221180c0300000000000000121e2b3845515e6b7884919e9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b8ab9f9285786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7b9b6a99c8f8376695c5043363a4754616d7a86929facb9b9bcb1a79a8d8174675d5145392b20150a00000000000c17232e38424e57616b707e8791969fa4acaeb4b5b7b7b8b7b6b4b2acaaa29f9490847c6e695f554c41352921160b0000000000000000000000000000000000000000000000000006121f2b37434e586773808d9aa9b3b7aca095887b6e6255483b31251a1d27313c454d575f676d747b8085888b8c8d8e8d8d8b8985817c756d6860584f473d32291d140a0000000000000000020d17202930363a3b4040404040404040403e3d39342d241b232c33383c3d4040404040404040403c3a37312a22180e0400000000000000000000000000000000000000000000000000000000000000000003060809060b0f12131312100c060b0706040100000000000000000000000000000000000a1724313d4a5764707d8a97a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a095887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000a1724313d4a5764707d8a97a9b3becad5d2d1d2cfbfb2a5988c7f7265594c5865727f8b98a5b2becfd2d1d2d5cbc0b5ab988b7e7165584b3e2d22170b00000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000004111d2935414c565d60605c54524c47433d38342e2a251e1b16100c0700000000000000000000000000000000000000030f1b27333f4953606d7985929fabb5c0b9ac9f93877b6e61544b40343f4a54616e7b86929facb9bfb4aa9e9184796d6053463d3220170d02000000000814212e3a47535f6a727f8c929fa2aaaeb4b4b5b5b4b1aca79f9792857e8b98a5acacaca194877a6e6154473b2e211408000b1824313e4a56626d7279797979797979797979706b6054483c2f221606000f1b2835414d5a6570757979797979797979797975675c5145382c1f13060006121f2c3844505c666d75767676767676746e64574d42372b1d1207000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8aca09590898989898a9299a3afbbb9ada1968b7e7164594f413a31281e150b00000000000000121e2b3845515e6b7884919eabacacacacacacacacacacacacacacacacacacacacacaca89b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c6cdc8c4c3bbbbbbbbbbbbbbbbbbbbbbbbb8ab9f9285786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504337434e5865727f8b99a3aebbc4b8ab9f95887c6f62554b403529190f040000000003101c28343f4a545f6a707d879299a1a9afb6babfc2c0bebdbec1c1bdb9b4aea69f9691857b6e675d51453d32271c1004000000000000000000000000000000000000000000000000020f1a26313c4956636f7c8997a1adb9b1a7998c7f7266574d42362a1e232f39434d575f696e7980878d919797999a9a9a999897928e88817a6f6a60594f443b2f261b11060000000000000000050e171f252a2d2e33333333333333333331302d28221b121a21282c2f303333333333333333332f2e2b2620181006000000000000000000000000000000000000000000000000000000000000000000000000000000000305060706030000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3acacacacacacacacacacacacacacacacacacacacacacaca295887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000d1a2633404d596673808c99a6b3bfcfc9c6c5c6c9c1b4a79a8e81746753495a6774818d9aa7b4c0c9c6c5c6c9cfc0b4a79a8d817467544a3f33281c0f03000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000010d19242f3a434c525453514a46413b37322c28231c19140f0a04000000000000000000000000000000000000000000000b17222d3845515d6773808d99a3afbbbbafa4998d8073665c51453844505c6673808c99a3afbbbaaea2988c7f72665c5044382c1f12050000000005121e2a36424d57626e7b86929fa4aeb4babfbfbab8b4b2b1b1a9a2979285929fabb8b9ada194877a6e6154473b2e211408000c1925323f4c5865727f868686868686868686867d7063564a3d2d22170b05121e2b37424d5769758286868686868686868687796d6053473a2d201407000713202d3a4653606d78828282828282828074695f5347392e23180c000000000000000000000000000000121e2b3845515e6b7884919eabb7c4bcb1a7a09d96969696979fa3abb5c0b7ab9e9184796d605b534b433a30271d1207000000000000121e2b3845515e6b7884919eabb7b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b5a89b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cbc3bcb8b6aeaeaeaeaeaeaeaeaeaeaeaeaeab9f9285786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433a47535f6a7783909dabb5bfbeb3a99d9083766a5f53433a2f241807000000000006121f2c3844505c666e7c869299a3abb2bbc0bdb9b8b3b1b0b1b4b8babfbfbab0a8a19791847a6d60594f44382c21160a000000000000000000000000000000000000000000000000000a13202d3a4653606d7985929eabb8b6aa9d908377695e53463a2d212934404b555f696e7b848d92999ea1a9a6a7a7a7a6a9a29f9a938e847c6f6b60564c41382d22170b000000000000000000050d141a1e20212626262626262626262524211d17100910171c20232426262626262626262622211f1b150e0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9afa295887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000005111d2a36414c566975828f9ca8b5c2c5beb9b8b9bec3b6a99d908376655b5057697683909ca9b6c3beb9b8b9bec5c3b6a99d908376665b5044382b1f1206000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000008131e28313a4145474644403936302b271f1c18120e080200000000000000000000000000000000000000000000000006111b2935404b55616e7b87929facb9c0b5ab9e9285796d6053463c4653606d7884919eabb5c0b8ac9f92867a6d61544a3f34281c1003000000000714212d3a46535e6976828f98a3aebabfc2bcb4aeaca8a5a4a6a9a9a2979297a2adbabaada194877a6e6154473b2e211408000916222f3c4955626f7c8897939393939393938c7f736653493f33271b0f0714212d3a46535f6978859293939393939393908376675c5145382c1f13060006121f2c3844505c6676838f8f8f8f8f8f877b6e61554b4034281c10040000000000000000000000000000121e2b3845515e6b7884919eabb7c4c3b9b1acaaa3a3a3a3a3acafb5bdc3b6aa9d90837b736c655d554b43392e23180e040000000000121e2b3845515e6b7884919eabb7c4c6ccc7c3c2bbbbbbbbbbbbbbbbbbbbbbbbbbbbb5a89b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c3b9b1abaaa2a2a2a2a2a2a2a2a2a2a2a2a2a29f9285786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433f4a54626f7b8895a0abbdc6baada2978b7e7165584e4331281d13070000000004101d2935404b55606d78839098a2abb4bdc0bbb2adaba6a4a3a5a7acaeb4bcc1bab2a9a0968e81746b6054483d32271b0f0000000000000000000000000000000000000000000000000006121f2b3844505c6674818e9baab4b8ab9f95877b6e6154483b30252c3845515c676e7b8591969fa3abadb3b3b4b4b4b3b3adaba59e9691867d6f685e53493f33271b110600000000000000000002090e111414191919191919191919181715110c0600050b101416171919191919191919191515120f0a0400000000000000000000000000000000000000010406070a0d0f0f0f0e0c0906050300000006060606060606060600000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3adadadadadadadadadadadadadadadadadadadadadadada295887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000713202d3946525e687884919eabb8c4bbb3adabadb3bbb8ac9f9285796c60535e697885929fabb8bbb3adabadb3bbc5b8ac9f9285796c605346392d201306000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000010c161f282f35393a3a38342e2a251e1b15100c07000000000000000000000000000000000000000000000000000000000d18242f3946525e6975828e9ba7b1bcb9ada1978a7e7164584e434d5764707d8a96a1adbdbbb0a69a8e8174685e5242382e23170c00000000000815212e3b4854616e7b87939faab4bfc2b8b0aaa29f9b9898999c9fa6a29fa2a9b3bebaada194877a6e6154473b2e211408000613202d394653606c7985929f9f9f9f9f9f9c8f8276655b5044372b1f120815222e3b4855616e7b8897a19f9f9f9f9f998d807366554b4034291c10040003101c28343f4a5466737f8c999c9c9c9a8d8073675c5145382c1f15090000000000000000000000000000121e2b3845515e6b7884919eabb7c4cbc3bcb8b7b0b0b0b0b0b9bbc0c7c4b8ab9f9590867f776d675d554b40342820160c0200000000121e2b3845515e6b7884919eabb7c4cac2bbb7b5aeaeaeaeaeaeaeaeaeaeaeaeaeaeaea89b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4bcb1a79f9d9595959595959595959595959595959285786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504344505c6673808d9aa7b1bcc5b8ab9f9285796d6053473c3220160c010000000006131f2c3945515d67727f8b959faab4bdbdb5afa8a19e999796989b9fa3aaafb7c1bbb2a89d93897d7063594f44382c1c110600000000000000000000000000000000000000000000000003101c28343f4a5464707d8a98a2aebab1a7988b7f7265564c41362b37434e58606d79839097a0a8afb5b9b7b6b2b1b2b5b9bab8afa9a19892857a6e655b5044382d22170b0000000000000000000000020507080d0d0d0d0d0d0d0d0d0b0a0805000000000004070a0a0d0d0d0d0d0d0d0d0d090806030000000000000000000000000000000000000001070d111314171a1b1c1c1b191513120f0b060a13131313131313131308070502000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a095887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000714212e3a4754616d7a8796a1adb9beb3a9a19ea1a9b3baaea298887b6e6155616e7b8797a2adbab3a9a19ea1a9b3bebaaea298887b6e6255483b2f221508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000040d161e24292c2d2d2c28231c19140f0a0400000000000000000000000000000000000000000000000000000000000007121d2a36424d57636f7c89959fabb8beb3a99c8f83766a5f5347535f6976828f9ca8b2bdb7ab9f94887c6f62564c4130261c110600000000030f1c28333f4a5466737f8c99a4afbcc4bab0a69f98928e8c8b8c8f949ea1a9adb3bcc5baada194877a6e6154473b2e2114080006121f2b3844505b6675828f9ca8acacacab9f9285796c605346392d20130e1824313e4b5764717e8a97a9b3acacafa4998a7d7063574a3d2f23180c0000000c17232e3c4955626f7c8897a1a9ac9e9285796d6053463c31261a0e0000000000000000000000000000121e2b3845515e6b7884919eabb7c4d1cec8c5c3bcbcbcbcbdc4c5c6cac8bcb1a79f98928c82796d675c51453e32281e130800000000121e2b3845515e6b7884919eabb7c4c2b8b0aaa9a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a29b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8ab9f95908888888888888888888888888888888885786c5f5245392c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50434653606d7984919eabb8c3bcb1a79a8d8074675d5145392c1f130400000000000714202d3a4753606d7985929ea7b1bcc0b5aba39f96918d8b8a8b8e92989ea5afb7c1baafa59d9083776b605448382e23170b000000000000000000000000000000000000000000000000000b17232e3a4753606d7985929facb8b6a99c908376685e5246392e3b4754606a74808d95a0a9b2bbbab0aba9a6a4a5a8acaeb4bbb2aaa1978f82776c6053493f33271b0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e13181d20212426282928272522201f1b1716172020202020202020201414110e080200000000000000000000000000000000000000000a1724313d4a5764707d8a939393939393939393939393939393939393939393939393939393887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000a1723303d4a5663707d8996a8b2bdb9ada1979297a1adb9b4aa978a7d70645763707d8a96a9b3b9ada1979297a1adb9bfb4aa978a7e7164574b3e31241809000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000040c13191d2021201f1c18120d08020000000000000000000000000000000000000000000000000000000000000000010e1a25303b4854606b7683909da9b2bdb7ab9f94887b6e62554b55616e7b87939facb9bdb2a89c8f82766a5f53443a301e150a000000000006121f2b3844505b667683909dabb5c0bdb2a89f949086817f7e7f82899297a1acb6c0ccbaada194877a6e6154473b2e21140800030f1c28333f4a5466727f8c99aab4bfbaada297887b6f6255483c2f221b1b1c2934404b556774808d9aa7b3b9b9ac9f93867a6d6054473a2d2114070000000613202d394653606c7885929eabada1978a7e7164574d42372b1d120700000000000000000000000000121e2b3845515e6b7884919eabb7c4cec6bfbab8b7b7b7b7b7b7b8babfc5c3b9b1aaa39f938f82796d605a50443a3024190d01000000121e2b3845515e6b7884919eabb7c4bbb0a69e9c95959595959595959595959595959595958e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c3b6aa9d90837c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7c6e6255483b2f221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50414c5663707d8997a1adb9c4b7ab9f95887c6f62554b4035291d10040000000005111e2a36414c5665717e8b97a1adb9c3bbafa399928c84807e7d7e81868f939da5afbbc1b8ab9f95897c6f63544a3f34281c100300000000000000000000000000000000000000000000000006131f2c3845515c6775828e9babb4b9ac9f93867a6d6154473a36414c56626f7c87939fa7b1bbb4aea69f9c9998989b9fa3abb2bab3a99f948b7e71655b5044372b1f120500000000000000000000000000010406070b0e0e0c0808060200000000000000000000000000000000000000000000000000000000000000000000000000000000060e151a1d24292c2d313335363534322f2d2b272222232d2d2d2d2d2d2d2d2d21201e19140d05000000000000000000000000000000000000000a1724313d4a5764707e87878787878787878787878787878787878787878787878787878787877c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000c1926333f4c5966727f8c99a5b2bfb8ab9e9285929ea9b3b2a6998c7f73665966727f8c99a5b2b5ab9e9285929eabb8c0b3a69a8d8073675a4d4031251a0e020000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000001080d1113141312100c0700000000000000000000000000000000000000000000000000000000000000000000000009141f2c38434f5964717e8a96a1adb9bbb0a69a8d8074675d515c6773808d9aa4afbbb8aca0968a7d7063584e4332281e0c0300000000000613202d394653606c7985929facb8c5b9aca09690827b75727173767d85929aa4afbbc8baada194877a6e6154473b2e21140800000b17222d3c4956626f7c8998a2aebabeb3a9988b7e7165584b3e30242727272c3845515c677783909daab6c3b7aa9d908477685d5245392c20130700000005121f2b3744505b6575818e9ba8b3a99c8f8376695f5347392e23180c00000000000000000000000000121e2b3845515e6b7884919eabb7c4c6bcb4aeacaaaaaaaaaaabacaeb4b8babebcb4aea69e948e81756c61564c4135291d1207000000121e2b3845515e6b7884919eabb7c4b7aa9e948f8888888888888888888888888888888888888175685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f83766f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e6a5f53473a2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5045525d6875818e9ba9b2bebeb3a99d9083766a5f5343392f24180c00000000000714202d3946525e687683909ca9b3bebbb0a69f92877f7973717072747a818e939da9b3bebcb1a79b8e8174665c5044382b1f120600000000000000000000000000000000000000000000000004101c2934404b5564717e8a99a3aebaafa4998b7e7165564c413946525e6875818e9aa4afb9b4aaa29f94908c8b8c8e9299a0a8b2bbb0a69d9184786c605346392d201309000000000000000000000001070d101314181a1b191514120f0903000000000000000000000000000000000000000000000000000000000000000000000000010a0f1820262b2f35393a3d40424242413f3c3937332d2f303939393939393939392e2d2a251e170e050000000000000000000000000000000000000713202d3a4653606d787a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a796d6053463a2d2013070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000004111d2935414b556875828e9ba8b5c0b4a79a8d818d97a1adb5a89b8e827568546875818e9ba8b4afa3998d818d9aabb5c0b6a99c8f827669574d42362a1e12050000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000010406070706040000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27323d4653606d7984919eaab4bfb8ab9f9285796d6053606d7985929eacb6beb3a99d9184786c6053463c3120160c0000000000000815222f3b4855626e7b8898a2aebabfb4aa9e9184796e696565666b6f7c88939facb9c6baada194877a6e6154473b2e21140800000613202d3a4653606d7985929facb8c1b4a79b8e817468564c413534343434343a4753606d7986929facb9c0b4a79a8d817467564c4135291d1104000000030f1b27333f495364717e8b97a7b1ab9f94887b6e62554b4034281c1004000000000000000000000000121e2b3845515e6b7884919eabb7c4bfb4aaa29f9d9d9d9d9d9e9fa2aaabaeb4bcbfbab0a69e938a7e71685d5246392f24180c000000121e2b3845515e6b7884919eabb7c2b5a99c8f827c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e6154483b2e21150800000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696262626262626262626262626262625f584e43372b1f1206000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504754606d7a86929facb8c4baada2978b7e7164584e4331271d120700000000000814212e3b4754616e7a86939facb9c5b7aa9e948a7e726d66646365686d77818e97a1adb9c3b8ab9e9285796d6053463a2d201307000000000000000000000000000000000000000000000000000c18232f3a4754606d7a86929facb9b5ab9c8f8276685d52453b4754616e7a86929facb6baaea298928a837f7e7f82869196a0abb5b8aca095897d7063564a3d30251a0e02000000000000000000040c12181d20202427272622211f1a150c0701000000000000000000000000000000000000000000000000000000000000000000020b131c212a31373a4145474a4d4e4f4f4e4c4846443f383c3d4646464646464646463b3936302920170d02000000000000000000000000000000000006121f2c3844515c666d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d665c5044382b1f12060000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000613202c3945515d677784919eaab7bfb4aa978a7d85919eabb7aa9d908477665c667783909daab6ac9f92867c8999a4afbbb8ab9e928578695e53463a2d2114070000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a161f2c3844515c66737f8c98a3aebabaada2978b7e71655864717e8a97a1adbebaada2978b7f72655b5044372b1f12040000000000000a1724303d4a5763707d8a96aab4bfbaaea3988b7e71675e565859606b75828e9ba8b5c1baada194877a6e6154473b2e211408000006121f2c3844515c6676838f9ca9b6c2b7aa9d918477685d5246414141414141414956636f7c8999a3aebbbdb2a8978a7e7164574b3e2f24190d01000000000b17222d3b4754616e7a8795a0acb0a69a8d8073675c5145382c1f1509000000000000000000000000121e2b3845515e6b7884919eabb7c4baaea298929090909090919298999fa2aab1b9c1b8afa59e92857a6d61554b4035291d10040000121e2b3845515e6b7884919eabb7c1b5a89b8e82756f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e695e52463a2d20140700000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5555555555555555555555555555534e463c31261a0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504d5765717e8b98a3aebac5b8ab9f9285796d6053473c3120150b0100000000000b1724313e4a5764717d8a99a4afbbbfb4aa9c8f82766c605c5457565e656d7a85929eabb8c5b9ada297887c6f6255483c2f221509000000000000000000000000000000000000000000000000000713202c3945515d6775828f9cabb5b9ac9f92867a6d6054473f4b5865727e8b99a3aebeb1a79f92867d76737172757b849199a3aebbb1a79b8e817568574d42362a1e12050000000000000000080d161d24292c2d313434332f2e2b262018120b0300000000000000000000000000000000000000000000000000000000000000010b141d252e333c42474b515457595b5c5b5a585553504945484a5353535353535353535346413b32291e1408000000000000000000000000000000000004101c2834404a545c606060606060606060606060606060606060606060606060606060606060605c544a3f34281c10030000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000714212d3a4754606d7a86939facb9baaea298887b828f9ca9b5ac9f9286796d606d7986929facb7aa9d90847986939facb9b9ada297877b6e6154483b2e2115080000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404a54616d7a86929facb8beb3a99d9083776a606a7683909ca9b3beb5ab9f9285796d6053493f33271b0f030000000000000b1824313e4b5764717e8a97a4b1bdb9ac9f92867a6d60554d4b4f5964707d8a97aab4bfbaada194877a6e6154473b2e211408000004101c2834404a546673808c99abb5bfb9ac9f93867a6d61544e4e4e4e4e4e4e4e4e5965727f8c98abb5bfb9aca196877b6e6154483b2e21150800000000000614202d3946525e687784909daab7ab9e9285796d6053463c31261a0f010000000000000000000000121e2b3845515e6b7884919eabb7c4b8ac9f928683848484848485888d92989fa7b1b9c1b9ada2978c7f73675d5145382c1f13060000121e2b3845515e6b7884919eabb7c1b5a89b8e82756862626262626262626262626262626262615e574d42362a1e120500000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504848484848484848484848484847433c332a20150900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50535f697683909caab4bfbcb0a69a8d8074675d5145382c1f13030000000000000d1a2733404d5a6673808d99abb5c0baaea398897d70635a504a4a4c535d6873808d99a6b3c0beb3a9988b7e7165584b3e3225180b0000000000000000000000000000000000000000000000000004111d2935414c5565717e8b99a3afbbaea3998a7e7164554b414c556875818e9babb4b8aca0958a7e716b6665656a6e7c87929facb9b7ab9e918478695e52463a2d2014070000000000000008111a1f282f35393a3e41413f3b3a373129241d150d0300000000000000000000000000000000000000000000000000000000000009131d262f373f454e53555d606466686968676562605b535154566060606060606060605f524c443b3025190e020000000000000000000000000000000004101c27323d474f54565d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d55534e463c31261a0f020000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000091623303c4956636f7c899aa4afbbb8ac9f928577808d9aa7b3afa399887b6f626e7b8898a3aeb4a89b8e817784919eaab7beb3a9978a7d7064574a3d312417080000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3946525e6874818e9aa6b0bbb8ab9f95887c6f626f7c88949fabbbbbafa3998d8073675d5141382d22170b000000000000000c1825323f4b5865727e8b98a5b1beb6aa9d908377675d51433e4854616e7b8798a3aebabaada194877a6e6154473b2e2114080000000c18232e3d495663707c8999a3aebbbbafa49a8a7d70635a5a5a5a5a5a5a5a5a5a566875828e9ba8b5c1b7ab9e918478695e52463a2d201407000000000005111e2a36414d566773808d9aaab4ada1978a7e7164584e43372b1d12070000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f82777777777778797c808690959fa7b1bcbeb3a99e9285796d6053473a2d2014070000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b55555555555555555555555555555554524d453b30251a0e0200000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433c3c3c3c3c3c3c3c3c3c3c3b3a37312a21180e0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c4953616e7b88949fabbcc6b7ab9f94887b6e62554b4035291d10040000000000000f1c2835424f5b6875818e9ba8b5c1b8ac9f9286796d6053473f3d414c56636f7c8996aab4bfc0b3a6998d8073665a4d4033271a0d00000000000000000000000000000000000000000000000000010d19242f3a4754616d7a86929facb9b5ab9b8f8275675d5145515d677784919eaab7b7aa9d9083776c615958575f6a74818e9ba7b4b9ada196877b6e6154483b2e21150800000000000008121a232c31394045474b4d4e4c4847433c352f271f150c0300000000000000000000000000000000000000000000000000000000060f1b252f38414951575f62676d707375757574726f6c65605d60636c6c6c6c6c6c6c6c6c6c5e564c41362a1e1105000000000000000000000000000000000713202c38444f5960636a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a625f584e43372b1f12060000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000c1925323f4c5865727f8b98acb6c0b6a99d9083767e8b98acb6b5ab978a7e7164717d8a97aab4b2a6998c7f75828e9ba8b5bfb3a6998c807366594d403025190d0100000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121c2a36414c56626f7c88949fabb7bcb1a79a8e81746874818d9aa6b0bcb9ac9f92877b6e61554b402f261b1106000000000000000c1926333f4c5966727f8c99a5b2bfb5a89b8e827568554b403a46525e697986929facb9baada194877a6e6154473b2e2114080000000714202d3a4753606d7a86929facb9c0b6ac998d8073676767676767676767676767687884919eabb7c1b4a79b8e817468574d42362a1e12050000000000020e1925303d4a5663707d8998a2aeb3a99c9083766a5f5347392f23180c0000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f83766a6a6a6a666c6f737a839095a0acb8c2b9ada1978a7d7064574a3d2f24180d0100121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f48484848484848484848484848484846423b33291f14090000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362f2f2f2f2f2f2f2f2f2f2f2e2b2620180f060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c505b6573808c99a6b0bcbeb3a99c9083766a5f5343392f24180c00000000000000101d2a3643505d697683909ca9b6c3b7aa9d908477675c5145382f3a4753606d7a8698a2aebac1b4a79b8e8174685b4e4135281b0e00000000000000000000000000000000000000000000000000000813202d3946525e6876838f9cacb6b8ac9f9286796d60534754606d7a8796a0acb9b3a6998c8073665a504b4e5764707d8a97a3b0bdb2a8978a7d7064574a3d3124170a0000000000050e1a242c353e434b5153575a5a5955534e45403931271e150b000000000000000000000000000000000000000000000000000000030e18212d37414a525b636a6e747a7d80818282817f7c78726d676b7079797979797979797976685e5246392d201407000000000000000000000000000000000916222f3b4854606b7077777777777777777777777777777777777777777777777777777777776e6a5f53473a2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000004101c2934404b556874818e9ba7b4c0b4a79a8d81747c899aa4afb3a6998d80736673808c99a6b3b4aa978a7d737f8c99a6b2bfb5a89b8f827568564c4135291d110500000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1925303a47535f6a76828f9ca8b2bdb8ac9f92867a6d7a85929fabb8bcb1a79b8e8275695e5343392f1d140a00000000000000000d192633404c5966737f8c99a6b2bfb4a79b8e8174685b4e4136424d576b7885929eabb8baada194877a6e6154473b2e21140800000006131f2c3845515d677683909da9b6c2b6a99c8f8276747474747474747474747474747b8796a1acb9beb3a9988b7e7165584b3e30251a0e020000000000000813202d3a4653606d7985929facb8ab9f94887b6e62554b4034291c100400000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695d5d545b6062686d7983919da7b1bcbeb3a99a8e817467554b4035291d100400121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423c3c3c3c3c3c3c3c3c3c3c3c3c3b3a36302921170d020000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362922222222222222222222211f1a150e06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c53606c7884919eaab7c2b9ada2978a7e7164584e4331271d120700000000000000111e2a3744515d6a7783909daab7c2b5a99c8f827669554b40342c3945515d677985929facb8c2b5a89b8f8275685c4f4235291c0f000000000000000000000000000000000000000000000000000005111d2a36414c5665727f8b9aa4afbaaea2988a7d7064544b55616e7b8894a8b2bdb0a3978a7d7064574a3e4854616e7b8794aab4bfb1a4988b7e7165584b3e3225180b00000000020d17202c363e474f555d6064676766625f58514b433930271c120700000000000000000000000000000000000000000000000000000915202a333f49525c646d727b81868a8c8e8f8e8d8b88847f796f707d8686868686868686867a6e6154473b2e211408000000000000000000000000000000000a1623303d495663707d83848484848484848484848484848484848484848484848484848484837c6e6255483b2f2215080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000006131f2c3845515c677784909daab7c0b6ac988b7e727a86939facb5a89c8f82756975828f9ba8b5aea298887b707d8a97a9b3beb7ab9e918478685e5246392d20130700000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e2b37434e5863707d8a96a0acb9baaea2988b7f727e8b98a2aebab8ab9f95897c6f63574d4231281d0b0200000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413045525e6b7885919eabb8baada194877a6e6154473b2e21140800000004101d2935404b556673808d99abb5c0b8ac9f92868081818181818181818181818181818f9ba8b2bdb9ada197887b6e6255483b2f2215090000000000000006131f2c3845515c6775828f9ca8b5b0a69a8d8074675c5145382c1f150a00000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c514a5053565e676f7c89959fabb8c4b7ab9e918478675d5145392c20130600121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352f2f2f2f2f2f2f2f2f2f2f2f2e2d2a251f170f05000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d15151515151515151514120f090300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5563707c8996a0acb9c5b8ab9e9285796d6053473c3120150b0100000000000000111e2b3744515e6a7784919daab6b6b5a89b8f8275685c4f422f2935404b556b7885919eabb8c2b5a99c8f8276695c4f4336291c100000000000000000000000000000000000000000000000000000010d1925303b4754616e7b87939facb9b4aa9b8e8175665c5155626f7c8895a2afbbafa295897c6f6256493c4653606d798698a2aebab2a5998c7f7266594c3f3326190c0000000008141e29323e48505961676d717474726e6a605d554b42392e23180c00000000000000000000000000000000000000000000000000020f1a26313c46515b646e747f868e9299999b9c9b9a9896918c847c717d8993939393939393877a6e6154473b2e211408000000000000000000000000000000000a1724313d4a5764707d8a909090909090909090909090909090909090909090909090909090887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000714202d3a4753606d7986929facb9bbafa49a897c6f7784919eaab7ab9e918478677784919daab7ac9f9285796e7b8797a2adbab9ada196877a6d6154473a2e21140700000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f1b26313c4653606c7884919ea9b3beb4aa9d91847783909daab3beb3a99d9083776b6054453b311f160c0000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000000c18242f3d4a5763707d8a99a4afbbbaaea298928d8d8d8d8d8d8d8d8d8d8d8d8d8d8f939eaabac4b8ab9e9285796c605346392d2013060000000000000004101c2834404b5565727f8b98a8b2b8ab9f9285796d6053473c31261a0f01000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c503f44464c55606a7683909da9b6c3b9ac9f9386796d6053473a2d20140700121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423528222222222222222222222221201e1a140d0500000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100909090909090908080602000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5d6774818e9ba8b2bdbbb0a69a8d8073675c5145382c1f13030000000000000000111e2b3744515e6a7784919da9a9a9a9a89b8f8275685c4f4235242f45525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100000000000000000000000000000000000000000000000000000000814202d3a46525e697683909da9b6b8ab9f9285796d60535663707c8996a3afbbaea195887b6e6255483b44505c667985929facb8b3a69a8d8073675a4d4034271a0d000000020e1925303b44505a616b70797e80817f7b746d675d544a4034281c120700000000000000000000000000000000000000000000000006121f2b37434e58626d74808c92999fa3aba8a8a8a7a8a09e9691877e7d89969f9f9f9f9f94877a6e6154473b2e211408000000000000000000000000000000000a1724313d4a5764707d8a979d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d95887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000916232f3c4956626f7c8999a3afbbb9ac9f93867a6d75828f9ca8b5ac9f93867a6d7986929facb6a99d908376697885929fabb8bdb2a896897d7063564a3d3023170700000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a151f2b3844505b66727f8b97a2adbab8aca0958c7f8c95a0acbcb9ada1978b7e7164594f4333291f0d040000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000000714212d3a4754606d7a86939facb9bfb4aaa29f9a9a9a9a9a9a9a9a9a9a9a9a9a9a9b9ea5afbbc2b5a89b8f8275655b5044372b1f120500000000000000000c18232e3b4855626e7b8896a1acb9ada2978b7e7164584e43372b1d1207000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043383a434e5865727f8c98a5b2bfbbafa49a887c6f6255493c2f22160900121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c151515151515151515151514120e09020000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c606d7985929fabb8c4b7ab9f94887b6e62554b4034291c10040000000000000000111e2b3744515e6a7784919d9d9d9d9d9d9b8f8275685c4f42352b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c1000000000000000000000000000000000000000000000000000000005111e2a36424d5765727f8c98a7b1baada2978a7d7063545763707d8a96a3b0bbaea195887b6e6255483b3f4a5f6c7985929facb8b3a79a8d8074675a4d4134271a0e00000005111e2a36414c56616c717d858a8d8d8c8781796d665c5144392e23180c0000000000000000000000000000000000000000000000000814212e3a47535f6a727f8c929fa3abaeb4b4b5b5b4b2aca8a0999287808c99a6acacaca194877a6e6154473b2e211408000000000000000000000000000000000a1724313d4a5764707d8a97a3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa295887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000b1825323e4b5865717e8b98abb5c0b7aa9e9184776773808d99a6b3afa49a897c6f7c8899a3afb4a79a8e8174697683909ca9b6bfb2a5988c7f7265594c3f2f24180d01000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c28333f4a54606d7a85929fabb5bcb1a79f9386939fa7b1bcb4aa9e9185796d6053463d3220170d000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000000613202c3945525d687783909daab7c3bcb4aeaca7a7a7a7a7a7a7a7a7a7a7a7a7a7a8aaafb7c1bfb4aa988c7f726553493f33271b0f0300000000000000000714212e3a47535f6a7884919eabb7b3a99c9083766a5f5347392f24180c000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336313d495663707c8996a3afbcc0b6ac968a7d7063574a3d3024170a00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c1b1b1b1b1b1a1916130e0807050200000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695764717e8a98a2aebabeb3a99c8f83766a5f5343392f23180c000000000000000000111e2b3744515e6a778490909090909090908f8275685c4f42352b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000000000000000000000000000000000000000000000000000000020e1a25303b4854616e7b8795a0abb8b3a99a8e8174665c5763707d8a96a3b0bbaea195887b6e6255483b46525f6c7985929facb8b4a79a8d8174675a4e4134271b0e0000000714202d3946525e68717e8791979a9a9a938e82786d60544a4034281c10040000000000000000000000000000000000000000000006121f2b37434e58626e7c87929fa4aeb4babfbebab8b3b1b0b2aba3999286929facb9b9ada194877a6e6154473b2e211408000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7afa295887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000003101c28343f4a546774818d9aa7b4c0b5a89b8f827568717e8a97abb5b6ac988b7e717e8b97abb5b2a5988b7f726774818d9aa7b4c0b4a89b8e817568554b4035291d1004000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d3845515d6773808d99a4afbbbbafa4999399a4afb9baaea3988c7f73665c5145382c1f1305000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000000004111d2935414c566774808d9aa7b3c0c6bfbab8b4b4b4b4b4b4b4b4b4b4b4b4b4b4b5b6bbc1c6baaea298897c6f6256493c2d22170b00000000000000000006121f2b37434e586774818e9aabb5b7ab9f94887b6f62554b4035291d10040000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362e3b4854616e7b8794a1aebabdb1a4978a7e7164574b3e3124180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235282828282828282625231f19120a010000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695e6976828f9caab4beb9ada1978a7e7164574e4231271d12070000000000000000000f1c2835424f5b6875818383838383838383838073665a4d40332b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000000000000000000000000000000000000000000000003050605030914212d3a46535e697783909daab6b8ab9e9285796d605763707d8a96a3b0bbaea195887b6e6255483b46525f6c7985929facb8b4a79a8d8174675a4e4134271b0e0000000814212e3b4754616e7a869299a1a9aca49f948c7f73665c5144382c1f1206000000000000000000000000000000000000000000000814212e3a47535f6a76828f99a3aebabfc2bbb3adaba7a4a3a4a8aba3999299a3aebabaada194877a6e6154473b2e211408000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1afa295887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000006121f2b3844505c667683909da9b6bfb3a6998c8073666f7b8899a3aeb3a79a8d8074808d9aa6b3b3a996897c7065717e8b98abb5c0b7aa9d918477675d5145392c201306000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c2935404b55616e7b87939facb9c0b5aba49fa4abb5c0b9ac9f92867a6d61544b4034281c1004000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000010d19242f3e4a5764717d8a97a8b2bdc8cac6bfbab8b4b4b4b4b4b4b4b4b4b4b4b6bac1c6ccc5b8ac9f9285796d6053463a2d201306000000000000000000020f1a26313e4a5764717d8a99a3afbbb0a69a8d8074675d5145382c1f150a0000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4754606d7a8793a0adbabeb1a5988b7e7265584b3f3225180c00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42353535353535353533322f2a241c130a0000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f837669616e7b87939facb9c0b6ac9e9285796d6053463c3120150b010000000000000000000e1b2734404d59656f75767676767676767676736e63584b3f322b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c1000000000000000000000000000000000020507080c060b0f1213120f0b121e2a36424d5766727f8c99a7b1b9ada197897c70635663707d8996a3b0bbaea195887b6e6255483b44505c667985929facb8b3a69a8d8073675a4d4034271a0d0000000d1a2633404d596673808c98a2abb3b6afa69f9285786d6053463a2d201307000000000000000000000000000000000000000000000815222f3b4855626e7b88949fabb5bfc2b8b0a9a29f9a9796989b9fa3a39fa3abb4bfbaada194877a6e6154473b2e211408000000000000000000000000000000000a1724313d4a5764707d8a97a3a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a295887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000713202d3a4653606d7985929facb8bfb4aa978a7d70646d7986929facb6a99c8f8376828f9ca9b5ada197877a6d626f7c8999a4afbbb9ac9f93867a6d6053473a2d201407000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d18242f3a46535f6975828f9ba7b1bcbdb5afacafb5bdbbb0a69b8e8174685e5242392e23180c00000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000814212e3b4754616e7a8796a0acb8c5c6bcb4aeaca7a7a7a7a7a7a7a7a7a7a8aaafb7c1cbc2b6a99c8f8376665c5144382c1f1206000000000000000000000914212d3a4754606d7a86929facb9b8ab9f9285796d6053473c31261b0f0100000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f424242424242424242403f3b352e251c120700000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f83766966727f8c99a4afbbbbafa49a8d8073665c5145382c1f1303000000000000000000000c1825313d48535d65686a6a6a6a6a6a6a6a6a66635c52473b2f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000000000000000000000000000002080e111414181b171b1f201f1b171a1a25313b4855616e7b8895a0acb8b3a99a8d80746758626f7c8895a2afbbafa295887c6f6255493c4653606d798698a2aebab2a5998c7f7266594c3f3326190c000000101d2a3643505d697683909caab4bdc0baada297887c6f6255493c2f22160900000000000000000000000000000000000000000004111d2935414b556773808d9aa6b0bdc4bab0a69f97928d8a8a8b8e9299a1a8aeb4bdc6baada194877a6e6154473b2e211408000000000000000000000000000000000a1724313d4a5764707d8a979797979797979797979797979797979797979797979797979795887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000915222f3c4855626f7b8898a2aebabaaea298887b6e61667784919daab7ab9e92857884919eabb7ab9e91857868606d7a86939facb9bbafa499897c6f6256493c2f231607000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007131d2a36424d5763707c8995a0acb8c4c0bbb9bbc0c7b7ab9f94887c6f62564c4130271d120700000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000714202d3946525e687784919daab7c4bfb4aaa29f9a9a9a9a9a9a9a9a9a9a9b9ea5afbac6c0b5ab998c807366544a4034281c1004000000000000000000000713202c3945525d687683909da9b6baada2978b7e7164584e43372b1d120700000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4e4e4e4e4e4e4e4e4e4d4b4740372e24190e02000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696a7784919dabb5c0b9ac9f93877b6e61544b4034281c1004000000000000000000000814202c37414b53595b5d5d5d5d5d5d5d5d5d5a58524a40362a2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000000000000000000000000040a0f14191e2021252822272b2d2b27222623202d3a47535f697784909daab7b7ab9e9184786a60616e7b8894a8b2bdb0a3968a7d7063574a3f4754616e7b8794aab4bfb1a5988b7e7265584b3f3225180c000000111e2a3744515d6a7784909daab7c3c9beb3a996897d7063564a3d3023170a0000000000000000000000000000000000000000000613202c3945515d677783909daab6c2bdb2a89f949085807e7d7e81879196a1abb5c0cbbaada194877a6e6154473b2e211408000000000000000000000000000000000a1724313d4a5764707d8a8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b887c6f6255493c2f2216090000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000b1825313e4b5864717e8b97aab4bfb8ac9f9285796c606875828e9ba8b5ada197887b8896a1adb5a99c8f8276695d677784919eaab7c0b5ab988b7e7265584b3f2e23180c000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1a26313b4854606b7783909da9b3bec9c7c6c7c9bdb2a89c8f82766a5f53443a301e150b0000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000000005111e2a36414c566774818e9aa7b4c1baaea298928d8d8d8d8d8d8d8d8d8d8e939eaab6c2bbafa399897d7063564a3d2e23180c000000000000000000000004111d2935414c566673808c99a9b3b5b3a99d9083766a5f5347392f24180c00000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5b5b5b5b5b5b5b5b5b5b5957524940352a1f1307000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f837673737c8995a0acbdbeb3a99c8f8276695f5342392e23180c0000000000000000000000040f1a252f3941484d4f5050505050505050504d4b4740382e242b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100000000000000000000000070c151b1f252a2d2e32352d33373937332d33302d2b37424d5766737f8c99a7b1b9ada196897c6f62606d7a8796a0acb9b2a6998c7f73665a504c4f5964707d8a97a3b0bdb2a8978a7d7164574a3e3124170b000000101c2936434f5c6976828f9ca9b3bdc0b9ada197887c6f6255483c2f2215090000000000000000000000000000000000000000000714212d3a4754606d7a86939facb9c6b9aca19690827a74717071757c849199a3afbbc7baada194877a6e6154473b2e211408000000000000000000000000000000000815212e3b4854616e7b7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7a6d6154473a2e2114070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000030f1b27333f49536774808d9aa7b3c0b6a99d908376655b66737f8c99a6b2b3a9998c7f8c99a8b2b3a69a8d807367556875828e9ba8b5c1b4a79a8e817467544a4034281c10040000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f2c38444f5964717e8b97a1adb9c6d1d2d2c5b9aca0968a7d7064584e4332291e0c030000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000000000010d1925303e4b5864717e8b97a8b2bdb8ac9f928681818181818181818181818e9ba8b4c1b9ac9f92867a6d6053473a2d2014070000000000000000000000010d19242f3c4956626f7c8997a2a8a8a8a89f95887c6f62554b4035291d1004000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c1b5a89b8e827568686868686868686868686866635c52473b2f23160a000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b7ab9e918480808082909ca7b1bcb9ada1978a7d7164574d4230271d120700000000000000000000000009131e272f373d4042434343434343434343403f3b362e261c2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000000000000000000030b121820272b3036393b3f42443f4446443f43403c3937333c4855626f7b8895a0acb8b2a8998d8073665d687784919eaab7b7aa9d9083776c615a5959616b75818e9ba8b5b9ada196887b6e6155483b2e2215080000000c1926333f4c5966727f8c97a2abb2b5afa69e9185786c605346392d2013060000000000000000000000000000000000000000000916222f3c4955626f7c8899a4afbbbfb4ab9e9184796d686463656a6f7c87929facb9c5baada194877a6e6154473b2e211408000000000000000000000000000000000714212d3a46535e696e71717171717171717171717171717171717171717171717171717171716d685e5246392d2013070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000005121f2b3744505b6576838f9ca9b6c0b4a79a8d8174675364707d8a97aab4b7aa9d9184919daab7b5ab978b7e71645966737f8c99a6b2bfb6aa9d908377665c5144382c1f12060000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101b27323d4653606d7985919eabb4bfcbd6cabeb4aa9e9184786c6053463c3120170c000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000000000000815212e3b4854616e7b8796a1acb9b9ac9f92867a7474747474747474747d8996a3b0bcb6aa9d908377675d5145392c2013060000000000000000000000000813202d3a4653606d7985929b9b9b9b9b9b9a8d8074675d5145392c1f1306000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c1b5a89b8e8175757575757575757575757575736e63574b3f3225190c000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b9ada196918d8d8d90949fabb9c0b6ac9e9285796d6053463c3120150b00000000000000000000000000020c151e252c31343537373737373737373733322f2a241c1f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100000000000000000040c151d232832373b4146474b4e5149505350494f4d4946443f3847535f6a7784919daab7b7aa9d9184776a5f6875818e9baab4b8aca0958a7e716c6766676b707d87939facb9b8ab9e918478695f53463a2d2114070000000714212d3a4754606d7a859299a1a8aba39f948b7f72665b5044382b1f12060000000000000000000000000000000000000000000a1724313d4a5764707d8a97abb5c0baaea3998b7e71675e5657585f6a75818e9ba8b4c1baada194877a6e6154473b2e2114080000000000000000000000000000000005121e2a36424d575e616464646464646464646464646464646464646464646464646464646464615e564c4135291d11050000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000613202d394653606c7985929fabb8c0b6ac988b7e726558616e7b8898a2aeb8aca0959195a0acb8afa499887c6f625764707d8a97aab3beb9ac9f9286796d6053463a2d2013070000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b161f2c3845515c6773808c99a3aebac7d3c6baaea2988b7f72665b5044382b1f1205000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000000000000714212d3a46535e697884919eabb7bbafa399897c7067676767676767737f8c99a6b2bfb3a69a8d807367554b4035291d110400000000000000000000000006121f2b3844505c6675828e8e8e8e8e8e8e8e8e857a6d6053473a2d201407000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c4b7ab9e918481818181818181818181818181807366594d4033261a0d000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4bdb2a8a19e9a9a9a9c9fa6b0bcbbafa49a8d8073665c5144382c1f12030000000000000000000000000000030c131a202527282a2a2a2a2a2a2a2a2a2726231f19121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c1000000000000000040d161e272e343c43474d5254585b5d5f5b605b5e5c595653504944434e586673808c99a8b2b8aca096887b6f6265727e8b98a3aebab1a79f92867e77747273767d859299a4afbbb1a89b8e817568574d42362a1e12050000000713202c3945525d68707d8791969a9a99928d82786c60544a3f33281c0f030000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1beb9ac9f92867a6d60554c4a4e5864707d8a97aab4bfbaada194877a6e6154473b2e21140800000000000000000000000000000000020e1a25313b454d5354585858585858585858585858585858585858585858585858585858585854524c443a3025190d010000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000815222e3b4855616e7b8897a2adbabbafa49a897c6f6356606c7985929facb8b1a8a09da0a8b1b9ac9f93867a6d6055616e7b8898a2aebabaaea398887b6f6255483c2f2215060000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b55616e7a86929facb9c5d2c5b8ab9f92857a6d60544a3f33281c0f03000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000005121e2a36424d576875818e9ba8b4c0b5ab988c7f72655a5a5a5a576975828f9ca8b5bdb2a8978a7d7064574a3d2f24180d0100000000000000000000000003101c28343f4a5463707d828282828282828282817c6f6256493c2f231609000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c4b9aca196918e8e8e8e8e8e8e8e8e8e8e8e8e83776a5d5044372a1d11040000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c4bab2adaba6a6a6a9abb0b8c2b9ac9f93877b6e61544a4034281c100400000000000000000000000000000002090f14181b1c1d1d1d1d1d1d1d1d1d1a1917130e121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000000000000030c161f28303940454e54565e6165686a6c656c656b696663605b53504a4855626f7c8896a0acb8b2a8998c7f7366616d7a86929facb6baaea398928a83807f80838a9297a2abb5b8aca0958a7d7063574a3d31261a0e0200000004111d2935414c56606b707d848a8d8d8c8780786d665b5042382d22170b000000000000000000000000000000000000000000000c1926323f4c5965727f8c98a5b2bfb6aa9d908377675d51433d4754616e7b8798a3aebabaada194877a6e6154473b2e211408000000000000000000000000000000000009141f29333b4246484b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4746413a32281e1308000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000b1724313e4a5764717d8a97a9b3beb9ac9f93867a6d60545b667783909daab6bab1acaaacb1bab7aa9e918477675d535f697885929fabb8bfb4aa978b7e7164584b3e2d22170b0000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3946525e6874818e9ba7b4c1cdc0b3a79a8d8074675d5142382d22170b00000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000000000020e1a25313f4b5865727e8b98a9b3beb5a89b8e827568564c4e525e697885919eabb8b8aca096877a6d6154473a2e21140700000000000000000000000000000b17232e384855616b70757575757575757575756f6a6054473b2e221508000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c4bdb2a8a19e9b9b9b9b9b9b9b9b9b9b9b9b9083776a5d5044372a1d11040000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b3b3b3b6b7bcc2c2b5a99c8f8276695f5342392e23180c00000000000000000000000000000000000004080c0e0f1010101010101010100d0d0a0702121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100000000000000a151e28313a424b51586062686e727577787979797876736f6c65605c544d535f6a7784919eaab7b7aa9d908377695f6874818e9aa4afbbb4aaa39f95908d8c8d90959fa2a9b3bbb0a69d9184786c605346392d20130900000000010d19242f3a444f59606b70797d80807f7b746d665c544a3f2f261c1106000000000000000000000000000000000000000000000c1926333f4c5966727f8c99a5b2bfb5a89b8e827568554b403a46525e697986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000030d17212931363a3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3a3935302820160c02000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000d1a2733404d5a6673808d99a6b3c0b7ab9e918478675d51546874818e9ba7b4c1bdb8b7b8bdc2b5a89b8f827568554d57697683909ca9b6c0b3a79a8d80746753493f33271b0f0300000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d2a36414c5663707d8996a3b0bcc8bbafa295887c6f62554c4134281c110600000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000000000000915222f3b4855626e7b8897a1adb9b7ab9e918478685e524854616e7b8797a1adb9b7aa9d918477685e5246392d201307000000000000000000000000000006111c2c38444f596163686868686868686868686260584e43372b1f1306000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4753606d7a8693a0adb9beb1a5988b7e7265584b3f3225180c00121e2b3845515e6b7884919eabb7c4c4bab2acaba8a8a8a8a8a8a8a8a8a8a89d9083776a5d5044372a1d11040000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cec6bfbab8b7b7b7b8b9bec5c0b3a79a8d8074675d5145382c1f150a00000000000000000000000000000000000000000001020404040404040404040000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000000000006111c26303a434c545c606a6f757b7e8184858686858482807c78716d665f574f586673808d99a8b2b8aca095887b6e61626f7c87939fa7b1bab4aea7a09d9a999a9d9fa7adb3bcb3a99f948b7e71655b5044372b1f1205000000000008131e28323d474f5960676d717374726e69605c544a42382d1d140a00000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79b8e8174685b4e4136424d576b7885929eabb8baada194877a6e6154473b2e211408000000000000000000000000000000000000050f171f252a2d2e31313131313131313131313131313131313131313131313131313131312e2d29251e160e0400000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000005111e2a36424d566976828f9ca9b5c2b5a89b8f827568554c5965727f8c98a5b2bfc8c5c4c5c8bfb3a6998c807366594e5a6774818d9aa7b4c0b6a99c908376655b5044372b1f120500000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d6774808d9aa7b3c0ccbfb2a6998c7f73665c5145382c1f160b00000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000000000000814212e3a47535f6a7885929eabb8b9aca196877a6e61544a5764717d8a97a9b3beb4a79a8e817467564c41362a1d1105000000000000000000000000000000101c28333e474f55575b5b5b5b5b5b5b5b5b5b56544e463d32271b0f03000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362e3b4754616e7a8794a1adbabeb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b4b4b4b4b4b4b4b4b4b4aa9d9083776a5d5044372a1d11040000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c6bcb4aeacaaaaaaabadb3bbc5b8ab9f9285796d6053473d32271b0f02000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c1000000000000c17232e38424c555d666d747c82878b8e9092929892918f8c89847e786e69605955626f7c8896a0acb9b1a7988c7f72655f6a73808d95a0a8b1bbbab1acaaa7a5a6a9abb1babbb3aaa1978f82776c6053493f33271b0f030000000000010c16202c353d474f555c6064676765615f57514a42392f261c0b0200000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413045525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000000000000000000000000000000050d141a1e2121252525252525252525252525252525252525252525252525252525252521201d19130c040000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000714202d3a46525e697885929eabb8bfb3a6998c807366594d5663707d8996a9b3becad1d0d1cbbfb4aa978a7d7164574b5865727e8b98acb6c0b8ab9f9285796c605346392d20130600000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c28333f4a54606d7a85929fabb8c5d1c4b8ab9e9185796d6053463d32271b0f03000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000000000000006121f2b37434e586875828f9ba8b5bdb2a8968a7d70635749536673808d99a6b3beb2a9978b7e7164584b3e3025190d010000000000000000000000000000000b16212c353e44484a4f4f4f4f4f4f4f4f4f4f4947433d342b20150a00000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362f3c4855626f7c8895a2aebbbdb0a4978a7e7164574a3e3124170b00121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b4b4b4b4b4b4b4b4b4b4aa9d9083776a5d5044372a1d11040000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4bfb4aaa29f9d9d9d9ea1a9b3bebaada2978b7e7165584e43372b1e1308000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100000000003101c28343f4a545d676d7880878f93999b9d9f9fa39f9e9c9996918b837b706b60585f6a7784919eaab7b6a99d908376695e606d79839096a0a7afb5b9b8b7b3b2b3b6b8bab8afa9a19892857a6e655b5041382d22170b00000000000000040d1a232c353d434b5153575a5a5955534d44403930271d140a0000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000000000000000000000000000000000000003090e12141518181818181818181818181818181818181818181818181818181818181413110d0802000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000814212e3b4754616e7a8797a1adb9bfb4aa978a7d7164574a54616e7a8797a2adb9c6d2ddd3c7baaea398887b6e62554956626f7c899aa4afbbbaaea298887b6e6155483b2e22150800000000000d1a2633404d596673808c99a6b2b2b2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505b66727f8b98a2aebac6d2c6b9ada1978b7e7164594f44382c1f1409000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000000020f1a26313f4c5865727f8b98aab3beb3a6998c80736653505b6576838f9ca9b6b9ada197887b6e6155483b2e2215080000000000000000000000000000000005101a232c33383c3d424242424242424242423c3b37322b22190f0400000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433639414d5765717e8b98a4b1bebeb3a995897c6f6256493c2f23160900121e2b3845515e6b7884919eabb7c4c4bab2acaba7a7a7a7a7a7a7a7a7a7a79d9083776a5d5044372a1d11040000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4baaea298929090909297a1adb9beb3a99d9083776a6054473a3025190d000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000000030e18222c3844505c666d79828d93999fa4abaaabacaeacaba9a8a09e9590867d706a60586673808d99a8b2b9ac9f93877b6e615c666e7b8490959fa3abadb2b3b4b4b4b3b3aeaba59e9791867d6f685e53493f2f261b1106000000000000000008111a232b31394045474a4d4d4c4846423b342e271e150b020000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000020507080b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b070705010000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000a1724303d4a5763707d8a96a9b3bebaaea298887b6e615548525e697885929eabb8c5d1ded2c5b8ac9f9286796d60534753606d7a86939facb9beb3aa978a7d7164574a3e3124170800000000000d1a2633404d596673808c99a6a6a6a6a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7884919eaab3becad5c9beb3a99d9083776b6054483b31261a0e010000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8e8174675b4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000000000916222f3c4955626f7c8898a2aebab5a99c8f8276655b53606c7985929fabb8b8ab9e918578695f53463a2d211407000000000000000000000000000000000008111a21282c2f30353535353535353535352f2e2b27201910070000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504341464b535e6975828e9ba8b5c1b9ada197877b6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4bdb2a8a19e9b9b9b9b9b9b9b9b9b9b9b9b9083776a5d5044372a1d11040000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8ac9f928683848385929ea9b3beb8ab9f95897c6f62564c4135291c11060000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100000000a15202c38434e58606d788290949fa4abafb5b7b8b9bab8b7b5b2aca79f9892867c6f675d626f7c8896a1acb9afa49a8b7e7265565f696e7b838d92999ea1a9a6a7a7a7a6aaa29f9b938e857d6f6b60564d41382d1d140a000000000000000000000811191f272f34383a3e40413f3b3a363128231c150c03000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000d192633404c5966737f8c99a6b2bfb8ac9f9285796c6053464d56697683909ca9b6c3cfdcd0c3b6aa9d908377665c5045515d677784919eaab7c0b3a6998d8073665a4d403025190e02000000000d1a2633404d596673808c999999999999998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b37434e5864707d8a96a0acbcc5d0dacfc4b8aca095897c6f63574d42362a1d13070000000000000000000000000d192633404c5966737f8c99a6b2bfb4a89b8e8175685b4e4236424d576b7885919eabb8baada194877a6e6154473b2e21140800000000000000000613202d394653606c7985929fabb8b8ab9f9285796c6055626e7b8897a2adbab5a89b8e827568574d42362a1e12050000000000000000000000000000000000000810161c2023242828282828282828282823221f1b150f07000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504f4c52555c656e7b86929facb9c5b8ab9e928578695e52463a2d20140700121e2b3845515e6b7884919eabb7c4b9aca196918e8e8e8e8e8e8e8e8e8e8e8e8e83776a5d5044372a1d11040000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f827777777d8a97a1adb9bcb1a79b8e8174685e5246382d22170b0000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100000030f1a26313b4854606a73808c949fa6afb5bbb7b6b0aeadafb3b8bab9b1aaa29891847a6d60606a7884919eabb7b6ac9c8f8276685e575f696e7980878d919697999a9b9a9a9898928e88817a6f6a60594f443b2f261b0b020000000000000000000000070d151d23292c2d313434322e2d2a261f18120b0300000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000000003080b0d0e1313131313131313130c0b090501000004090e11121313131313131313131308070502000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000004111d2935414c566875828f9ba8b5c2b6a99d908376665b50444e5a6774818d9aa7b4c0cddacec1b4a79b8e817468544a404b556875828f9ba8b5c2b5a99c8f827669564d41362a1e1105000000000d1a2633404d596673808c8c8c8c8c8c8c8c8c7f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b15212e3b47535f6a76828f9ca8b2bdcecfcecfc8bcb1a79b8f8275695f53463a2f24180d0000000000000000000000000c1926323f4c5965727f8c98a5b2bfb6a99c8f837669584e433946535f697985929facb8baada194877a6e6154473b2e211408000000000000000006121f2b3844505b6676828f9ca9b5baada297887b6e625864717e8b97a9b3beb3a9988b7f7265584c3f31261a0e0200000000000000000000000000000000000000050b101416171c1c1c1c1c1c1c1c1c1c1615130f0a0400000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5c5c565e61676d77828f99a3aebbc0b6ac9c8f827669574d42362a1e110500121e2b3845515e6b7884919eabb7c4b7ab9e9184818181818181818181818181817f7366594c403326190d000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f83766a6d7985919eabb8c2b8ac9f92867a6d61544a3f33281c0f0300000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000006121f2b37434e58626f7c87929fa6b0bbb8b0aba9a4a1a1a2a6acaeb4bcb3aaa1968e81756a5f6773808d9aa8b2b9ac9f92867a6d6154575f676d737b8084888b8c8d8e8e8d8b8985817c756e6860584f473d32291d140a00000000000000000000000000030b12181c1f202427272622211e1a140c07000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000000001080f14181a1b202020202020202020181815110c06080f151a1d1f202020202020202020201414110e080200000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000713202c3945525d687884919eabb7c1b4a79a8e817467544a3f4b5865727e8b98a5b1becfdacbbfb2a5988c7f7265594c404c5966737f8c99a6b2bfb8ab9e918578685e5246392d20140700000000091623303c4956636f7d7f7f7f7f7f7f7f7f7f7d6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d2a36414c56626f7c88949fabbac4c6c3c1c3c6c3b9ac9f93877b6e61554b4135291c110600000000000000000000000b1825323e4b5865717e8b98a4b1beb8ab9e9285786a605447464b55616e7b8898a3aebabaada194877a6e6154473b2e2114080000000000000000030f1c28333f4a5466727f8c99aab4beb3a9978a7e7164546774808d9aa7b3baada297887c6f6255493c2f221609000000000000000000000000000000000000000000000407090a0f0f0f0f0f0f0f0f0f0f09080603000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696969696a686e7179818e949fabb5bfbbafa49a8b7f7265584c3f30251a0e0200121e2b3845515e6b7884919eabb7c1b5a89b8e8175747474747474747474747474736d63574b3e3225190c000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696673808d9aa7b1bcbaaea3988c7f72665b5044382b1f140900000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c1000000815212e3a47535f6a76828f99a3afb8b6aea69f9c97949495999fa2aab3bbb2a89e93887c6f62626f7c8996a1adb9afa3998b7e7164554d555d60696e73787b7e80818181807e7c79746f6a615e564e463d352b20170b02000000000000000000000000000001070c101314171a1a191514120e090300000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000020b131a202427272d2d2d2d2d2d2d2d2d2524221d1811121920262a2c2c2d2d2d2d2d2d2d2d2d21201e19140d05000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000714212d3a4754606d7a8796a1acb9beb1a5988b7e7265584b3f4956636f7c8996a9b2bdc9d5cabeb3a996897d7063564a3d4a5764707d8a97aab3beb9ada197877a6e6154473b2e211408000000000915222f3b4854606b6f7373737373737373736f6b6054483b2f221509000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3946525e6874818e9ba6b0bbc1bab6b5b6bac1bbafa4998d8073675d5145382d22170b00000000000000000000000b1724313e4a5764717d8a97acb6c0b9ada197897c6f625b5353555d67727f8b98aab4bfbaada194877a6e6154473b2e2114080000000000000000000b17222d3c4956636f7c8998a2aebab3a79a8d8074675c667683909da9b6b8ab9f9285796c605346392d20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f83767676767676787a7e848e939ea6b0bdc6b9ac9f93877b6e6155483b2e2215090000121e2b3845515e6b7884919eabb7c1b5a89b8e827568686868686868686868686866635b52463b2f23160a000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f837669626e7b88959fabb7bfb4aa9e9184786c6053463b31261a0e00000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c1000000915222f3c4855626f7c88949fabb5b9aea49c948f8a8887898d9298a1a9b3baafa59b8e817468606c7884919eabb7b5ab9c8f8275675d514b51575e61656c6f717374747473726f6d66625f58524c443d342b23190e050000000000000000000000000000000000000406070b0d0e0c08070502000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000010b141d252b30333439393939393939393932312e29231b1b242b313638393939393939393939392e2d2a251e170e050000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000a1623303d495663707d8996a8b2bdbdb2a896897c6f6356493c4754606d7a8796a1adb9c5d2c6b9ada297877a6e6154473b4855616e7b8898a2aebabeb3a9968a7d7063574a3d30241708000000000713202c38444f5960636666666666666666666360594f43382c1f130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b54616d7a86929facb9c1b7afaaa8aaafb7c0b5ab9f92857a6d60544a3f33281c0f0300000000000000000000091623303c4956636f7c899aa4afbbbeb3a99b8e81756d63606061676d7984919eabb7c4baada194877a6e6154473b2e2114080000000000000000000613202d3a4653606d7985929facb8b6a99d90837666606d7986929facb8b5a89c8f8275665b5044382b1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8ab9f928582828282828384878b91969ea5afb8c2bcb0a69c8f8276695f53463a2d2114070000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5b5b5b5b5b5b5b5b5b5b5957524940352a1e1307000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695f6a7683909daab4bfb9aca0968a7d7063574d42362a1d1207000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100005111e2a36414c566774818d9aa6b0bdb1a79c928d827d7b7a7c80869197a1adb9b9ac9f92867a6e616574808d9aa9b2b9ac9f92867a6d605447454d53535b60626466676867676562605c54544e46413b322b22191107000000000000000000000000000000000000000000000001010000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000008131d262f363c40414646464646464646463f3d3a342d24242d353d4245464646464646464646463b3936302920170d0200000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000c1926323f4c5965727f8c98a5b2bfb9aca196877a6d6054473a45525d687885919eabb8c4d1c5b8ab9e928578695e5246394653606c7985929fabb8bfb2a6998c7f7366594c402f24190d01000000030f1b27323d474f5456565e61646565615f5756544f473d32271b0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c66737f8c98a3aebabbafa59e9b9ea5afbbbaaea2988b7f72665b5044382b1f150a000000000000000000000714212d3a4754606d7a86939facb9c5b6aa9e938b7f756f6d6c6e7179828f96a1acb9c5baada194877a6e6154473b2e21140800000000000000000006131f2c3845515c6676838f9ca9b6b9ac9f9286796d626f7c8898a3aebab4aa998c7f7266544a3f33281c0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4baada297928f8f8f8f8f909196989ea0a8afb7c1beb4aa9f94897d7063574d42362a1e12050000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4e4e4e4e4e4e4e4e4e4c4b4640372e24190d02000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695765717e8b98a2aebabdb2a89c8f8275695f5346392e23180c000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000714202d3946525e687784919eaab7b8ab9f958d8076716e6e6f737c85919ea7b1baaea3998a7e7164636f7c8996a1adb9aea3988a7e7164554b4042464950535558595a5b5b5a585653514b47433c3630292019100700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800030f1a252f3841484c4e5353535353535353534b4a453f372d2b353f474e52535353535353535353535346413b32291e140800000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000004101d2935404b556875818e9ba8b4c1b7ab9e918478685d524539414c566976828f9ca9b5c2cfc2b6a99c8f837669564d423744505b657683909ca9b6c1b5a89b8e827568564c4135291d1104000000000c18242f39434b555d60686e7172716e69615e564d453b30251a0e050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7985919eaab4beb3a99e938e939ea9b2beb3aa9e9184786c6053463c31261b0f020000000000000000000613202c3945515d677784919daab7c3baafa59b918b817c7a797a7e848f949ea8b2bdc9baada194877a6e6154473b2e21140800000000000000000004101c2834404b546673808c99abb5baaea398897c6f65727e8b98aab4baaea398897c6f6356493c2d22170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4beb3a9a29f9c9c9c9c9c9d9ea1a8aaacb2bac1bfb6aca2988f82766b6054453b31261a0e020000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f424141414141414141403e3b352e251c120700000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c606d7a86929facb8c4b9ac9f93877b6e61554b4034281c10040000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000814212e3b4754616e7a8796a0acb9b6a99d9083786c646161626a707d8a95a0acb8b4ab9a8d817467606c7884919eabb8b4aa9b8e8275675c514538383f4446484b4d4e4e4e4d4b494645403937322a251e170e070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000814202b36414a53585a606060606060606060585651493f34313d4751595e5f6060606060606060605f524c443b3025190e02000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000613202c3945515d677784919daab7c2b5a89b8f827568564c4135404d5a6773808d9aa6b3c0d2c0b4a79a8d8174675a4e41333f49536774818d9aa7b4c0b7aa9e918477685d5245392c20130600000004101d2935404b555d676d747a7e7f7e7b756e685e574d42362a21160b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c38444f5964717e8b97a1adbcb9ada1978e828e97a1adb9b9aca0968a7d7064584e43372b1e130800000000000000000004111d2935414c556874818e9ba8b2bdc1b7aca39b938e898686878b91969ea6b0bac1cabaada194877a6e6154473b2e211408000000000000000000000c18232e3d4a5663707d8999a3afbbb4aa988b7e726774818e9aa7b4b9ac9f9286796d6053473a2d2014060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c5bbb3adaba9a9a9a9a9a9abacb2b7b9bdc4bdb5aea49a92867b6e61594f4433291f1409000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42353535353535353533322f2a241c130a0000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5d6774818e9ba8b2bdbbafa4998d8073675c5145382c1f150a0000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000a1724313d4a5764707d8a97a8b2bdb2a8978a7e71655b555458616b7783909daab7b7aa9d9084776a5b6574808d9aa9b3b8ac9f9285796d6053473a2e3337393c3e40414141403f3c3a38342e2b262019140d05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000b1824303c48535c64676c6c6c6c6c6c6c6c6c65625b51453a36424e59636a6c6c6c6c6c6c6c6c6c6c6c5e564c41362a1e1105000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000714202d3a4753606d7a86939facb9bfb3a6998c807366594d402f3e4b5864717e8b97abb5c0ccbeb1a5988b7e7265584b3f2d3f4b5865727e8b98acb6c0b9aca096877a6d6054473a2d21140700000006131f2c3845515d676d7980868a8c8b88827a6e695e52463d33271c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c16222f3b4854606b7783909da9b3beb6ac9e92857a84919eabb5bdb2a89c8f82766a5f53473a3025190d000000000000000000010d19242f3d495663707c8996a0acb8c1beb5aca59e9b96999399979ea0a8a8aab0b8c1baada194877a6e6154473b2e211408000000000000000000000714202d3a4753606d7a86929facb9b4a79b8e8174677784909daab7b6a99c908376675c5145382c1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cdc5bebab8b5b5b5b5b5b6b7b9bdc4c5beb9b2aba39f93887e71695f53473d3321170d03000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235282828282828282625231e19120a010000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5563707c8996a0acb9c0b5ab9e9285796d6053463c32261b0f0200000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000c1926333f4c5966727f8c99a5b2b9ada196877a6d605349474f596673808d99a6b3b9ac9f928679675d63707c8997a1adb9aea2988a7d7063544a3f34282b2d2f313334353434322f2d2c28231d1b150d080200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000d1a2733404c58646e74797979797979797979726d62564a3d3845525e6a757979797979797979797976685e5246392d201407000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000091623303c4956636f7c8999a4afbbbfb4aa978a7d7164574a3e313c4955626f7c8899a4afbbc7bdb2a896897c6f6356493c303c4956626f7c899aa4afbbbdb2a896897c706356493d30231607000005111e2a36424d57606d79828d92999898938f847b6e61594f44382c20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007131d2a36424d5763707c8995a0acbbbbafa49a8d8073808c99a4afbbb7ab9f94887c6f62564c41362a1d12070000000000000000000816222f3b4854606b7784919ea5afb9c2beb7afaaa8aba49fa4abaaa69e9c9ea6b0bbbaada194877a6e6154473b2e211408000000000000000000000613202c3945515d677683909da9b6b7aa9d9184776d7a86929facb9b5ab998d807366554b4034291c10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbfbebebebab8b3ada8a099928b7f726c61574d42352b210f0600000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c1b1b1b1b1b191916130d0d0c0a0702000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c54606b7784919eabb5c0b9ada1978b7e7164584e43372b1e130800000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000d1a2733404d5a6673808d99a6b3b7ab9e918478685d52413e4b5764717e8a97a4b1bbafa399867a6d60606c7985919eabb8b4aa9b8e8174665c5044382c1f20222526272828272523201f1c18120f0a04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774808686868686868686867f7265584b3f3946535f6c79878686868686868686867a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000c1825323f4b5865727e8b98abb5c0baaea298887b6e6155483b2e3a4753606d7a86939facb9bfb9aca196877a6d6054473a2d3a4753606d7a86939facb9beb2a5988b7f7265584c3f2f23180c00000714202d3a46525e6974818d959fa3aba59e969082766b6054483c2f2216090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d18242f3a46535f6975828f9ba7b1bcb9ac9f93877b6e7b87939facb9bbb0a69b8e8174685e5246392e23180c0000000000000000000713202c38444f5964717e8a939ea7b0b9bdc1bab6b4b5afacafafa59d948f949eaab7baada194877a6e6154473b2e2114080000000000000000000004101d2935404b556773808d9aacb6b9ac9f93867a6f7c8999a3afbbafa4998a7d7063574a3d2f23180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b2b1b3adaba9a19e9691877f726d625a50453b3123190f0000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281e1e1e1e1e1e1e1e1e1e1e1a1917130e080000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c4f5966737f8c99a4afbbbeb3a99d9083766a5f54473a3024190d00000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4b7aa9d9084776a564c413d4a5663707d8996a3b0c0b5ab94877b6e615b6674818d9aa9b3b8ab9e9285796d6053463a2d221715181a1b1b1b1a18161313100c07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d939393939393938b7e7265584b3f3946535f6c79869293939393939393877a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100004101c2834404b546774818e9aa7b2b2b2ac9f9285796c605346392d3845515d677784919eaab2b2b2ab9e918478675d5145392c3945515d677784919eaab2b2b2a79b8e817468554b4034291c1004000814212e3b4754616e7b86929fa7afb5afa89f94897d706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414b55616e7b87939facb9beb3a99c8f82766975828f9ca8b2bdb9ac9f92867a6d61544b4034281c1004000000000000000004101b27323d4955616c75818e959fa6adb2b7b8b9b9b8b6b0aba39f938e828f9ca8b2b2ada194877a6e6154473b2e21140800000000000000000000010d18242f3d4a5763707d8a9aa4afbbafa49a897d727f8c98abb5b9ac9f93867a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a4a9a29f9b97928c847d726d625b51483e33291f11080000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352a2a2a2a2a2a2a2a2a2a2a2a2726231f19120a02000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5054616e7b87939facb9c5b8ab9f95887c6f62564c4135291b1106000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000f1b2835424e5b6875818e9ba8b4b6a99d9083766a5d50433c4956636f7c8996a2afbbaea295887b6f625463707d8997a1adb9ada297897d706353493f33271b0f0b0d0e0e0e0d0c090706040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9a9f9f9f9f9f988b7e7265584b3f3946535f6c7986929f9f9f9f9f9f94877a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100006131f2c3845515c667783909da5a5a5a5a59d908376665b5044382b35404b556875828f9ba5a5a5a5a59c8f827569554c41352935404b556875828f9ba5a5a5a5a59d908477675c5145382c1f1306000b1825313e4b5864717e8b99a3afbbc0bab0a6998d8073665a4d4033271a0d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d6774808d99a4afbbb9ada1978a7d7164707d8a96a1adb9baaea3988c7f73665c5145382c1f160a0000000000000000000b16212d3945505a616d7a838f949ea1a8aaabacacaba9a69e99928c817d8996a3a6a6a6a194877a6e6154473b2e21140800000000000000000000000714212d3a4754606d7a86939facb9b6ac998c7f75818e9ba8b4b7aa9d908477685d5245392c201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b78849198989898989898989898989898989898979697928f8a857f796f6b625b51493f362c21170d000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423737373737373737373737373733322f2a241c140a000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50525e6976828f9ca9b3bebcb1a79a8e8174685d5245382d22170b000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000f1c2835424f5b6875828e9ba8b5b6a99d9083766a5d50433c4956636f7c8996a2afbbafa295887c6f6255606d7985929eabb8b3a99a8d8174655b5044372b1f12050001020101000000000000000000000000000000000000000000000000000000000000000000000001040607090a0807050200000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7acacaca5988b7e7265584b3f3946535f6c7986929facacacaca194877a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000713202d3a4653606d798692989898989898988e817467544a3f33282f404d596673808c989898989898988d8073665a4d402f242f404c5966737f8c989898989898989286796d6053473a2d201407000c1926333f4c5966727f8c99abb5c0cbc1b4a79b8e8174685b4e4135281b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c28333f4a54606d7a85929fabb5c0b5ab9e9185796d606c7884919eabb5bfb4aa9e9185796d6053463d32271b0f03000000000000000004111d28333e46525d686d79828b91969a9d9e9f9f9f9d99948f877f787d8996999999999994877a6e6154473b2e21140800000000000000000000000713202c3945525d687784909daab7b5a89b8f827784919eaab7b4a79a8d817467564c4135291d1104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8b8b898885827e79726d67605951483f372d241a0f06000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4444444444444444444444444444403f3b362e261c12080000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504d5764717e8a97a2adb9c2b8ac9f92867a6d6053493f33271b0f030000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000f1c2835424f5b6875828e9ba8b5b6a99d9083766a5d50433c4956636f7c8996a2afbbafa295887c6f62555c6674818e9ba9b3b8ab9e9184786c605346392d20130a000000000000000000000000000000000000000000000000000000000000000000000000000001070d11131416161514120e09030000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3946535f6c7986929facb9b9ada194877a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b9b6a99c908376695d5043362a1d10000916222f3c4955626f7c888c8c8c8c8c8c8c8c8b7f7265584c3f2d22313e4a5764717e8a8c8c8c8c8c8c8c8a7e7164574b3e3124313d4a5764707d8a8c8c8c8c8c8c8c8c887c6f6255493c2f221609000b1825323e4b5865717e8b98a5afbac1bcb1a79a8d8073675a4d4034271a0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505b66727f8b98a2aebdbbafa4998d8073665c66737f8c99a3afbbb9ada1978b7e7164594f44382c1f14090000000000000000000c17222935414c565d676d777e848a8d9091929392908d88827c73707d898c8c8c8c8c8c8c877a6e6154473b2e211408000000000000000000000004111d2935414c566774818d9aa7b4b8ab9e91847a8796a0acb9b2a8978a7e7164574b3e2f24190d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7d7b7975716d67605c554f463f362d251b120800000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5151515151515151515151515151514d4b4740382e24190e0200000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504653606d7985929eabb8c3baaea2988c7f72655b5044372b1f14090000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000f1c2835424f5b6875828e9ba8b5b6a99d9083766a5d50433c4956636f7c8996a2afbbafa295887c6f62555463707d8a97a2adb9ada197897c6f6356493c32261b0f03000000000000000000000000000000000000000000000000000000000000000000000002080d13181d2021232322211e1a14100b05000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8e8174675b4e4134404b556b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3adadada99c908376695d5043362a1d10000815222f3b4855626e7b7f7f7f7f7f7f7f7f7f7f7b6e6155483b2e222e3b4754616e7a7f7f7f7f7f7f7f7f7f7b6e6154473b2e212e3a4754616d7a7f7f7f7f7f7f7f7f7f7f7c6e6255483b2f221508000815222e3b4855616e7b88939ea8b0b5b2aaa0958a7d7064574a3d3124170a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7884919eaab3beb9ac9f93877b6e6154616e7b86929facb9beb3a99d9083776b6054483b31251a0e010000000000000000060d1924303a444c555d656c71797d81838586868583807c766f6a6e7b7f7f7f7f7f7f7f7f7f796d6053473a2d2014070000000000000000000000010d1924303e4a5764717e8a97a8b2b9ada1978b7e8b98a8b2b9aca196877b6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313d4a56626c71727272727272727272727272727272727271706e6c6564605d55514b433d342d241b13090000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5a58524a40362a1f130700000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5045515c6774808d9aa7b1bcbfb4aa9e9184786c6053463b30251a0e0000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2835414e5b6874818e9ba7b4b6aa9d9083776a544a3f3d495663707c8996a3afbbaea195887b6e625553606d7985929fabb8b2a99a8d807367584e43372b1f130600000000000000000000000000000000000000000000000000000000000000000000040c13191d24292c2d30302e2d2a261f1c160f080000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a89b8e817568544a3f3845515c677885929fabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a0a0a0a0a09c908376695d5043362a1d10000814212e3a47535f696e727272727272727272726e695f53463a2d212d3946525e686e7272727272727272726e695e52463a2d202d3946525e686d727272727272727272726e6a5f53473a2e211408000714212d3a46535f6975818e969fa6a8a8a0989083786d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b37434e5864707d8a96a0acbcbdb2a89c8f8275695e535e6975828f9ba8b2bdb8aba095897c6f63574d42362a1d130700000000000000000008131e28323a434b535b60676d7074777879797876736f6a625f696e7373737373737373736d675d5145392c2013060000000000000000000000000814212e3b4754616e7a8796a0acb9b2a99d9083909daab6b7ab9e918478695e52463a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915212e3a45505a62656565656565656565656565656565656565646361605b5353514b454039312b221b1209010000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e82756a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a66635c52473b2f23170a00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50404b55626f7c8895a0acb8c6b8aca096897d7063574d42362a1d120700000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000d1a2734404d5a6773808d9aa6b3b7aa9d918477665c50443d4a5764707d8a97a3b0beb3a994877a6d6154515c6675818e9baab4b7aa9e9184776a5f53473b2e211509000000000000000000000000000000000000000000000000000000000000000000050e161e24292f35393a3c3d3b3a36312c27211a110901000000000000000000000000000000000000000000000000000c1926323f4c5965727f8c98a5b2bfb6a99c8f8376665b50443a4753606d7a86939facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707d8a93939393939393908376695d5043362a1d100006121e2b37424d575f6265656565656565656565615f574d42362a1e2a36414c565e61656565656565656565615e564d42362a1e2a36414c565e6165656565656565656565625f574e42372b1e12060005121e2a36424d57616d7a8490949a9b9a9691867c6f665c5044382b1f12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b15212e3a47535f6a76828f9ca8b2bdb9ada1968a7d7064574d5663707d8996a0acb9bcb1a79b8f8275695e53463a2f24180d000000000000000000020c162028313a414950555c6063676a656c6c666a66625f58575e61666666666666666666605d554b4035291d10040000000000000000000000000714202d3946525e687784919eaab7b8aba0959095a0abb8b4a79b8e817468574d42362a1e11050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d29343f48505658595959595959595959595959595959595858565553504947454039342f271f19100900000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e81777777777777777777777777777777777777736e63584b3f3226190c00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504347535f6a7783909daab4bfbdb2a89b8f8275695e5246392e23180c00000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000d192633404c5966737f8c99a6b2b9ac9f9286796d605346434d5765727f8c98a5b2b9ada19786796d60534b5464707d8a98a2aeb9aca096887c6f6255493c31261a0e0200000000000000000000000000000000000000000000000000000000000000050e17202830353a41454749494846423b38332b231b1309000000000000000000000000000000000000000000000000000b1825323e4b5865717e8b98a4b1beb8ab9f9285796c605347464c56626f7c899aa4afbbbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000a1724313d4a5764707e8686868686868686868276695d5043362a1d1000020e1a26313c454d53555959595959595959595955534d453b31261a25303b444c525459595959595959595954524d443b30251925303a444c52545959595959595959595955534e453c31261a0e0200020e1a26313b46525e686e7b83898d8e8d8a847c6f6a5f544a3f34281c1003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d2a36414c56626f7c88949fabbac0b5ab9e9184786d60534653606c7884919eabb4bfb9ac9f92877b6e61554b4035291c1106000000000000000000040e161f282f383f444b5153575a535b60605b545a55534e4d535459595959595959595953514b43392f24180d0100000000000000000000000005111e2a36414d566774818e9aa7b4bcb1a7a09da0a7b1bcb3a9988b7e7165584b3e30251a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4b4a4846443f3a38352f29231d150d070000000000000000000000121e2b3845515e6b7884919eabb7c4b8ab9f92858384848484848484848484848484848484838073665a4d4033271a0d00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043434e5865727f8b98a3aebac3b9ac9f92877b6e61544b4034281c1004000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000b1825323e4b5865717e8b98a9b3baaea398897c6f6258514e555e6975828f9ba8b5b8ab9e918578665c504753606d7986929facb8b2a8998c807366574d42372b1e1206000000000000000000000000000000000000000000000000000000000000020b172029323a41464b5154565655534d48443d352d251b11070000000000000000000000000000000000000000000000000b1724313e4a5764717d8a97acb6c0baada297897d70635c5353555d6873808c99acb6c0baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000713202d3a4653606d787a7a7a7a7a7a7a7a7a7a6d6053473a2d201407000009151f2a333c4247484c4c4c4c4c4c4c4c4c4c4846423b33291f141e29323b4146474c4c4c4c4c4c4c4c4c4746423b32291f141e29323a4146474c4c4c4c4c4c4c4c4c4c4847423c332a20150900000009141f2a36414c565e696e767d8082817e796f6a5f584e42382e23170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3946525e6874818e9ba6b0bbbbafa3998c7f73665c5044505b65727f8c99a3aebabbafa3998d8073675d5145382d22170b00000000000000000000040d161d262d33394045474a4e49505353504a4d4847434246484c4c4c4c4c4c4c4c4c4745403931281d120700000000000000000000000000020e1925303e4b5864717e8b97a8b2bdb9b1abaaabb1b9b9ada197887b6e6255483b2f22150900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3e3d3b3937332d2c29241d18120b03000000000000000000000000121e2b3845515e6b7884919eabb7c4baada2979290909090909090909090909090909090908e8175685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433c4754616d7a86929facb9c4bbafa3998c8073665c5145382c1f150a000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000815222f3b4855626e7b8897a2adb9b4aa9a8d81746a605c585f676e7b87929facb9b5a89b8f827568544a45515d6775828e9baab4b7aa9d918477695f53473a2e2114090000000000000000000000000000000000000000000000000000000000000a141d29333b444c52555d606363615f57544f473f372d23190f050000000000000000000000000000000000000000000000091623303c4956636f7c899aa4afbbbeb3a99c9082766e63606061676d7a85929eabb8c5baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000006121f2b3844505c666d6d6d6d6d6d6d6d6d6d6d675d5145382c1f13060000030e18212a31373a3b3f3f3f3f3f3f3f3f3f3f3b3a36312921170d1720293036393b3f3f3f3f3f3f3f3f3f3b3a36302920170d1720293036393a3f3f3f3f3f3f3f3f3f3f3b3a37312a21180e03000000030d1925303a444d565e616b70747574716d665f584e463c30261c1106000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b54616d7a86929facb9c2b9ac9f92877b6e61544a3f4953616d7a86929facb9c0b5ab9f92857a6d60544a3f33281c0f0300000000000000000000040b141b22272f34383a3d413f444646443f403c3a37363a3b4040404040404040403a39352f281f160c0100000000000000000000000000000815222e3b4855616e7b8896a1adb9c3bcb8b6b8bcc3b8ab9e9285796c605346392d2013060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b22292e3132323232323232323232323232323232323231302e2d2b27221f1d18120c070100000000000000000000000000121e2b3845515e6b7884919eabb7c4beb3a9a29f9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433946525d6875828e9ba8b2bdc0b5ab9e9285796d6053463c31261b0f010000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000613202d394653606c7985929eabb8b9ac9f92877c716d67696a6f79828f99a3afbbb0a6988c7f7265594c404b5564717e8a98a3aeb8aca095887b6e6255483b31251a0e020000000000000000000000000000000000000000000000000000000006111c262f3b454d565d61676d6f706e6963605951493f352b21160b00000000000000000000000000000000000000000000000714212d3a4754606d7a86939facb9c5b7ab9f948d8076706d6c6e7179828f97a1adb9c6baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000003101c28343f4a545c60606060606060606060605d554b4035291d1004000000060f181f262b2e2f323232323232323232322e2d2a261f170f060e171e252a2d2e3232323232323232322e2d2a251f170e050e171e252a2d2e323232323232323232322f2e2b2620180f06000000000008131e29323b444d5259606367686764605c544e463c342a1e140a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c66737f8c98a3aebabdb2a89b8f8275695e52423846525e6875818e9ba8b2bdbaada2978b7f72665b5044382b1f150a0000000000000000000000020a11171d23292c2d302d3337393938332d2f2e2b2a2d2e3333333333333333332d2c29241d160d040000000000000000000000000000000714212d3a46535f697884919eabb8c4c8c4c3c4c8c2b5a89b8f8275655b5044372b1f120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000911181d2124252626262626262626262626262626262625252322201f1b1713100c0701000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c5bbb3adabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa89b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7bfb6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7bfb6a99c8f8376695c504335414c5663707d8a96a1adb9bfb9ada1978a7e7164584e43372b1e13080000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c100005121f2b3744505b6575828f9ba7b1bbafa39992867e797776787c828f949fabb5b7ab9f94887c6f6255483c4754606d7a86929facb9b1a7998c7f7266574d42362a1e1205000000000000000000000000000000000000000000000000000000000b17222d38424d575e686d747a7c7c7b77706b625b51473d33271c1003000000000000000000000000000000000000000000000613202c3945525d687784919eaab7c4bbb0a69c928d827d7a797a7e848f949fa9b3bec9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000b17232e38424a505353535353535353535353514b43392f24180c0000000000060e151a1e21222626262626262626262622211e1a140d0600050d14191e202126262626262626262621201e19140d0500050c13191d20212626262626262626262622211e1a150e06000000000000020c172029323b42464f54565a5b5a5753514b423c342a22180c020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7985919eaab4b2b2aca196897d7063574d4236414c5663707d8996a0acb2b2b3a99e9184786c6053463c31261b0f03000000000000000000000000060b12181c1f202422272b2d2d2b282222211f1e212126262626262626262620201d18120c040000000000000000000000000000000005121e2a36424d576875818e9ba8b4c1cfd1d0d1cabfb4aa988c7f726553493f33271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c11151718191919191919191919191919191919191918171513120f0b0604000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cdc5bebab8b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5a89b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2a99c8f8376695c5043303a4653606c7884919eabb2b2b2b3a99c9083766a5f53473a2f24190d0100000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8bfb5a99c8f8276695c4f4336291c1000030f1b27333f495363707d8995a0acb8b5aba298928b858383848890949fa6b0bcb1a79c9083766a5f53473b45515d6775828f9cabb5b6aa9d908377695e53463a2d211408000000000000000000000000000000000000000000000000000000030f1c28333f4a545e696e7a8186898988837d726d62594f44382c1f14090000000000000000000000000000000000000000000004111d2935414c566874818e9ba8b2bdc2b8aea49c948f898686878a91969fa6b0bbc5d0baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000006111c2630383f44464747474747474747474745403931271d120700000000000003090e121415191919191919191919191514120e090300000002080e1114141919191919191919191414110e090200000002080d111314191919191919191919191514120e09030000000000000000050e17202930363d44484a4d4f4e4b46454039302a221810060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c38444f5964717e8b97a1a5a5a5a5ab9e9184786c6053463b303a4854606b7784919daaa5a5a5a5a0968a7d7063584e43372b1f12060000000000000000000000000001070c10131417171b1f20201f1c171515121214151919191919191919191413100d07010000000000000000000000000000000000020e1a26313f4b5865727e8b98a9b3becad6ddd3c6baaea298897c6f6256493c2d22170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0b0a08060503000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb5a89b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a59c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a59c8f8376695c5043363844505b6673808d99a6a5a5a5a5a59f94887c6f62554c4135291d110400000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb2b2b2a99c8f8276695c4f4336291c1000000b17222d384854606b7783909da5afbab3aaa29f9892909091969c9fa6b0b8b4aaa0958a7d7064584e4337414c5565717e8b99a3afb8ab9f95877b6e6154483b3025190d01000000000000000000000000000000000000000000000000000006121f2b3844505b666e7b848e9298969590877f726b6054483b31251a0e02000000000000000000000000000000000000000000010d19242f3d4a5663707d8996a0acb9c1c0b6aea69f9c96999399979da0a8acafb6bec7baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000a141e262e34383a3a3a3a3a3a3a3a3a3a3a38352f271f150b010000000000000000020608080c0c0c0c0c0c0c0c0c0c0807050200000000000000020507080c0c0c0c0c0c0c0c0c0807050200000000000000010507070c0c0c0c0c0c0c0c0c0c080806020000000000000000000000050e171f252a33383c3d4142413e3a38342e271e181006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3b4854606b77839098989898989898998c7f72665b5044382c38444f5965727f8c98989898989898988f82766a5f53473a2e21150800000000000000000000000000000000040607060b0f121313120f0b0608060507080d0d0d0d0d0d0d0d0d0706040100000000000000000000000000000000000000000915222f3c4855626f7b8897a1adb9c6d2dfd2c5b8ac9f9285796d6053463a2d201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a89b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b788491989898989898988f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b788491989898989898988f8376695c504336333f4a54616e7b889498989898989898988d8174675d5145392c20130600000000000000000000000000000000000000000000000005121f2b3845525e6b7885919ea5a5a5a5a59c8f8276695c4f4336291c10000006111b2c38444f5964717e8a939ea8b2bab3aeaaa29f9d9c9ea1a8abb0b8baaea2989083786c6053463c323a4754616d7a86929facb9b1a7988b7f7265564c41362a1e110500000000000000000000000000000000000000000000000000000613202d394653606c788390969fa3a7a09993877d7063574d42362a1e1205000000000000000000000000000000000000000000000813202d394653606c7884919ea6b0b9c2c0b8b0aba9aba49fa4abaaa29f9fa4acb6c0baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000020c141c23282b2d2d2d2d2d2d2d2d2d2d2d2c29241d150d0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050d141921272c2f30343534312d2c28231d150c060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c898c8c8c8c8c8c8c8c8c877a6e61544a3f3328323d4754616d7a868c8c8c8c8c8c8c8c8c887b6f6255483c2f221509000000000000000000000000000000000000000000030506060603000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7985929eabb8c5d1d8cfc2b6a99c8f8376665c5044382c1f120600000000000000000000000000000000000000000000000000000000000004090c0e0f13131313131313131311110e0b060100000000000000000000000000000000000000000000000000000000000000000000000001000004060706060300000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a59b8e8275685b4f4235281c0f00000000000000000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8376695c5043362d3846535f6976828c8c8c8c8c8c8c8c8c8c857a6d6054473a2d21140700000000000000000000000000000000000000000000000005121f2b3845525e6b788591989898989898988f8276695c4f4336291c10000000101c27333d4955616c75818e96a0a8b0b9bab4aeacaaa9abacb2b7bbb4aea39f92867b6e665b5044382d3946525e6876838f9ca9b6b6a99c908376685e5246392d20130800000000000000000000000000000000000000000000000000000b1824313e4b5764717e8a959fa8aeb1aba499908377695e53463a2d2114070000000000000000000000000000000000000000000005121f2b3744505b65717e8b949ea7b0b9bec2bbb7b5b5afacafaca29892939aa4afbbbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000020a11171c1f20202020202020202020201f1d18120b03000000000000000000000000000000000000000002070a0c0d1313131313131313130e0d0b080300000001040707131313131313131313130807050200000000000000000000000000000000000000000000000000000000000002090e161c20222327282724201f1c18120b030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707d7f7f7f7f7f7f7f7f7f7f7e71685e5242382d222d3946525d68717e7f7f7f7f7f7f7f7f7f7f7c6f6256493c2f2316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6575828f9ba8b5c2d0cbcbc0b5ab998c807366544a3f34281c10030000000000000000000000000000000000000000000000000000000002090f15191b1c2020202020202020201e1d1b17120c04000000000000000000000000000000000000000000000000000000000000010507070b0d070c10121313120f0b060000000000000000000000000000121e2b3845515e6b78849198989898989898989898989898989898989898989898989898988e8275685b4f4235281c0f000000000000000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7e7164574a3e3124170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7e7164574a3e312a36424d57626f7c7f7f7f7f7f7f7f7f7f7f7f7b6e6155483b2e22150800000000000000000000000000000000000000000000000005121f2b3845525e6b78858c8c8c8c8c8c8c8c8c8276695c4f4336291c100000000b16212d3945505a606d7a8491969fa6adb2b7b9b8b6b6b7b9b8b5afaaa29f918b7e71695f544a3f332a36414c5665727f8b98a7b1b9ac9f93867a6d6154473a2f24190d01000000000000000000000000000000000000000000000000000f1c2935424f5c6875828f9ba7b1babdb5aba095877b6e6154483b2e21150800000000000000000000000000000000000000000000030f1b27333f4953626c75828f959fa6adb3b7b8b9b9b8b6afaaa29a928588939facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000060b1012131414141414141414141413100c07010000000000000000000000000000000000000000070d1316191a2020202020202020201b1a18140f0802080d111314202020202020202020201514120e0903000000000000000000000000000000000000000000000000000000000000050b101416171a1c1b181313100c0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3b4854606b7072727272727272727272716c61564c412f261c2935414c56616c71727272727272727272726f6a6054483b2e2215090000000000000000000001010606060606060606050400010406070a0d0e0f0f0e0c080806020000000000000000000000000000000000000000000000000000000000030f1b27333f495365727f8c98aab4bebfbfbfbbafa399897d7063564a3d2e23170c00000000000000000000000000000000000000000000000000000000030c141b202528282d2d2d2d2d2d2d2d2d2b2a27231d160e0600000000000000000000000000000000000000000000000000000002080d111314171a1c181c1f20201f1c17110a02000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8275685b4f4235281c0f000000000000000000000000000000000000000000000b1724313d4a56626c71727272727272727272716c6155493d3023170a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313d4a56626c71727272727272727272716c6155493d3026313b4754606a6f72727272727272727272726e695f53463a2d211407000000000000000000000000000000000000000000000000000c1825323f4b5865727f7f7f7f7f7f7f7f7f7f7e7164574a3e3124170b00000005111d28333e45515d676e7b8490949ea1a8abacb2afafb4aeacaba39f98928a7f726c62574d42382d25303b4854616e7b8795a0acb8afa4998b7e7165564c4135291d110400000000000000000000000000000000000000000000000000111d2a3744505d6a7783909daab6c2c7bdb1a796897d706356493d3023160a00000000000000000000000000000000000000000000000b17222d3841505a616e7a8390949ea1a9aaabacacaba9a59e9892887e87929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000030607070707070707070707070604000000000000000000000000000000000000000000010a12191e2325262d2d2d2d2d2d2d2d2d282724201a130c13191d20212d2d2d2d2d2d2d2d2d2d21211e1a140d05000000000000000000000000000000000000000000000000000000000000000407090a0e0f0e0b070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c38444f5960636565656565656565656564615a50443b301d1924303a44505a6164656565656565656565656260584e43382c1f13070000000000000003080b0d0e13131313131313131111080d111314171a1b1c1b1a191514120e0903000000000000000000000000000000000000000000000000000000000b17222d3c4955626f7c8898a2aeb2b2b2b2b2ac9f92867a6d6053473a2d201406000000000000000000000000000000000000000000000000000000020c151e252c3134353939393939393939393837332e2820180e04000000000000000000000000000000000000000000000000050b1013191d202124272923282c2d2d2b28221c140b0200000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7d7063574a3d3024170a000000000000000000000000000000000000000000000915212e3a45505a626565656565656565656564615a5045392d21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915212e3a45505a626565656565656565656564615a5045392d1f2b37434e5860626565656565656565656565615f574d42372b1e1205000000000000000000000000000000000000000000000000000b1824313d4a56626d72727272727272727272716c6155493c3023160a000000000c17222935414c555f696e7a828b91969b9ea1a8a2a3aaa39f9c99928e867e726d635a50453c2f26212d3a46535e697783909daab6b5ab9c8f8276685d5245392c20130700000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c0c4bbafa399897c6f6356493c30231609000000000000000000000000000000000000000000000006111b262f3e46525e686e7a828b91979a9d9e9f9f9e9c99938e867e7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a131c242a2f32333939393939393939393433302b251d161e24292c39393939393939393939392e2d2a251f170f0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101b27323d474f545659595959595959595959575550483e32291e131e28323e485055575959595959595959595956544e463d32271b0f03000000000001080f14181a1b20202020202020201e1d13191d20212427282928272522211e1a15100b0600000000000000000000000000000000000000000000000000000613202d3a4653606d7985929fa5a5a5a5a5a5a59d908376675d5145392c20130600000000000000000000000000000000000000000000000000000009141e2730373d414246464646464646464644433f39322a20160c0100000000000000000000000000000000000000000003090e161c1e252a2d2e3134362e34383a3938332d261d140a00000000000000000000000b1724313d4a56626c7172727272727272727272727272727272727272727272727272727272706b6155483c2f2316090000000000000000000000000000000000000000000005111d29343f48505658595959595959595959575550483e33281d1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d29343f48505658595959595959595959575550483e33281d27323d464e5456595959595959595959595955534d453c31261a0e02000000000000000000000000000000000000000000000000000915222e3a45515b626565656565656565656564615a5044392d21140800000000050d19242f3a434d575f686e777e848a8e9196959696959892908c87817b716c635b51483f332a1d1e2a36424d5766737f8c99a8b2b9ac9f92867a6d6054473a2f24180c000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa4aeb7b8b2a99f92867a6d6054473a2d2114070000000000000000000000000000000000000000000000000a141d2a36414c565e686d787e858a8e90919292918f8c88817b717986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000050a0e10111212121212121212120e0d0b080300000000000000000000000000000000000000000000000000000000000000000000000000000007121c252e353b3f4046464646464646464641403c362f26202830353946464646464646464646463b3a36312921170d03000000000000000000000000000000000000050a0d0f10131313131313131313130b0b08050100000000000004080a0b1313131313131313131311060503000000000000000000000000000000000000000000000000000000000000000000000000000000000b16212b353d4448494c4c4c4c4c4c4c4c4c4c4b49453e362c20170d16202c363e45494a4c4c4c4c4c4c4c4c4c4c4948433d342b21160a0000000000020b131a202427272d2d2d2d2d2d2d2d2b2a1e24292c2d303335363534322f2e2b261f1c17110a0200000000000000000000000000000000000000000000000006121f2b3844505c6676828f9898989898989898988d807367554b4035291d10040000000000000000000000000000000000000000000000000000040f1b25303942484d4f535353535353535353514f4b443c32281d12060000000000000000000000000000000000000000050d141a21282c3036393a3e40434440444646443f382f261c1106000000000000000000000915212e3a45505a6265656565656565656565656565656565656565656565656565656565656361594f44382c20140700000000000000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4a49453e362c22170c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4a49453e362c2217202b343d4347494c4c4c4c4c4c4c4c4c4c4c4846423c332a1f1409000000000000000000000000000000000000000000000000000005121d29343f49515658595959595959595959575550483e33281c1004000000000008131e28313b454d565e656c71797d818487888989898786837f7b756e69615a51493f362d21181a25313c4855626f7c8896a1acb9aea3998a7e7164554b4035291d10040000000000000000000000000000000000000000000000000916232f3c4956626f7c89929da4aaaba8a1978e8175685d5245392c201306000000000000000000000000000000000000000000000000020b1925303b444c565d666d72797d818485868685837f7b756e697986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000030b11161a1c1d1f1f1f1f1f1f1f1f1f1b1a18140f0801000000000000000000000000000000000000000000000000000000000000000000000000020d19242e3740474b4d5353535353535353534e4c4841382f28323a414553535353535353535353534846423b33291f140900000000000000000000000000000000030a10161a1c1d20202020202020202020181715110c06000000050b10141617202020202020202020201d13120f0b060000000000000000000000000000000000000000000000000000000000000000000000000000040f19232b32383b3d3f3f3f3f3f3f3f3f3f3f3e3d39342c241a0e050e1a242c33393c3e3f3f3f3f3f3f3f3f3f3f3c3b38322b22190f0400000000010b141d252b30333439393939393939393837332f35393a3d40414242413f3b3a37312b28231c140c06000000000000000000000000000000000000000000000003101c28343f4a5466737f8c8c8c8c8c8c8c8c8c8c8a7d7064574a3d2f24180d0100000000000000000000000000000000000000000000000000000915202c37424b53595b6060606060606060605e5c564e44392e23170b00000000000000000000000000000000000000070f171f252a33383a4146474a4d4f514a515353504a42382d22170b0000000000000000000005111d29343f485056585959595959595959595959595959595959595959595959595959595957554f473e33281c1004000000000000000000000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3e3d39332c241a10050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3e3d39332c241a1019222b32373b3c3f3f3f3f3f3f3f3f3f3f3f3b3a37312a21180e030000000000000000000000000000000000000000000000000000010c18232d373f454a4b4c4c4c4c4c4c4c4c4c4a49443e362c22170b000000000000010c161f29333b444c535b60666d7075787a7b7c7c7c7b7976726e69615e5750483f372e241b0f15212e3b47535f6a7884919eabafb5ab9b8f8275675d5145392c1f13060000000000000000000000000000000000000000000000000815222e3b4754606a74808d929b9e9e9d9691857b6e61564c4135291d11040000000000000000000000000000000000000000000000000008141e29323b444c545c60676d7074777879797876736e6a616c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000050d151c2226292a2b2b2b2b2b2b2b2b2b272724201a130b02000000000000000000000000000000000000000000000000000000000000000000000007131e2a3540495257596060606060606060605b59534a4136303a444c525f606060606060606060605f534d453b31251a0e020000000000000000000000000000040d151c2226292a2d2d2d2d2d2d2d2d2d2d2524211d171109000810171c2123242d2d2d2d2d2d2d2d2d2d2a201f1b17110a020000000000000000000000000000000000000000000000000000000000000000000000000007111921272c2f303232323232323232323231302d28221a12080008121a22282d3031323232323232323232322f2e2c2721191007000000000008131d262f363c4041464646464646464644433f3a4145474a4d4e4f4e4d4c4847423c38342e261e180f0700000000000000000000000000000000000000000000000b17232e3b4855616e7b7f7f7f7f7f7f7f7f7f7f7f7a6d6054473a2d2114070000000000000000000000000000000000000000000000000000000c1925313d48535d65686c6c6c6c6c6c6c6c6c6b6760564b3f33271b0e020000000000000000000000000000000000071019212930363e44484c5254575a5c5e5f5c60605b544a3f33281c0f03000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a48443e352c21160b0000000000000000000000000000000000000000000000000009121b22292e313232323232323232323231302d28221a120800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b22292e313232323232323232323231302d28221a1208101920272b2e2f32323232323232323232322e2d2b261f180f060000000000000000000000000000000000000000000000000000000006111b252d343a3d3f3f3f3f3f3f3f3f3f3f3e3c39332c241a100500000000000000040d182129323b414950545c606468676d6f6f706f6e6d6666615e57524d453e362e251c1209121f2b37434e586774808d9aaaa2a2a29f9286796d6053473a2d20140700000000000000000000000000000000000000000000000006131f2b37434e58606d7880898e9191908c847c6f695e52433a2f24190d0100000000000000000000000000000000000000000000000000020d172029323a424a50555d6064676a656c6c656966625f586c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000030d171f272d3236373838383838383838383433302b251d140b01000000000000000000000000000000000000000000000000000000000000000000000a16232f3b47525b63666c6c6c6c6c6c6c6c6c67645d53483c35414c565d6c6c6c6c6c6c6c6c6c6c6c6c5e574d42362a1e120500000000000000000000000000030d161f262d3235363939393939393939393931302d29221b1209121a22282d303139393939393939393939372d2b27221b140b0200000000000000000000000000000000000000000000000000000000000000000000000000070f161b202223262626262626262626262423211d1710080000000810171c2123242626262626262626262623221f1b160f070000000000030f1a252f3841484c4e5353535353535353514f4b474c5254575a5b5c5b5a5855534d46443f38302a21191007000000000000000000000000000000000000000000000614212d3a46535f696e72727272727272727272726d685d5245392c2013070000000000000000000000000000000000000000000000000000020e1b2834414d59656f757979797979797979797772675c4f43372a1d110400000000000000000000000000000000060f19222b333b42464f55565e616467696a6c666d6c665b5044382b1f12060000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3d3c38332c231a100500000000000000000000000000000000000000000000000000000911181d2124252626262626262626262423211d17100800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000911181d2124252626262626262626262423211d17100800070f161b1f2223262626262626262626262622211e1a140e0600000000000000000000000000000000000000000000000000000000000009121b23292e313232323232323232323231302d28221a1208000000000000000000060f1820292f383f444a515357555d606263636261605c5454534d46423b332c241c130a030f1b26323d4a5663707d89989595959595988a7d7064574a3d3124170a000000000000000000000000000000000000000000000000030f1b27323d44505c666d747d828485837f796f6a5f574d4231281e1308000000000000000000000000000000000000000000000000000000050e17202830383f444b5153575b535b60605b535955535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000b151f2931383e424445454545454545454541403c362f261d1308000000000000000000000000000000000000000000000000000000000000000000000c1925323f4b57636d73797979797979797979746f64594c383945525d68767979797979797979797976695e53463a2d211407000000000000000000000000000a151f2831383e4243464646464646464646463e3d39342d241b111a242c33393c3e46464646464646464646443937332d261d140a0000000000000000000000000000000000000000000000000000000000000000000000000000040b1013161619191919191919191919181715110c060000000000050c11141717191919191919191919191615130f0a040000000000000814202b36414a53585a60606060606060605e5c5653565d6063666869686765625f5753504a423c332b22190f0500000000000000000000000000000000000000000005121e2a36424d575f616565656565656565656565605d564c4135291d11040000000000000000000000000000000000000000000000000000020f1c2835424f5b68758186868686868686868684776b5e5144382b1e1105000000000000000000000000000000020b18212b343d454d52596163686d71737677787979786c605346392d201306000000000000000000000009121b22292e313232323232323232323232323232323232323232323232323232323232302f2c28211a110800000000000000000000000000000000000000000000000000000000060c11151718191919191919191919171714110c0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c11151718191919191919191919171714110c05000000040a0f13151619191919191919191919191514120e090300000000000000000000000000000000000000000000000000000000000000000911181d2224252626262626262626262423211c1710080000000000000000000000060e171d262d33394044464a4c5154555656565453504a4846423b363029211a120a01000a13202d3a4653606d798689898989898989898175685b4e4235281b0f020000000000000000000000000000000000000000000000000a152028343f4a545c606b7075777876726d675f584e453b301f160c0100000000000000000000000000000000000000000000000000000000050e161e262e34394045474a4e4950535350494c48535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080005111c27313b434a4f505252525252525252524e4c4841382f251a0f030000000000000000000000000000000000000000000000000000000000000000030f1b27333f4953667380868686868686868686817467544a3f3a4754606d7a868686868686868686867b6e6154483b2e21150700000000000000000000000005101c26313a434a4e50535353535353535353534b49453f362d2217222c363e44494a535353535353535353535046443f382f261b11060000000000000000000000000000000000000000000000000000000000000000000000000000000407090a0c0c0c0c0c0c0c0c0c0c0b0a080500000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c0909070300000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6b67605f62686d707374757574726e6965605c544e463d342b21170b020000000000000000000000000000000000000000020e1a26313b454d5355595959595959595959595954524c443a2f24190d010000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e939393939393939184776b5e5144382b1e11050000000000000000000000000000000a141d2a333d464e575e616b70767a7d8082848586867d706356493d3023160a0000000000000000000000000911181d212425262626262626262626262626262626262626262626262626262626262423201c1610080000000000000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0b0a0805000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0b0a080500000000000000030608090c0c0c0c0c0c0c0c0c0c0c080705020000000000000000000000000000000000000000000000000000000000000000000000060c12151818191919191919191919171614100b0500000000000000000000000000050b141b22272e34383a3d414547484949494846443f3b3a36312a251f170f0800000006121f2c3844515c666f7c7c7c7c7c7c7c7c7c7c6f6255483c2f22150900000000000000000000000000000000000000000000000000040c17232e38424a50596063686b6b6a66605d554e463c33291f0d04000000000000000000000000000000000000000000000000000000000000040c141c23282f35393a3d413f444646443f4046535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000a16222d38434d555b5d5e5e5e5e5e5e5e5e5e5a58534a41362b201408000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6576828f93939393939393908377665c50443d495663707c8993939393939393938a7e7164574a3e2e23180c0000000000000000000000000a16222d38434c545a5d60606060606060606060585650483f34291d28333e48505557606060606060606060605d53504941382d22170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2733404c58646e7479797979797979797772606a6f747a7d80818281807f7b77716d665f584e463d33291d140a00000000000000000000000000000000000000000009141f2a333b4246484c4c4c4c4c4c4c4c4c4c4c4745413a32281e1308000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9b9f9f9f9f9f9e9184776b5e5144382b1e1105000000000000000000000000000006111c262f3b454e5860696e767d82868a8d8f919292897c706356493d3023160a00000000000000000000000000060c1115171819191919191919191919191919191919191919191919191919191919171614100b05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105090b0c0c0c0c0c0c0c0c0c0c0b0a080400000000000000000000000000000000020a11171c23282c2d2f35393a3c3c3d3c3b3a38342e2d2a251f1a140d050000000004101c2834404a545f6a6f6f6f6f6f6f6f6f6f6f6a5f53473b2e211508000000000000000000000000000000000000000000000000000006111c2630383f444f54565b5e5e5d5953514b433c342a21170d0000000000000000000000000000000000000000000000000000000000000000020a11171d24292c2d312d3337393937332d46535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000e1a26323e4a555f666a6b6b6b6b6b6b6b6b6b67645c53483c3024180b00000000000000000000000000000000000000000000000000000000000000000613202d394653606c7985929f9f9f9f9f9f9f9286796d6053463f4c5965727f8c989f9f9f9f9f9f9a8d807467544b4034281c100400000000000000000000010d1a26323e4a545e66696c6c6c6c6c6c6c6c6c6c64625a5045392d212d3944505a61646c6c6c6c6c6c6c6c6c6c6a605b53493f33271b0f0300000000000000000000000000000000000001070b0f1112131313131313131313130706030000000000000000000000000000000000000000000000000000000000010406070b0e0e0c08080602000000000000000000000000000e1b2734414e5a677480868686868686868684776d737c81868a8d8e8f8e8d8b88847e786e6a60584e453b2f261b11060000000000000000000000000000000000000000030e18212a31363a3b3f3f3f3f3f3f3f3f3f3f3f3a39352f2820160c01000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8acacacaa9e9184776b5e5144382b1e110500000000000000000000000000000b17222d38424d57606a6f7b828a8f92999a9c9d9f96897c706356493d3023160a00000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0a0907040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030608090a0a0a0a0a0a0a0a07070501000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b12181c1f2024292c2d2f30302f2e2d2b2823211e1a140e09020000000000000c18232e39424e585f626262626262626262625f584e43372b1f12060000000000000000000000000000000000000000000000000000000a151e262e343d4448494f5152504c4745403a312a22180f0500000000000000000000000000000000000000000000000000000000000000000000060b12181d1f202422272b2d2d2b273946535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101c2936424f5b667177787878787878787878746e64584c4033271a0d01000000000000000000000000000000000000000000000000000000000000000815222f3b4855626e7b8897a2adacacacaea398887b6f625548404b556875818e9ba8acacacaca99d908376665c5145382c1f130600000000000000000000030f1c2935424e5a66707679797979797979797979716c6256493d3327303c4955616c7179797979797979797979776c655b5044372b1f12050000000000000000000000000000000000050c12171b1e1e2020202020202020201f1312100c060000000000000000000000000000000000000000000000000001070d101314181a1b191514120f090300000000000000000000000e1b2734414e5a6774818d939393939393918477787f878e9298999b9c9b9a9896918b837c6f6a60574d41382d22170b000000000000000000000000000000000000000000060f181f262a2d2e32323232323232323232322d2c29241e160d0400000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5b9b7aa9e9184776b5e5144382b1e110500000000000000000000000000030f1c28333f4a545f696f7c858f949c9fa3aba9aaa396897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f13151616161616161616161413110d080200000000000000000000000000000000000000000000000000000000000000000000000000000000030608090a0a0a0a0a0a0a0a0a0a070705010000000000000000000000000000000000000000000000000000000000070c101213191d20212223232321201f1c1714120e0903000000000000000007121c27303c464e5355565656565656565655534e463c32261b0f03000000000000000000000000000000000000000000000000000000030c151c232833383b3d424445433f3a39352f281f18100600000000000000000000000000000000000000000000000000000000000000000000000001070c10131417171b1f20201f2c3946535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800111d2a3744505d6a77838585858585858585858074675a4e4134271b0e01000000000000000000000000000000000000000000000000000000000000000b1825313e4b5864717e8b97a9b3beb9bfb4aa978b7e7164584b45515c677784909daab7b9b9b9ac9f9286796d6053463a2d2013070000000000000000000003101d2a3643505d697682868686868686868686867e7164594f44382c38444f5964717e8686868686868686868683786c605346392d20130600000000000000000000000000000000060f171d23272a2b2d2d2d2d2d2d2d2d2d2c201f1c17110a0300000000000000000000000000000000000000000000040c12181d20202427272622211f1a150c07010000000000000000000e1b2734414e5a6774818d9a9f9f9f9f9e918479818c92999fa3aaa7a8a8a7a8a09e9590857c6f695e53493f33271b0f03000000000000000000000000000000000000000000060e141a1e2122262626262626262626262621201d19130c040000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000000006121f2b3844505b666e7b8592979fa6acafb5b5afa396897c706356493d3023160a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070e151b1f2222232323232323232321201d19130c0400000000000000000000000000000000000000000000000000000000000000000000000000040a0f131516171717171717171717171413110d080200000000000000000000000000000000000000000000000000000000000406080d11131415161616151312100b06050200000000000000000000000b151e2a343c43474849494949494949494847433c342a20150a0000000000000000000000000000000000000000000000000000000000030a111721272c2f3035383837332d2c29241d160d0600000000000000000000000000000000000000000000000000000000000000000000000000000000040607060b0f121313202c3946535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b788491919191919191918e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000000000004101d2935404b556774818d9aa7b4c0cfc0b3a79a8d8074675a4d4753606d7986929facb9c5c7baaea398897c6f6256493c2f23160800000000000000000000000a1723303d4a5663707d8994939393939393939083776b6055483c313b4854606b76839093939393939393958a7d70655b5044372b1f1205000000000000000000000000000000000f1821282f343738393939393939393939392d2c28231c150c030000000000000000000000000000000000000000080d161d24292c2d313434332f2e2b262018120b0300000000000000000e1b2734414e5a6774818d9aa7acacaa9e9184818e939fa3abaeb4b4b5b4b3b2aca7a09792867b6e655b5044372b1f14090000000000000000000000000000000000000000000003090e12141519191919191919191919191413110d0801000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e1105000000000000000000000000000613202d394653606c78839097a1a9b0b9bbb9b8afa396897c706356493d3023160a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007101920272b2e2f30303030303030302e2d29251e160e040000000000000000000000000000000000000000000000000000000000000000000000070f161b1f22232323232323232323232321201d19130c05000000000000000000000000000000000000000000000000000000000000000104060709090a0908070603000000000000000000000000000000030c18222a31373a3c3c3c3c3c3c3c3c3c3c3b37322a22180e0400000000000000000000000000000000000000000000000000000000000000060c161c202223282b2b2a2620201d18130c040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003050613202c3946535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919e9e9e9e9e9e9b8e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000000000006131f2c3945515d677783909daab6c3cfc2b6a99c8f837669574d4956626f7c8999a3afbbc7cbbfb4aa988b7f7265584c3f3025190d01000000000000000000000916222f3c4854606b7683909ca69f9f9f9fa095897d7063584e4337434e5863707d89959f9f9f9f9fa79d9083786c6053493f33271b0f03000000000000000000000000000000060f212a333a404345464646464646464646463a38342e261e150a0000000000000000000000000000000000000008111a1f282f35393a3e41413f3b3a373129241d150d03000000000000000e1b2734414e5a6774818d9aa7b4b9ac9f92868e939da5afb5b0b2b5b7bbc0bdb9b1a9a1988f82776c6053463b31251a0e020000000000000000000000000000000000000000000000020507080c0c0c0c0c0c0c0c0c0c0c070704010000000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000006131f2b38434e5865717e8b959fa9b3bbbab2adaba5ab96897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040e19222b32373b3c3d3d3d3d3d3d3d3d3a3935302820160c0200000000000000000000000000000000000000000000000000000000000000000007101920272b2e2f303030303030303030302e2d2a251e170e050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006101820262b2e2f2f2f2f2f2f2f2f2f2f2e2b2620181006000000000000000000000000000000000000000000000000000000000000000000050b101316161c1e1f1d191413110d0701000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3946535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eababababa89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a86929facb9c5d2c5b8ab9f928578695f534b5865717e8b98abb5c0cbd1c1b4a89b8e817568564c41362a1d1105000000000000000000000713202c38444f5963707d89949fabacacb1a79c8f82766a5f53473b47535f6a75828f9ca7b1acacaca0958a7d70655b5041382d22170b000000000000000000000000000000030e1821333c454b50515353535353535353535246443f3830261c1106000000000000000000000000000000000008121a232c31394045474b4d4e4c4847433c352f271f150c030000000000000e1b2734414e5a6774818d9aa7b4baaea39992999da5aba6a4a3a5a9abb0babfc3bbb3aa9f948a7d7164574d42362a1e12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000000815222e3b4754606a7784919da7b1bbb9b1a8a19e999599897c706356493d3023160a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a15202b343c43474949494949494949494746413a32281e13080000000000000000000000000000000000000000000000000000000000000000061019222b32383b3c3d3d3d3d3d3d3d3d3d3d3a3936302920170c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e151a1f2122232323232323232322211f1b150e060000000000000000000000000000000000000000000000000000000000000000000000000407090a0f1112100c070604010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3946535f6c7986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7b8b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8999a3afbbc7d3c6baada297887b6e61554a546774818d9aa7b4c0d1d1c4b7aa9e918477685e5246392d2013070000000000000000000004101c27333d4854606b7683909ca6b0bcb7ab9f94887c6f62564d424d57626f7c88949eaab9bcb1a79d9083786c6053493f2f261b110600000000000000000000000000000009141f2a33454e565c5e6060606060606060605f53504a42382e23170c00000000000000000000000000000000050e1a242c353e434b5153575a5a5955534e45403931271e150b0000000000000e1b2734414e5a6774818d9aa7b4bfb4aba39fa3a8a19e999797989c9fa6aeb4bcc5bcb0a69c8f8276695e53463a2d21140700000000000000050a0d101013131313131313131313131313131313131212100e0b07070401000000000000000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000000916232f3c4956626f7c8995a0acb9bcb1a7a096918c8886877d6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27323c464e5455565656565656565654524c443a3025190d01000000000000000000000000000000000000000000000000000000000000040e18222b343d4347494a4a4a4a4a4a4a4a4a4a4746413a32291e13080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a0f12151516161616161616161515120f0a0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3946535f6c7986929facb9b9ada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3844505b667986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c99abb5c0cbd6cabeb3a9978a7d706457505c667683909da9b6c3d0d2c5b9aca096877a6d6154473a2e21140600000000000000000000000b16212c38444f5963707d89949fabb7bbb0a69b8e8174685e5246525e6974818e9ba6b0bbb8aca0958a7d70655b5041382d1d140a000000000000000000000000000000020e1a26313b455660686b6c6c6c6c6c6c6c6c6c6c605c544a3f34281c10030000000000000000000000000000020d17202c363e474f555d6064676766625f58514b433930271c120700000000000e1b2734414e5a6774818d9aa7b4c0bdb4aeaca59e96918d8a8a8b8f949fa2aab4bfc2b9ac9f93877b6e6154483b2e2115080000000000030a11161a1c1d20202020202020202020202020202020201f1e1d1a181413110d080100000000000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000000d192633404c5966737f8c99a7b1bcb8aca09591847f7c7a796f6b6054483b2f221509000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2b37434e5860626363636363636363615e564c4135291d11050000000000000000000000000000000000000000000000000000000000000a15202a343d464e54565656565656565656565654524c443a3025190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003060809090909090909090909080603000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004060707070707070707070707060400000000000000000000000000000000000000000000000000000000000000000000000613202c3946535f6c7986929facadadada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f394653606c7986939facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000005121e2a36424d576875828f9ba8b5c2d1dbd0bfb3a6998c8073665953606d7985929facb8c5d2d5c9bdb2a8968a7d7063574a3d2d22170b000000000000000000000005101c27333d4854606b7683909ca6b0bcb9ac9f92867b6e61554c56616e7b86929facb9bcb1a79d9083786c6053493f2f261b0b0200000000000000000000000000000005121e2a36424d57687278797979797979797979796d665c5044382c1f1206000000000000000000000000000008141e29323e48505961676d717474726e6a605d554b42392e23180c00000000000e1b2734414e5a6774818d9aa7b4c0c6bbb0a69e938e84807d7d7f828a9298a2aebac2bbafa49a8b7e7165584b3e3225180b00000000040d151c2226292a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c2b2a272421201d1913100b050000000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e1105000000000000000000000004101c2934404b556976828f9ca9b5bfb4aa9d91837a726f6d676360594f44382c1f130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4754606a6f70707070707070706d685e5246392d2013070000000000000000000000000000000000000000000000000000000000030f1b26313c464e58606263636363636363636363615e564c41362a1d110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070c1013131414141414141414141313100c070000000000000000000000000000000000000000000000000000000000000000000613202c3946535f6c7986929fa0a0a0a0a094877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366544a3f3b4754616d7a879aa4afbbbbafa399867a6d6053473a2d20140700121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000000000714202d3a46525e697884919eabb8c4d1dbcfc2b5a89c8f8275695655626e7b8898a2aebac6d3d9cebfb3a6998c807366544a3f33281c0f0300000000000000000000000b16212c38444f5963707d89949fabb7baaea3998d8073675d525d6873808d99a3aebbb8aca0958a7d70655b5041382d1d140a000000000000000000000000000000000714212d3a46535f69788486868686868686868686786d6053463a2d20130600000000000000000000000000020e1925303b44505a616b70797e80817f7b746d675d544a4034281c1207000000000e1b2734414e5a6774818d9aa7b4c0c4b7ab9f948e817973717072767d86929fa6b0bcc0b6ac9a8d8174675a4e4134271b07000000030d161f272d323637393939393939393939393939393939393939383634312d2c29241e1c160f0a04000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e1105000000000000000000000006131f2c3845515c677885919eabb8baaea2988a7d706862605d55544f473d32271b0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c7c7c7c7c7c7c7c7d7a6d6154473a2e211407000000000000000000000000000000000000000000000000000000000006121f2b37434e58606a6f707070707070707070706d685e5246392d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b12181c1f20202020202020202020201f1c18120b03000000000000000000000000000000000000000000000000000000000000000613202c3946535f6c79869293939393939393877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0b4a89b8e8175665c5048474c56636f7c8996acb6c0b9ac9f928679675d5145392c20130600121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000000000815212e3b4854616e7b8796a1adb9c5d2ded1c4b8ab9e918478685e5764717e8a97aab4bfcad6dccfc2b6a99c8f8276665b5044382b1f1206000000000000000000000005101c27333d4854606b7683909ca6b0bcb4ab9f9285796d6055606d7a85929fabb5bcb1a79d9083786c6053493f2f261b0b02000000000000000000000000000000000815222e3b4855616e7b88969393939393939398897c6f6256493c2e23170b0000000000000000000000000005111e2a36414c56616c717d858a8d8d8c8781796d665c5144392e23180c000000000e1b2734414e5a6774818d9aa7b4c0bdb2a89c8f82786d676464656b707e8a949fabb7c3b6a99d9083766a5d50432e23180c0000000a151f2831383e42434646464646464646464646464646464646454543413e3a39352f2c27211b150b060000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000714202d3a4753606d7a86939facb9b8ac9f9285796d605653514b48443d352b21160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2a3744505d6a778389898989898989897d7063574a3d3024170a00000000000000000000000000000000000000000000000000000000020b1a232e3a47535f6a6f7c7d7d7d7d7d7d7d7d7d7d7a6d6154473a2e21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c151d23282c2d2d2d2d2d2d2d2d2d2d2d2c28231d150c030000000000000000000000000000000000000000000000000000000000000613202c3946535f6c79878686868686868686867a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0b8ab9e9185796d60595454565e6873808d99a6b3c0b8ab9f9285786c554b4035291d110400121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000000000b1724313e4a5764717d8a97a8b2bdc9d2d1d2c5b9ada196877a6d615a6773808d9aa6b3c0d0d1d2d2c5b8ab9f9285796c605346392d2013060000000000000000000000000b16212c38444f5963707d89949fabb7baada2978b7f72665c67727f8c98a2aebdb8aca0958a7d70655b5041382d1d140a00000000000000000000000000000000000b1825323e4b5865717e8b98a89f9f9f9f9faa998c7f7266544a3f34281c10030000000000000000000000000714202d3946525e68717e8791979a9a9a938e82786d60544a4034281c10040000000e1b2734414e5a6774818d9aa7b4c0b8aca096887c6f665d555759616c7683909ca9b6c3b8ab9e9185786b544b4034281c10040005111c27313a434a4e5053535353535353535353535353535353535251504d4b4745413a38332b272017110a02000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000815222e3b4855616e7b889aa4afbbb6a99d908376665c504745403a38322b23190f04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104111d2a3744505d6a7783909696969696968a7d7063574a3d3024170a010000000000000000000000000000000000000000000000000000000a141d2c38434e58626f7c87898989898989898989847a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b151e272e34383a3a3a3a3a3a3a3a3a3a3a38342e271e150b00000000000000000000000000000000000000000000000000000000000006121f2c3845525e6a75797a7a7a7a7a7a7a7a7a776c605346392d201306000e1b2734414e5a6774818d9aa7b4c0b9ada1978b7e716b63616162686e7a85929eabb8c4b7aa9d9184776a5e51442f24180d0100121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000003101c28343f4a546773808d9aa6b3c0cac6c5c6c8bdb2a896897d7063576976828f9ca9b6c2c5c4c5c9c6baaea298887b6f6255483c2f22150700000000000000000000000005101c27333d4854606b7683909ca6b0bbb3a99e9184786c606d7985919eaab4bcb1a79d9083786c6053493f2f261b0b020000000000000000000000000000000005121e2a36424d576874818e9ba7acacacacaca89c8f8275665c5044382b1f12060000000000000000000000000814212e3b4754616e7a869299a1a9aca49f948c7f73665c5144382c1f12060000000e1b2734414e5a6774818d9aa7b4c0b7aa9d9184776a5f544b4a505a65727e8b98a5b1beb8ac9f928579665c5145382c1f1306000a16222d38434d555b5d60606060606060606060606060606060605f5e5d5a5754524c48443d373227221b140b030000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000916232f3c4956626f7c8995acb6c0b5a89c8f827569544a3f39352f2c272119110700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030608090d0d111d2a3744505d6a7783909da3a3a3a3968a7d7063574a3d3024170d0d0d0c0a060200000000000000000000000000000000000000000006111b262f384854606a75828f99969696969696948a7e71675d5145392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d2730394045464747474747474747474645403930271d12070000000000000000000000000000000000000000000000000000000000000613202c3945515d676d6d6d6d6d6d6d6d6d6d6c655b5044372b1f1205000e1b2734414e5a6774818d9aa7b4c0beb3a99f92867d74706e6e6f737a829097a2adb9c1b4a89b8e8175685b4e4235281b070000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000006121f2c3844505c667683909ca9b6c3beb9b8b9bbc0b2a5998c7f72665e697885929eabb8bdb9b8b9bdc4beb3aa988b7e7165584b3e2f24180d010000000000000000000000000b16212c38444f5963707d89949fabb7b9aca0968a7d7066717e8b97a1adbcb8aca0958a7d70655b5041382d1d140a00000000000000000000000000000000000714212d3a46535f697884919eabb7b9b9b9b8ab9f9285796d6053463a2d2013060000000000000000000000000d1a2633404d596673808c98a2abb3b6afa69f9285786d6053463a2d2013070000000e1b2734414e5a6774818d9aa7b4c0b4a79b8e817468584e423e4955626f7c8895a2afbbbaaea39886796d6053463a2d201307000d1a26323e4a555f666a6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6b696764605d56544f47433c332d261d150c0300000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1623303d495663707c8996a3afbcb5a89b8f8275685c4f422e29241d1b160f07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a0f1215151a1a1a1d2a3744505d6a7783909daaafafa3968a7d7063574a3d30241a1a1a191916120d0700000000000000000000000000000000000003090e17222d38414f59626f7c89949eaba3a3a3a3998f82766c61554b4035291d10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e39434b515353535353535353535353514b43392e23180c00000000000000000000000000000000000000000000000000000000000004101d2935404b555d60606060606060606060605b53493f33271b0f03000e1b2734414e5a6774818d9aa7b4c0c4baaea2989287817d7b7a7c7f8590959fa9b3bebdb2a8988c7f7265594c3f3226190c0000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000713202d3a4653606d7985929facb8bbb3adabacafb6b4a89b8e817568616e7b8797a1adb9b2adabadb2bbc1b4a79a8e817467554b4135291d110400000000000000000000000005101c27333d4854606b7683909ca6b0bbb2a89c9083766c7884919da9b3bcb1a79d9083786c6053493f2f261b0b0200000000000000000000000000000000000815222e3b4855616e7b8896a1acb9c5c6c6baaea298887c6f6255493c2d22170b000000000000000000000000101d2a3643505d697683909caab4bdc0baada297887c6f6255493c2f2216090000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403a4754606d7a8793a0b5c0bfb4aa94877a6d6154473a2e21140700101c2936424e5b667176797979797979797979797979797979797978787674716d68636059544e443f382f271e150b00000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724303d4a5763707d8a96a3b0bdb5a89b8f8275685c4f42352918130f0a04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e151a1f2122272727272a3744505d6a7783909daab6b0a3968a7d7063574a3d30272727272625231e19120a01000000000000000000000000000002090e141a1e27333f4953606b76828f9ca6b0b0b2a89f92867b6e615a5043392f24180d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b555c60606060606060606060605c554b4034281c10040000000000000000000000000000000000000000000000000000000000010d18242f39434b515353535353535353535353504941382d22170b00000e1b2734414e5a6774818d9aa7b4c0c4bdb4aaa299928e898787888c92979fa7b1bbc5b8aca096897c6f6356493c302316090000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8898a2aebab3a9a19e9fa4acb6aa9d9184776764707d8a97a9b3b2a9a19ea1a9b2bdb7aa9d908477675d5145392c201306000000000000000000000000000b16212c38444f5963707d89949fabb7b7ab9f94897c707d8a96a0acbbb8aca0958a7d70655b5041382d1d140a0000000000000000000000000000000000000b1825313e4b5864717e8b97a8b2bdc9d5cabeb3aa988c7f7265544a3f33281c0f030000000000000000000000111e2a3744515d6a7784909daab7c3c9beb3a996897d7063564a3d3023170a0000000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f3a4653606d798699a3afbbbaada194877a6e6154473b2e21140800101d2a3743505d6a76838686868686868686868686868686868686858483807e7a75706b6260585049413930271c1207000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c07010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006101820262b2e2f34343434343744505d6a7783909daab6b0a3968a7d7063574a3d343434343433322f2a231c130a00000000000000000000000000050d14191f262a2d3744505b65707d89949fabb8b9aca1968d8073695f53483e31281d120700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c676d6d6d6d6d6d6d6d6d6d6d675c5145382c1f130600000000000000000000000000000000000000000000000000000000000007121d28313940454747474747474747474746443f382f261b110600000e1b2734414e5a6774818d9aa7b4c0bab2acababa39f9b96949495999ea1a9b1b9c2bdb2a89e9184776b6054483b2f2215090000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98aab4b9ada19792939aa4afac9f93867a6d66737f8c99a6b2ada1969196a1adb9b9ac9f93867a6d6054473a2d2114070000000000000000000000000005101c27333d4854606b7683909ca6b0bbb0a69b8e817683909da8b2bcb1a79d9083786c6053493f2f261b0b02000000000000000000000000000000000005121e2a36424d576874818e9ba7b4c1cedad0c2b5a89c8f8275665b5044382b1f12060000000000000000000000101c2936434f5c6976828f9ca9b3bdc0b9ada197887c6f6255483c2f2215090000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3844505c667986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a76839093939393939393939393939393939a939291908d8a86827d776f6a605b534a42392e23180e050000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030e18222a31373a3c40404040404044505d6a7783909daab6b0a3968a7d7063574a404040404040403e3b352e251c12070000000000000000000000080e171f252a31363a3f4a54606c7883909da6b0bcb0a69e9184796d60574d42362c1f160c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a54606d797a7a7a7a7a7a7a7a7a796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000010c161f282f35393a3a3a3a3a3a3a3a3a3a3937332d261d140a0000000e1b2734414e5a6774818d9aa7b4bdb2a8a19e9d9fa7a7a3a1a1a2a6abadb3bbc2c0b9ada1968c7f7265594f43382c1f13070000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000005111d2935414c566875818e9ba8b4b8ab9e928588939facafa499897c6f6875828f9ba8b5ab9e9185919ea9b3bbafa499897c706356493d3023160900000000000000000000000000000b16212c38444f5963707d89949fabb7b9ac9f92877e8b959fabbab8aca0958a7d70655b5041382d1d140a0000000000000000000000000000000000000714212d3a46535e697884919eabb7c4d1ded2c5b8ab9f9285796c605346392d20130600000000000000000000000c1926333f4c5966727f8c97a2abb2b5afa69e9185786c605346392d2013060000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f343f4a5f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909d9f9f9f9f9f9f9f9f9f9f9f9f9fa49f9f9e9c9a99928f89837c736c655c544a40342820170c0200000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a15202a343c4347484d4d4d4d4d4d4d505d6a7783909daab6b0a3968a7d7063574d4d4d4d4d4d4d4c4b4640372e23190d0200000000000000000109111a202930363b424648505c66717e8a95a0abb8b4aa9e948a7d70675d51453c31241a0d0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505c6676828686868686868686868073665a4d4033271a0d00000000000000000000000000000000000000000000000000000000000000040d161d24292c2d2d2d2d2d2d2d2d2d2d2d2b27221b140b020000000e1b2734414e5a6774818d9aa7b4b9aca1969190959fa7b0aeadafb2b8b9bec1bdb5afa39e91847a6d6054473d32271b0f030000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000713202d3946525d687784919eaab7b5a89c8f8284919eaab5ab988b7e72687884919eabb5ab998d808d97a2adb9b5ab998c7f7266594c3f31251a0e020000000000000000000000000005101c27333d4854606b7683909ca6b0bbafa3999286929fa7b1bcb1a79d9083786c6053493f2f261b0b020000000000000000000000000000000000000815212e3b4854616e7b8796a1acb9c5d2d2d3c6baada297887c6f6255493c2d22170b00000000000000000000000714212d3a4754606d7a859299a1a8aba39f948b7f72665b5044382b1f12060000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f2e46535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9acacacacacacacacacacacb6afacababa9aba39f9c95908780776d665c51443f32291e130800000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1a26313c464e53555a5a5a5a5a5a5a5a5d6a7783909daab6b0a3968a7d70635a5a5a5a5a5a5a5a5957514940352a1e1206000000000000000009131b232b323b42464d535558606d7884919da7b1baaea3988f82756c61554b403328221c140b0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d798592939393939393938a7d7063574a3d3024170a0000000000000000000000000000000000000000000000000000000000000000040c12181d2020202020202020202020201f1b17110a02000000000e1b2734414e5a6774818d9aa7b2b2ab9e91848390959ea6acb2b7b8bab8b7b6b0aba39f91897d70685d5245392b21160a000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020202000000000000000000000000000000000000000000000000000714212e3a4754616d7a8796a0acb8b3a6998c80818e9ba8b4a79a8e81746d7a8796a1acafa399887c85929eabb8b5a89b8f827568574d42362a1e120500000000000000000000000000000b16212c38444f5963707d89949fabb7b5aba3999299a3afb9b8aca0958a7d70655b5041382d1d140a000000000000000000000000000000000000000b1825313e4b5864717e8b97a8b2bdc9c6c5c6cabeb3a9988c7f7265544a3f33281c0f03000000000000000000000713202c3945525d68707d8791969a9a99928d82786c60544a3f33281c0f030000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6b9b9b9b9b9b9b9b9b9b9c0bbb9b8b7b6b5aeaca79f99928c81786d605a50443a3025190d02000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b37434e585f626767676767676767676a7783909daab6b0a3968a7d7067676767676767676766635b51463b2f23160a0000000000000009121b252d353d444d52575f61676a717e8b95a0acb9b9ac9f92867b6e615a534e453f332d261d140a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3c4855626f7b8898a2a0a0a0a0a096877a6d6154473a2e21140700000000000000000000000000000000000000000000000000000000000000000001070d10131414141414141414141413120f0b060000000000000e1b2734414e5a6774818d9aa6a6a6a69e91847a838f949ea0a8aaabadacaaa9a69e99928b7f726b60564c413529190f04000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0f0f0f0c0b09060100000000000000000000000000000000000000000a1724303d4a5763707d8a96a8b2bdb3a9978a7d7f8c99a5b2aa9d908377707d8996a8b2ac9f928679828f9ca9b6b8ab9e918578695e53463a2d211407000000000000000000000000000005101c27333d4854606b7683909ca6b0bdb5aba39fa3abb5bcb1a79d9083786c6053493f2f261b0b0200000000000000000000000000000000000005121e2a36424d576874818e9ba7b4c1bfbab8babfc2b5a89b8f8275665b5044382b1f12060000000000000000000004111d2935414c56606b707d848a8d8d8c8780786d665b5042382d22170b000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c3c6cdc7c4c3bababababababbbdc0c3bfbbb9b1aba39f938e81746c62564c41362a1e1308000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815212e3a47535f6a6f737373737373737373737783909daab6b0a3968a7d73737373737373737373736d63574b3e3225190c00000000000008111b242d373f474f565e61696e74787c84919ea8b1bdb3a6998d80756f6b625f5751443f382f261c1106000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e8b98aab4adadaa9e918477685e5246392d20130700000000000000000000000000000000000000000000000000000000000000000000000104060707070707070707070706050300000000000000000e1b2734414e5a6774818d9999999999999184777a828b91969a9d9fa29f9e9c98948f877e726d63594f433a2f24190700000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c1b1b1b1b191816120d07000000000000000000000000000000000000030f1b27333f49536673808c99a6b3b9ada197877b7d8996a8b2ac9f928679727f8c98a5b2aa9d908477808d99a6b3b9ada197877b6e6154483b2e2115070000000000000000000000000000000b16212c38444f5963707d89949fabb7bdb5afacafb5bdb8aca0958a7d70655b5041382d1d140a000000000000000000000000000000000000000714202d3a46525e697784919eaab7bcb4aeacaeb4bcb8ab9f9285796c605346392d20130600000000000000000000010d19242f3a444f59606b70797d80807f7b746d665c544a3f2f261c1106000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c3cbc2bcb7b6adadadadadadaeb0b4b8b9bec3bdb5afa59d938b7e71685e52463a3025190d010000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3c4855626f7c808080808080808080808085919eabb8b5a89b8f81808080808080808080807f7366594c403326190d0000000000040d1a232d363f49515960696e747b8084889196a1acbac3b8ac9f9286817c766e6a625b504a42382d22171007000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c566874818e9ba7b4b9b4a89b8e817568564c41362a1d110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818c8c8c8c8c8c8c8c84776d757e848a8d90929792918f8c88827c716c635b51473d31281e130800000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352828282828282625221e181109010000000000000000000000000000000005121f2b3744505b6576828f9ca9b5b8ab9e9285787a8796a1adaea398887b75818e9ba8b4a79b8e81747d8a97a9b3beb3a9978a7e7164574b3e2e23180c00000000000000000000000000000005101c27333d4854606b7683909ca6b0bbc0bbb9bbc0bcb1a79d9083786c6053493f2f261b0b02000000000000000000000000000000000000000815212e3b4854616e7b8796a0acb9b4aaa29fa2aab4baada297887c6f6255493c2d22170b000000000000000000000008131e28323d474f5960676d717374726e69605c544a42382d1d140a00000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c3c2b9b0aba9a0a0a0a0a0a1a2a3a7abadb3bbc1c0bbafa59f92857a6d61564c41362a1e11050000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a8d8d8d8d8d8d8d8d8d8d9197a1adb9b6aa9e938f8d8d8d8d8d8d8d8d8d8d85786b5e5245382b1f1200000000010c161f2c353f48515b626b707b81878d91969ea1a8b2bdc6baaea298928e89827b726d605b544a3f332822190b02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945525d687784919daab7bfb4aa988b7f7265584c3f3025190d01000000000000000000000000000000000000000000010507070a0b0d0d0d0d0c0b06060300000000000000000000000000000000000000000000000a1724303d4a5763707d7f7f7f7f7f7f7f7f7f72656c71787d808485868584827f7b756e6a625a514940352b1f160c0100000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423535353535353532312e29231b1309000000000000000000000000000000000613202d394653606c7985929fabb8b5a99c8f82767884919eabb4aa978b7e7784919daab2a5988b7f727b8897a2adbab3a79a8d807467544b4034281c10040000000000000000000000000000000b16212c38444f5963707d89949fabb7c2c7c5c7c4b8aca0958a7d70655b5041382d1d140a00000000000000000000000000000000000000000b1824313e4b5764717e8a97a8b2baaea2989298a2aebab3a9988b7f726553493f33271b0f0300000000000000000000010c16202c353d474f555c6064676765615f57514a42392f261c0b0200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c3bcb0a69f9c94949494949495979a9ea2a9afb7c1c0baaea2988d8074685e5246392d2014090000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a979a9a9a9a9a9a9a9a9a9ea1a9b3bebbafa59e9b9a9a9a9a9a9a9a9a9a9185786b5e5245382b1f120000000007131d28313d47505a626d727d858e92999ea1a8acb2bac4cabfb4aaa29f9b948f867f746c665b50443f342b1d140a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a86939facb9baaea298887c6f6255493c2f221608000000000000000000000000000000000000000205080d1113141618191a1a19191813120f0b060000000000000000000000000000000000000000000916232f3c4855616b707373737373737373726d6262666c7074777879797776726f6a625f58504840372e231a0d040000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42424242424242423f3e3a352d251b11070000000000000000000000000000000815222f3b4855626e7b8897a2adbab3a6998d807375828f9ba8b3a69a8d807986929facb2a896897c707885929fabb8b6a99d908376665c5145382c1f130600000000000000000000000000000005101c27333d4854606b7683909ca6b0bbc7d2c8bcb1a79d9083786c6053493f2f261b0b020000000000000000000000000000000000000005111e2a36424d576774818e9aa7b4b8ac9f9285929faab4b5a89b8f8275655b5044372b1f12050000000000000000000000040d1a232c353d434b5153575a5a5955534d44403930271d140a0000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c3b7ab9f9490878787878787888a8d92979ea5afb7c1beb3aa9f92867a6d6154473b30251a0e0200000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3a6a6a6a6a6a6a6a6abadb3bbc4c1b7afaaa8a6a6a6a6a6a6a6a69e9185786b5e5245382b1f12000000010d18242f3a434f59626c727f8792979fa3abadb2b9bdc4ccd0c6bcb4aeaca69f98928b80786c605b51463c2f261b11060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1723303d4a5663707d899aa4afbbb8ac9f9285796d6053463a2d201307000000000000000000000000000000000002090e1214191d20212325262727262525201f1c17110a02000000000000000000000000000000000000000714202c38444f596163666666666666666665625b545b6063676a666c666b6965625f58534e463f362e251c1108000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4e4e4e4e4e4e4e4e4c4a463f372d23180d0100000000000000000000000000000b1825313e4b5864717e8b97a9b3beb4aa978a7e7173808c99a6b3a99c8f827c8999a3afaca096877a6d76838f9ca9b6b9ac9f9286796d6053463a2d201307000000000000000000000000000000000b16212c38444f5963707d89949fabb7c4d0c4b8aca0958a7d70655b5041382d1d140a00000000000000000000000000000000000000000714202d3a46525e697784919eaab7b5ab9a8e818e98a3aeb8ab9e9285796c605346392d20130600000000000000000000000008111a232b31394045474a4d4d4c4846423b342e271e150b020000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c3b6a99c90837a7a7a7a7a7a7b7d81858e939da5afbbc4bbaea3998c7f7265574d42362a1e120500000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b3b3b3b3b3b3b3b8b9bec4cdc9c1bbb6b5b3b3b3b3b3b3b3ab9e9185786b5e5245382b1f1200000004111d2935414b55606b717e8b9399a1a9afb5b9bdc3bfbcbcbcbec3bfbab8b0aaa39f928d80746d63584e41382d22170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99acb6c0b6a99c908376665c5144382c1f120600000000000000000000000000000000070c141a1e20252a2d2e30323333333332322d2b28221c140b0200000000000000000000000000000000000004101c28333e474f555759595959595959595856514a5053575a545b605b545c5955534e47433c332d241c130a00000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5b5b5b5b5b5b5b5b5b595751493f35291e12060000000000000000000000000004101d2935404b556774818d9aa7b4baaea298887b6e707d8a97a9b3ab9f92857e8b98abb5aa9e9184776873808d9aa6b3baaea398897c6f6256493c2f2316080000000000000000000000000000000005101c27333d4854606b7683909ca9b6c3cfc3b7aa9d9083786c6053493f2f261b0b0200000000000000000000000000000000000000000814212e3b4754616e7b8796a0acb9aea399897c86929facb8ada297887c6f6255483c2d22170b000000000000000000000000000811191f272f34383a3e40413f3b3a363128231c150c03000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f83766d6d6d6d6e6f70747a818e939da9b3bebfb5ab9d918477695e52463a2d20140700000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b4b4b4b4b4b4b4b8b9bec5cdcac2bbb7b6b4b4b4b4b4b4b4ab9e9185786b5e5245382b1f120000000613202c3945515d67707d87929fa4abb3bbc0bcb7b6b2b0afafb2b6b7bcc2bcb4aea49d928c7f726a6053493f33271b0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121e2b37424d576975828f9ca8b5c0b3a69a8d807367544a4034281c10040000000000000000000000000000030b12181f252a2d3036393a3d3e404040403f3e3938332d261d140a000000000000000000000000000000000000000b16212c353e44484a4c4c4c4c4c4c4c4c4b4a463f44464a4d4a5053504a504c4847433c37312a211b120a0100000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275686868686868686868686865625b51463a2e2216090000000000000000000000000006131f2c3945515d677783909daab7b8ab9f9285796c6e7b8797a1adada2978f828f9ca9b5a89b8f827568717e8a97a9b3beb4aa988b7f7265584c3f3025190d01000000000000000000000000000000000b16212c38444f5963707d8996a3afbcc9bdb0a3978a7d70655b5041382d1d140a0000000000000000000000000000000000000000000b1824313e4b5764717e8a97a8b2b9ac9f92867983909da9b6b3a9988b7f726553493f33271b0f0300000000000000000000000000070d151d23292c2d313434322e2d2a261f18120b0300000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f837669616161616264686d77818e97a1adb9c6b8aca095877b6e6154483b2e21150800000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3a7a7a7a7a7a7a7a7abadb3bbc5c2b8b0aba9a7a7a7a7a7a7a7a79e9185786b5e5245382b1f12000005121e2a36424d57606d79849199a3afb5bdbfbab0aba9a5a3a2a3a5a9abb0b9bebfbaaea59f92877c6f655b5044372b1f1409000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212d3a47535f697885929eabb8bdb2a8978a7d7164574a3e2e23180c0000000000000000000000000000040c151d232830363a3b414647494b4c4d4d4c4c4b46443f382f261c110600000000000000000000000000000000000005101a232c33383c3d40404040404040403f3d3a3338393d413f4446443f433f3c3a37312b2620180f09000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e81757575757575757575757575726d62574a3e3125180b000000000000000000000000000714202d3a4753606d7a86929facb9b6a99c90837665697885929eabb3a99f9386939facb2a6998c7f73666e7b8897a2adbab4a89b8e817568564c41362a1e11050000000000000000000000000000000005121f2b3744505b65717d8a97a4b0bdcabeb1a4988b7e71665c5144392e23180c000000000000000000000000000000000000000005111e2a36414d566774818e9aa7b4b6aa9d908377818d9aa7b4b5a89b8f8275655b5044372b1f12050000000000000000000000000000030b12181c1f202427272622211e1a140c07000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c54545455565d656d7985919eabb8c3bcb1a7978b7e7164584b3e3125180b00000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a979b9b9b9b9b9b9b9b9b9ea1a9b3bebbb0a69f9c9b9b9b9b9b9b9b9b9b9185786b5e5245382b1f1200000714212d3a46535e6974808d96a1abb5c0bcb4aea69f9c98969596989c9fa6adb3bbc0bbafa3999083786c6053463b31251a0e020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b8897a1adb9b9ada196877b6e6154473b2e21140700000000000000000000000000040d161e272e343b4246484c52545658595a5a59585853504a42382d22170b0000000000000000000000000000000000000008111a21282c2f30333333333333333332312e282b2d302d33383938332d322f2e2b26201a150e0600000000000000000000121e2b3845515e6b7884919eabb7c4b7ab9e91848181818181818181818181817f7265594c3f3226190c000000000000000000000000000a1623303d495663707c8999a3afbbb3a79a8d8074676976828f9ca9b5afa4999399a4afb3a9968a7d70636c7985929fabb8b7aa9e918477685e5246392d201307000000000000000000000000000000030f1b27333f4953606c7883909daab7c3d0c4b7ab9e9184796d60544a4034281c1106000000000000000000000000000000000000000714202d3946525e687784919daab7b4a79a8d81747e8b98aab4b8ab9e9285796c605346392d20130600000000000000000000000000000001070c101314171a1a191514120e090300000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504747484c535d67727f8c98a8b2bdc0b4a79a8d8174675a4e4134271b0600000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707e8a8e8e8e8e8e8e8e8e8e8e9297a1adb9b7ab9f948f8e8e8e8e8e8e8e8e8e8e85786b5e5245382b1f120003101c28343f4a54616e7b87929fa8b2bdbfb4aaa29f94908c8989898b90949ea2a9b3bcc0b5aba0958a7e7164574d42362a1e12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313e4b5764717e8a97a9b3beb7ab9e918478695e52463a2d201407000000000000000000000000020b161f28303940454d5254565e616365666666666565605b544a3f33281c0f03000000000000000000000000000000000000000810161c20232426262626262626262524221c1f202422282b2d2b28222622211f1a150f09030000000000000000000000121e2b3845515e6b7884919eabb7c4b9aca196918e8e8e8e8e8e8e8e8e8e8e8e8275695c4f4236291c0f030000000000000000000000000c1926333f4c5966727f8c99abb5bfb4aa978b7e71646673808d99a6b3b5aba49fa4abb5ada197877b6e616576838f9ca9b6b9aca096877a6d6154473a2e21140600000000000000000000000000000005121f2b3744505b65717d8a95a0acb8c5d1c5b9aca1968b7e71665c5144382e23170c000000000000000000000000000000000000000814212e3b4754616e7a8796a0acb8b4aa988b7e717b8898a2aeb9ada197887b6f6255483c2f22150a0000000000000000000000000000000000000406070b0d0e0c08070502000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433b3c414b55616e7b8796a0acb8c2b5a99c8f8276695c4f432d22170b00000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c818181818181818181818185929eabb8b6a99c8f82818181818181818181818074675a4d4134271a0e0006121f2b3844505c6673808c99a3afbac4baaea298928a837f7d7c7c7f838a9297a2aab4bfbdb1a79c908376695e53463a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101d2935404b556774818d9aa7b4c0b5a89b8e827568574d42362a1e11050000000000000000000000000a141d28313a434b51575e6166686d70717373737372716c665b5044382b1f12060000000000000000000000000000000000000000050b1014161719191919191919191818150f121317171c1f201f1c17191515120f0a0300000000000000000000000000121e2b3845515e6b7884919eabb7c4bdb2a8a19e9b9b9b9b9b9b9b9b9b9b9b8f8275695c4f4236291c0f03000000000000000000000005121e2a36424d576875828f9ba8b5baaea398887b6f6264717d8a97aab3bdb5afacafb5b8ab9e928578695e6773808d9aa6b3bdb2a8968a7d7063574a3d2d22170b0000000000000000000000000000000613202d394653606c7883909da7b1bcc8d4c9bdb2a89e9184796d60544a3f34281c11060000000000000000000000000000000000000b1824313e4b5764717e8a97a8b2baaea298887b6f7985929facb8b3a9988b7e7265584b3f31261a0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362f3946535e697784919daab7c4b7ab9e9184786b5e493f33271b0f03000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b47545f6a6f747474747474747474747783909daab6b0a3968a7d74747474747474747474746e64584c3f33261a0d000713202d3a4653606d7984919eabb5c0baafa59f92867e7672706f7072767d859298a2aebac3b9ac9f93877b6e6154483b2e211507000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515d677783909daab6bfb5ab988c7f7265594c3f30251a0e02000000000000000000000006111b262f3a434c555c60696e73777a7d7e7f80807f7f7e786c605346392d201306000000000000000000000000000000000000000000000407090a0d0d0d0d0d0d0d0d0c0b09030606060b0f1213120f0b0609080603000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c4bab2acaba8a8a8a8a8a8a8a8a8a89c8f8275695c4f4236291c0f0300000000000000000000000714212d3a46535e697885919eabb8b8ac9f9286796d60616e7b8898a2aebac0bbb9bbc0b5a99c8f8276695764717e8a97aab3beb3a6998d807366544a3f33281c0f03000000000000000000000000000814202d39444f5964707d8a95a0acb9c3cecccec4b9aca1968b7e71665c5044382e23170c000000000000000000000000000000000005111e2a36414c566774818d9aa7b4b8ac9f9285796d7683909da9b6b5a89b8e827568584e43372b1f120600000000000000000000000003080b0d0e1313131313131313131212100c08020000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362a36424d576875828f9ba8b5c2b8ab9f928578655b5044372b1f1205000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2b37434e585f626868686868686868686a7783909daab6b0a3968a7d7068686868686868686867645c52473c3024170b000916222f3c4955626f7c8896a1adbdc7b6aa9e93897d716c65636263656b707c86929fa9b3bebbafa49a8b7e7165584b3e2e23180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a86929facb9bbaea399897c6f6356493c302316090000000000000000000000000b17222d38414c555d676d737b7f8486898b8c8d8d8c8b86796d6053473a2d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000306060603000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b4b4b4b4b4b4b4b4b4a89c8f8275695c4f4236291c0f0300000000000000000000000815212e3b4854616e7b8796a1adb9b6a99d908376665c606c7985929fabb8c5c7c6c7c0b3a6998d8073665a626e7b8898a2aebab6a99c8f8376665b5044382b1f120600000000000000000000000005101a23303c4955616c7783909da7b1bcc4c0bfc0c4bdb2a89e9184786d60544a3f34281c1106000000000000000000000000000000000714202d3946525e687784919daab7b6a99c9083766674818d9aa7b4b8ab9e9285786a5f53473a2e2114080000000000000000000001080f14181a1b2020202020202020201f1e1c18130d0600000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f35404b556c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362531404d5a6673808d99a6b3c0b9ac9f9386796c605346392d201306000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b26323c464e54555b5b5b5b5b5b5b5b5d6a7783909daab6b0a3968a7d70635b5b5b5b5b5b5b5b5a58524a40362b1f1307000c1925323f4c5865727f8b98a8b2bdbeb3a99b8e81756b615a56565659616a727f8b97a2adbac0b6ac9b8e817568554b4034281c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8999a3aebbb9ac9f9286796d6053473a2d2014070000000000000000000000030f1b27333f49535d676d7980868c90939a989999999993867a6d6053473a2d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b4b4b4b4b4b4b4b4b4a89c8f8275695c4f4236291c0f0300000000000000000000000b1724313e4a5764717d8a97a9b2bdb4a79a8e817467545b657683909ca9b6c3cfd2cabfb4aa978a7e716457606c7985929fabb8b8ab9f9285796c605346392d2013060000000000000000000000000b16212c38444f5964707d8a95a0acb9bfb8b4b2b4b8bfb9aca0968b7e71665c5044382e23170c000000000000000000000000000000000814212e3b4754616e7a8795a0acb8b3a69a8d807367717e8b97aab4b9ada197887b6e6255483b2f221509000000000000000000020b131a202427272d2d2d2d2d2d2d2d2d2c2b28241f181007000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3945515d677986939facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629333f4c5966727f8c99a5b2bfbbafa49a867a6d6053473a2d201407000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a15202a343c4347494e4e4e4e4e4e4e505d6a7783909daab6b0a3968a7d7063574e4e4e4e4e4e4e4d4c4740382f24190e03000f1b2835424e5b6875818e9ba8b4c1baada297897c6f6359504a49494f58606d7985929fabb8c4b7aa9e918477675c5145382c1f1306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926323f4c5965727f8c98abb5bfb6aa9d908377675c5145382c1f1306000000000000000000000005121f2b3744505b656d79828d92999d9fa4aca6a6a6a093867a6d6053473a2d2014070000000000000000000000000000000000030608091313131313131313131313090806030000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c4bab2acaba7a7a7a7a7a7a7a7a7a79c8f8275695c4f4236291c0f030000000000000000000004101c2834404a546773808d9aa6b3c0b5ab988b7e726558536774808d9aa7b3c0d0d3c6baaea298887b6e62555b657683909ca9b6baaea298887b6f6255483c2f221507000000000000000000000004101c27333c4855616b7783909da7b1bcb5ada7a5a7adb5bdb2a89e9184786d60544a3f34281c11060000000000000000000000000000000b1724313e4a5764717d8a97a8b1bdb3a9978a7e71646f7b8898a2aebab3a9988b7e7265584b3f31261a0e0200000000000000010b141d252b3033343939393939393939393938353029221910060000000000000e1b2734414e5a6774818d9aa7b4bfb2a5988c7f7265594c3f3a4753606d7a8699a4afbbbaada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323f4c5865727f8b98a5b2bec0b6a093867a6d6053473a2d201407000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040e19222a32373b3c41414141414144505d6a7783909daab6b0a3968a7d7063574a414141414141413f3c362f261d13080000101d2a3743505d6a7683909da9b6c3b8ab9f9285786b6054473e3c3e45515d6775828f9ba8b5c2b9ac9f9386796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36424d566875828e9ba8b5c0b3a79a8d807467554b4034291c10040000000000000000000004111d2935404b55606c77828f949fa3abacafb6b2b3ada093867a6d6053473a2d201407000000000000000000000000000000040a0f12151520202020202020202020201515120f0a03000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4bdb2a8a19e9b9b9b9b9b9b9b9b9b9b9b8f8275695c4f4236291c0f030000000000000000000006121f2c3844515c667683909ca9b6bbafa399897c6f62565864717e8b97aab4bfcbd2c5b8ac9f9285796c6053536773808d9aa6b3beb4aa988b7e7165584b3e2f24180d01000000000000000000000714202c38444f5963707d8a959fabb9b9ada39c999ca3adb8b9aca0968b7e71665c5044382e23170c000000000000000000000000000005111d2a36414c566774818d9aa7b4b9ada197887b6e616d7985929facb8b5a89b8e827568574d42372b1e12060000000000000008131d262f363c40414646464646464646464544413b342b22180d0200000000000e1b2734414e5a6774818d9aa7b4c0b3a69a8d807367564c413b4855616e7b8894abb5c0bbafa499877a6d6054473a2d21140700101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007101920262b2e2f35353535353744505d6a7783909daab6b0a3968a7d7063574a3d35353535353433302b241d140b010000111e2b3744515e6a7784919daab7c3b6a99c90837669594f43352f35404b5566727f8c99a5b2bfbbafa49a887b6e6155483b2e2215080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a46525e697884919eabb7beb3a9978a7e7164574b3e2f23180c00000000000000000000000613202c3945515d67727f8b949ea6aeb4b9bbbbb9b6ada093867a6d6053473a2d2014070000000000000000000000000000060e151b1f21222d2d2d2d2d2d2d2d2d2d2d22211f1a150e060000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b9aca196918e8e8e8e8e8e8e8e8e8e8e8e8275695c4f4236291c0f03000000000000000000000713202d3a4653606d7986929facb8b9ac9f9286796d605355626f7b8898a3aebac7d0c3b6a99d908376665b505764717e8a97aab4bfb4a79a8e817467554b4135291d1104000000000000000000050f19232f3c4855616b7683909da7b1bcb1a79c918c919ca6b0bcb2a89e9184786d60544a3f34281c1106000000000000000000000000000713202d3946525e687784919daab7b8ab9e928578695f667683909ca9b6b8ab9e918578695f53473a2e211408000000000000030f1a252f3841484c4e53535353535353535352514c463d34291f130800000000000e1b2734414e5a6774818d9aa7b4c0b6a99c8f8376685e5247464d5764717d8a97a4b0bdb9ac9f9386796c605346392d20130600101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070e151b1f2222282828282a3744505d6a7783909daab6b0a3968a7d7063574a3d30282828282726241f19130b02000000121f2b3845525e6b7885919eabb8c1b4a89b8e8175685b4e4232242f3e4b5864717e8b97a4b1bec0b6ac95887c6f6255493c2f2216090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3b4754616e7a8796a1adb9b9ada197887b6e6155483b2e22150700000000000000000000000714202d3a4753606d7985929ea6b0babfbeb6afaca9a7a093867a6d6053473a2d2014070000000000000000000000000006101820262b2e2f39393939393939393939392f2e2b262018100600000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b7ab9e91848181818181818181818181817f7265584c3f3225190c00000000000000000000000916222f3c4955626f7c8898a3aebab7aa9d908477675c5153606d7986929facb8c5cdc0b4a79a8d817467544a55626e7b8898a2aebab7aa9d908477675d5145392c2013060000000000000000000b16212c38444f5963707d89959fabb9b8aca0958c7f8c949fabb7b9aca0968b7e71665c5044382e23170b000000000000000000000000000714212e3a4754616d7a8795a0acb8b5a99c8f827669576774808d9aa7b3b9ada197887b6e6255483b2f2215090000000000000814202b36414a53585a6060606060606060605f5d574f463b3024180c00000000000e1b2734414e5a6774818d9aa7b4c0b9ac9f92867a6d615a5353565f6975818e9ba8b4c1b8ab9f928578655b5044372b1f120500101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f1315161b1b1b1d2a3744505d6a7783909daaafafa3968a7d7063574a3d30241b1b1b1a1a17130e080100000000131f2c3946525f6c7985929facb8c1b4a79a8e8174675b4e413428313d4a5764707d8a97a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313e4a5764717d8a97a8b2bdb8ab9e928578695f53463a2d2114070000000000000000000004101d2935404b5565727f8b97a1adb8c2b9b1aca49f9d9a9993867a6d6053473a2d201407000000000000000000000000040e18222a31373a3c46464646464646464646463c3a37312a22180e03000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e81757474747474747474747474726d62564a3e3125180b00000000000000000000000c1925323f4c5865727f8b98aab4bfb4a79b8e817468554b505c667683909da9b6c3cbc0b5ab988b7e7165584b53606c7985929facb8b9ac9f93867a6d6054473a2d211407000000000000000004101c27333c4854606b7683909da7b1bcb2a89d90837783909ca8b2bdb2a89e9184786d60544a3f34281c11060000000000000000000000000b1724313e4a5764717d8a97a7b1bcb3a6998c8073665964717e8b97aab4beb3a9988b7e7265584b3f31261a0e0200000000000b1824303c48535c64676c6c6c6c6c6c6c6c6c6c6961574c4135281c1000000000000e1b2734414e5a6774818d9aa7b4c0bbaea3998d80736c62606061686e7b86929facb9c4b7aa9e9184776b5e493f33271b0f0300101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030608090e0e111d2a3744505d6a7783909da2a2a2a2968a7d7063574a3d3024170e0e0e0d0b0703000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a546773808d9aa6b3c0b5a89c8f827569574d42362a1e12050000000000000000000006131f2c3945515d677683909ca9b3bebbb1a79f9a93908d8c8c86796d6053473a2d2014070000000000000000000000000a15202a343c43474853535353535353535353534847433c342a20150a000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275686868686868686868686865625b51463a2e2216090000000000000000000005111d2935414c566875818e9ba8b4c0b6ac988b7f7265584c4a546774818d9aa7b4c0c7bbafa399887c6f625549505b667683909ca9b6bbafa499897d706356493d3023160900000000000000000713202c38444f5963707d89959fabb9b9ada1968a7e717d8a96a0acb9b9aca0968b7e71665c5044382e23170b000000000000000000000005111d2935414c566774808d9aa7b3bdb2a8968a7d706357626f7b8898a2aebab4a89b8e817568574d42372b1e120600000000000d1a2733404c58646e747979797979797979797873695d5144382b1e1200000000000e1b2734414e5a6774818d9aa7b4c0bfb5ab9f93877e746f6d6d6e727a839098a3aebac1b5a89b8e8275685b4f422d22170b0000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000040f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204111d2a3744505d6a7783909696969696968a7d7063574a3d3024170a020100000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844505c667683909ca9b6c0b5ab998c7f7266594c3f31261a0e02000000000000000000000714202d3a4753606d7a86929facb9beb3a99f95908783807f7f80786d6053463a2d2013070000000000000000000000030f1b26313c464e5355606060606060606060606055534e463c31261a0f020000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5b5b5b5b5b5b5b5b5b585651493f34291e1206000000000000000000000713202d3946525e687784919eaab7bbafa49a897c6f6356494b5865727e8b98abb5c0c5b9ac9f9286796d6053474a546774808d9aa7b3c0b5ab998c7f7266594c3f31261a0e02000000000000040f19232f3c4854606b7683909ca7b1bcb4aa9e9184796d7884919ea9b3bdb2a89e9184786d60544a3f34281c1106000000000000000000000713202d3946525e687784909daab7b9ada196877a6e6154606c7985929facb8b8ab9e918478695f53473a2d21140800000000000e1b2734414e5a67748186868686868686868685786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4c0c6bbafa4999388817c7a797b7f859095a0aab4bfbdb2a8998c7f7266594c3f332619060000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000004080a0a11111c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11110d0c0a07020000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2a3744505d6a778389898989898989897d7063574a3d3024170a000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7985929facb8bbafa499897c706356493d302316090000000000000000000000091623303c4956636f7c8999a3afbbbaada29790837c76747373746d665c5144382c1f1206000000000000000000000006121f2b37434e585f626c6c6c6c6c6c6c6c6c6c6c625f584e43372b1f14090000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4e4e4e4e4e4e4e4e4c4a463f372d23180d01000000000000000000000714212e3a4754616d7a8796a0acb9b9ac9f93867a6d6054474956626f7c8999a3afbbc3b7aa9d908477675c51454b5764717e8a97aab4bfb5a89c8f827569574d42362a1e12050000000000000b16212c38444f5963707d89949fabb9baaea2988c7f7266727f8b97a2adbab9aca0968b7e71665c5044382e23170b000000000000000000000714212e3a4754616d7a86939facb9b7ab9e918478685e525b667683909ca9b6b9ada196887b6e6155483b2e22150900000000000e1b2734414e5a6774818d939393939393939285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4c0ccc0b5aba49a938e898686878b9197a0a7b1bcc6b9aca196897c706356493d3023160a0000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000050b101416171e1e1e2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e1e1e1a1917130e0800000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3c4855626f7c7c7c7c7c7c7c7c7c7a6d6054473a2d211407000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8898a2aebab9ac9f93867a6d6053473a2d20140700000000000000000000000b1825323e4b5865717e8b98abb5c0b8ab9f92857a6e6a67666667605c544a4034281c100400000000000000000000000815212e3a47535f6a7679797979797979797979796f6a5f53473b30251a0e0100000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42414141414141413f3e3a342d251b110700000000000000000000000a1724303d4a5763707d8a96a8b2bdb7aa9e918477675d51454653606d7986929facb9bfb4a79b8e817468554b404855626e7b8898a2aebab8ab9e928578695f53463a2d2114070000000000030f1b27323b4854606b7683909ca6b0bcb5ab9f92857a6d606d7985929fabb5bdb2a89e9184786d60544a3f34281c11060000000000000000000a1724313d4a5764707d8a9aa4afbbb5a89b8e827568564c546774808d9aa7b3bdb2a9988b7e7165584b3e31261a0e02000000000e1b2734414e5a6774818d9a9f9f9f9f9f9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4c0c5bcb3aeaca49f9b95999399989ea1a9b1b9c3beb3a99e9184786c605346392d2013060000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000000000810171c2023242a2a2a2a35424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b2a2a2a2726231f19120a020000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815212e3b47535f6a6f6f6f6f6f6f6f6f6f6d685d5245392c201307000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98aab4bfb7aa9d908477675d5145392c20130600000000000000000000000d1a2733404d5a6673808d99a6b3c0b4a79a8d8174685f5859595a53514a42392e23180c0000000000000000000000000915222f3c4855626f7c86868686868686868686877c6f62574d42362a1e130800000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423535353535353532312e29231b13090000000000000000000000030f1b27333f49536673808c99a6b2b2b2a89b8e827568554b4145515c677784909daab2b2b2a5988c7f7265594c3f4653606c7985929facb2b2ada197887b6e6155483b2e22150800000000000713202c38444f5963707d89949fabb8bbafa3998d8073685d6773808d99a3afbbb8aca0968b7e71665c5044382e23170b000000000000000005111d2935414c566774808d9aacb6c0b6ac998c7f7266594c5864717e8b97aab4bfb4a89b8e817568574d42362a1e1205000000000e1b2734414e5a6774818d9aa7acacacab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4c0beb3aaa29fa2aaa7aba49fa4ababadb3bbc3bfb9ada1978c7f73665b5044382b1f12060000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d2014070000000000000000000008111a21282d30313737373737424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144383737373733322f2a241c140a0000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b37434e585f626363636363636363605d564c4135291d1104000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c566874818e9ba7b4c1b4a79a8e817467554b4035291d110400000000000000000000020e1b2835414e5b6874818e9ba7b4bdb1a4978a7e7164564e4c4c4e4644403930271c12070000000000000000000000000815212e3a47535f6a75828f939393939393939a8e8174695e52463a2f24190d00000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352828282828282525221e18110901000000000000000000000005121f2b3744505b6576828f9ca6a6a6a6a5998c7f7266594c3f404b556874818e9ba6a6a6a6a896897c706356493d44505b667683909ca6a6a6a6a9978a7e7164574b3e3124180b00000000040f19222f3b4854606b76828f9ca6b0bbb9ac9f92867b6e6156616e7b86929facb9bdb2a89d9184786d60544a3f34281c1106000000000000000713202d3946525d687783909daab7bbafa49a897c7063564955626e7b8898a2aebab7ab9e918478695f53463a2d211407000000000e1b2734414e5a6774818d9aa7b4b9b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4c0baaea2989298a0a7b0afacafb5b8b9bec2bcb8ada49e92857a6d61544a3f33281c0f030000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000005101a232c33393c3d4444444444444f5b6875828e9ba8b5c1b7aa9e9184776b5e51444444444444403f3b362e261c120800000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b26323c464e5355565656565656565654524c443a3024190d01000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c3945525d687784919daab7beb3a9978b7e7164584b3e2f24180d0100000000000000000000030f1c2936424f5c6975828f9ca8b5bcafa295897c6f6256494040413a38342e271e150b0000000000000000000000000006121f2b37434e5863707c89959f9f9f9f9f9f9f92867b6e61554c4135291c1207000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c1b1b1b1b191816120d0b0b0905010000000000000000000613202d394653606c78859299999999999996897d7063564a3d3f4c5865727f8b98999999999996877a6d6054473a3f4a546774808d999999999999998d8074675a4d4134271a0e000000000a16202c38434f59636f7c89949fabb8bbb0a69b8e8175695e535e6975818e9ba6b0bbb8aca0968a7e71665c5044382d22170b000000000000000714212e3a4754616d7a86939facb9b9ac9f93867a6d60544753606c7985929facb8b9ada196887b6e6155483b2e221509000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f928590959fa6aeb4b8babebab8b7b1aba39c928a7e71685e5242382d22170b000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d2014070000000000000000000b17212c353e44494a515151515151515b6875828e9ba8b5c1b7aa9e9184776b5e515151515151514d4b4740382e24190e02000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a15202a343c43474849494949494949494745413a32281e130800000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a86939facb9baada297887b6e6255483b2f221507000000000000000000000003101d2a3643505d697683909ca9b6bbaea195887b6e6255483b33342d2c28231c150c0300000000000000000000000000030f1b26313c4854606b7683909da8b2acacaea3998d8073675d5145392e23180c000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281e1e1e1e1e1e1e1e1e1e181715110c0600000000000000000815222f3b4855626e7c888c8c8c8c8c8c8c8c877a6d6154473a3c4956636f7c898c8c8c8c8c8c8c8478685d5245393e4b5864717e8b8c8c8c8c8c8c8c8c83766a5d5043372a1d10000000030f1b27323b4854606b76828f9ca6b0bbb7ab9f94887c6f62574d57626f7c88949fabb7bdb2a89d9184786d60544a3f33281c11060000000000000a1724313d4a5764707d8a9aa4afbbb7aa9d918477675d5145505b667683909ca9b6bdb2a8988b7e7165584b3e31261a0e020000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4bfb2a5988c7f8390949fa2aaabaeb3aeacaaa79f9d918c80746c61564c412f261c1106000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000004101c28333e474f55575d5d5d5d5d5d5d5d6875828e9ba8b5c1b7aa9e9184776b5e5d5d5d5d5d5d5d5a58524a40362a1f1307000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040e18222a32373b3c3c3c3c3c3c3c3c3c3a3935302820160c0200000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724303d4a5763707d8a9aa4afbbb8ab9f9285796c605346392d201306000000000000000000000004111e2a3744515d6a7784909daab7baaea194877b6e6154483b2e27201f1c18120b030000000000000000000000000000000a15202c38444f5964707d8a96a0acb8bfb4ab9f92857a6d60544a4034281c10040000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352a2a2a2a2a2a2a2a2a2a2a2524211d181109000000000000000815222f3b4855626e7c7f7f7f7f7f7f7f7f7f7f72685e5246393a4753606d797f7f7f7f7f7f7f7f7e7164564c41353b4754616e7b7f7f7f7f7f7f7f7f7f7f7265594c3f3226190c00000006131f2b38434e58636f7c89949fabb2b2b1a89c8f83766a60544754606a7683909ca8b2b2b2aca0968a7e71665b5044382d22170b000000000004111d2935414c566774808d9aacb6c0b4a79b8e817468554c414a546773808d9aa6b3c0b4a79b8e817468574d42362a1e12050000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7a828c92989c9fa2aaa29f9d9a9590897f746e645a50443a301d140a00000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000814202d39444f5961646a6a6a6a6a6a6a6a6a75828e9ba8b5c1b7aa9e9184776b6a6a6a6a6a6a6a6a66635c52473b2f23170a000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006101820262b2e2f30303030303030302d2c29241e160e040000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27333f49536673808c99acb6c0b5a99c8f8276655b5044372b1f1205000000000000000000000004111e2b3744515e6a7784919daab7baaea194877b6e6154483b2e211512100c07000000000000000000000000000000000004101b27323d4653606c7884919da9b2bdbaaea2988c7f72665c5144382c1f160b0000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4237373737373737373737373732312e29221b12090000000000000814212e3a47535f6a6e737373737373737373726d62564c41363945515d676d7373737373737373716c6155443a2f3a46525e696e737373737373737373726d63574a3e3125180c0000000815222e3b4754606a76828f9ca6a6a6a6a6a0958a7d7063584e434e5864707d8a96a0a6a6a6a6a89d9184786c60544a3f33281c0f03000000000713202c3945525d687783909daab6bfb5ab988b7f7265584c3f4b5764717e8a97aab3beb7ab9e918478695f53463a2d2114070000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e72787f868c8f9298949892908d89837d736d645c52483e32291e0b0200000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000a1623303c4955616c7077777777777777777777828e9ba8b5c1b7aa9e918477777777777777777777736e63584b3f3226190c000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e151b1f2122232323232323232321201d19130c04000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6576828f9ca9b5c0b6ac998c80736653493f33271b0f03000000000000000000000005111e2b3844515e6b7784919eaab7baaea194877b6e6154483b2e2115080400000000000000000000000000000000000000000b161f2b3744505b65717e8b96a1adb9beb3aa9e9184796d6053463d33271c100400000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f444444444444444444444444443e3d3a342d241b1106000000000006121e2b37424e575f6266666666666666666665625b51443a3035404b555d60666666666666666664615a5045322a36424d575e6166666666666666666665635b51463a2e221609000004101d2935404b55626f7c8994999999999999999184786c6053463c4653606c78849199999999999999968a7e71665b5044382b1f1206000000000714212d3a4754606d7a86939facb9bbaea399897c6f6256493c4855626e7b8898a2aebab9ada196887b6e6155483b2e2215090000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e726d727a7f83858787868584807d786f6b635b524a40362c20170d0000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000a1724313d4a5764707d8384848484848484848385929fabb8c5b9ac9f9287838484848484848484838073665a4d4033271a0d000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f12151516161616161616161413110d080200000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7985929fabb8bbafa49a8a7d7063574a3d2d22170b00000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000030f1b27333f4953606d7984919ea9b3beb9ada1968b7e7164594f44382c20150a00000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b51515151515151515151515151514b4a453f362d22180c0100000000020e1a26313c454e5355595959595959595959595751493f32282f39434b51535959595959595959575550483e3425303b454d5254595959595959595959595751493f352a1e1206000006131f2c3945515d6776828c8c8c8c8c8c8c8c8c8b7e71655b50443844505b66727f8b8c8c8c8c8c8c8c8c8c84796c605346392d201306000000000a1724313d4a5764707d8a99a4afbbb9ac9f9286796d6053463a4653606c7985929fabb8bdb2a8978b7e7164584b3e31251a0e0200000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265686d7276787a7a7a797773706c656059514940382f241a0e050000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000b1825313e4b5864717e8b9090909090909090909297a2adbac6baaea399929090909090909090908e8175685b4f4235281c0f000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003060809090909090909090907070401000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222f3b4855626e7b8897a2adbab9ac9f93867a6d6154473a2e21140600000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000b17222d3845515c66727f8c97a2adbabdb2a89d9083776b6155483c32261b0f03000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685d5d5d5d5d5d5d5d5d5d5d5d5d5d5d585650483f34291d110500000000000915202a333c4247484c4c4c4c4c4c4c4c4c4c4a463f372d202831394045474c4c4c4c4c4c4c4c4b49453e362c2229333b4246474c4c4c4c4c4c4c4c4c4c4a463f372d23180d0100000714202d3a4753606d797f7f7f7f7f7f7f7f7f7f7f796d6053493f333f4a54606d797f7f7f7f7f7f7f7f7f7f7f7b6e6154473b2e21140800000004111d2935414c566773808d9aabb5c0b6aa9d908377675c51453844505b6576838f9ca9b6c1b4a79b8e817468574d42362a1e120500000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e72655d616569686d6e6d676a6763605b534f4740372f261d1208000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000b1825313e4b5864717e8b979d9d9d9d9d9d9d9d9fa2a9b3becabfb4aba39f9d9d9d9d9d9d9d9d9b8e8275685b4f4235281c0f000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825313e4b5864717e8b97a9b3beb7aa9d918477685d5246392d20130700000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e2115080000000000000000000000000000000000000000000006111b2834404b54606d7a85929faab4bfb8aca095897d7063584e43372b1f1409000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e82756a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a65625a50453a2e2115090000000000030e18212a31373a3b4040404040404040403f3e3a352d251b1f282f35393a40404040404040403e3d39342c241a202930363a3b4040404040404040403f3e3a352d251c110700000006131f2c3945515d676d73737373737373737373736d675c5141382d3845515d676d73737373737373737373736e695e52463a2d2014070000000613202c3945525d687783909daab6c0b4a79a8d817467554b40343f49536773808d9aa6b3c0b7ab9e918478695e53463a2d21140700000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265585459565d6061605d555a56535049413d352e251d140b00000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000b1825313e4b5864717e8b97a4aaaaaaaaaaaaaaabadb3bcc5d0c6bdb4aeacaaaaaaaaaaaaaaa89b8e8275685b4f4235281c0f000a1724303d4a5763707d8a96a3b0bdb5a89b8f8275685c4f42352917110f0a0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101d2935404b556774818d9aa7b4c0b4a79b8e817468564c4135291d110500000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000c18232e3945515d6773808d98a3aebabcb1a79c8f82766a5f53473b31251a0e010000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e817777777777777777777777777777777777716c62564a3d3124170b000000000000060f1820262b2e2f33333333333333333332312e29231b13161d24292c2d333333333333333331302d28221a12171f252a2d2e33333333333333333332312e2a231c130a0000000004101d2935404b555d606666666666666666666666605c554b402f2935404b555d606666666666666666666666615e574d42362a1e11050000000714212d3a4754606d7a86929facb9bfb4aa978b7e7164584b3e2e3e4b5764717e8a97a9b3beb9aca196877b6e6154483b2e21150900000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b4c4c52545453514b4d4946443f382f2b231c130b0200000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000b1825313e4b5864717e8b97a4b1b7b7b7b7b7b7b8babec5cecbcfc6bfbab9b7b7b7b7b7b7b5a89b8e8275685b4f4235281c0f000a1623303d495663707c8996a3afbcb5a89b8f8275685c4f422d28231c1b160f07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3945515d677783909daab6bfb4aa988b7e7265584b3f3024190d0100000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000007121d2935414c55616e7a86929fabb5c0b7ab9f94887c6f62574d42362a1e13080000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8ab9f928583848484848484848484848484848484837e7165584b3e3225180b00000000000000060e151a1e21222626262626262626262625221e18110a0c12181d202026262626262626262423211d1710080d141a1e20212626262626262626262625221e18110a0100000000000c18242f39434b5153595959595959595959595953514b43392f242f39434b5153595959595959595959595954524d453b30251a0e020000000a1724303d4a5763707d8a99a3afb2b2aea298887b6f6255483c2f3b4855626e7b8897a2adb2b2b2a8978b7e7164584b3e30251a0e02000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f41454747474540403d3937332d261d19110a010000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000b1825313e4b5864717e8b97a4b1bebfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb5a89b8e8275685b4f4235281c0f000916232f3c4956626f7c8995a2afbcb5a89c8f82756953493f38342e2b27201910070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a86929facb9baaea298887c6f6255493c2f2216080000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000002080e1119242f3a46525e6874818e99a4afbbbbb0a69b8e8175695e53463a2f24190d0000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4baada29792909090909090909090909090909090908c7f7366594c403326190d000000000000000003090e121415191919191919191919191816120d070001070d1013141919191919191919181715110c060002090e111414191919191919191919191816120d070000000000000007121d2731394045474c4c4c4c4c4c4c4c4c4c4c4745403931271d2831394045474c4c4c4c4c4c4c4c4c4c4c4746423b33291f140900000004111d2935414b556773808d9aaba6a6a6a69f9285796c605346392d394653606c7985929fa6a6a6a6a69b8e817468574d42362a1e1205000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f35393a3b3a39352f302d2b27221b140b0700000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000b1825313e4b5864717e8b97a4b1b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a89b8e8275685b4f4235281c0f000815222e3b4855616e7b8894a8b2bdb6a99d908376655b5046443f3838322b22190f0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707c8999a3afbbb8ac9f9285796d6053463a2d2013070000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e2115080000000000000000000000000000000000000002080d14191e20232a36414c56616e7b87939facb9c2b9ac9f92867b6e61554c4135291c110600000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4beb3a9a29f9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d998c7f7366594c403326190d00000000000000000000020608080d0d0d0d0d0d0d0d0d0c0b09060100000000010406070d0d0d0d0d0d0d0d0b0a08050000000000020507080d0d0d0d0d0d0d0d0d0c0c0906010000000000000000010b151f272f35393a40404040404040404040403a38342f271f161f282f35393a40404040404040404040403b3a36302920170d020000000613202c3945515d6776839099999999999999908376665b5044382b3744505b6576838f99999999999999918477695e52463a2d201407000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f322c2d2e2d2c292423201f1b17110a020000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000b1825313e4b5864717e8b97a4a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a59b8e8275685b4f4235281c0f000713202d3a4653606d798696a1adb9b8ab9f9285796c605553504a47433d342b20160a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c99abb5c0b6a99c8f8376665c5044382b1f12060000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000000000000000000040c13191f252a2d2e34383b47535f6975828e9ba6b0bbbbafa3998d8073675d5145382e23170c00000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c5bbb3adabaaaaaaaaaaaaaaaaaaaaaaaaaaaaa6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030d151d24292c2d33333333333333333333332d2c29231d150d161d24292c2d33333333333333333333332e2d2a251f170e05000000000714212d3a4754606d7a868c8c8c8c8c8c8c8c8c807367544a3f3328333f49536773808c8c8c8c8c8c8c8c8c877b6e6154483b2e211508000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225212120201d181613120f0b0600000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323f4b5865727e8b98a5b1beb9ada093867a6d6053473a2d20140700000000000000000b1825313e4b5864717e8b97989898989898989898989898989898989898989898989898989898988e8275685b4f4235281c0f0006131f2c3845515c677884919eabb8baada297897c6f6762605c54544e463d32271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d576875828f9ba8b5c0b3a6998d807366544a3f34281c10030000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e2115080000000000000000000000000000000000080e161e25293036393b404546484d57626f7c89949fabb7c0b5ab9f92857a6d60544a3f34281c1003000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cdc5bebab8b7b7b7b7b7b7b7b7b7b7b7b7b7b2a6998c7f7366594c403326190d000000000000000001040607070707070707070707060400000306070707070707070707070706030000000000000000000000000000000000000000000000000000000000000000000000000000000000030b12181d1f202626262626262626262626201f1c18120b040c12181d2020262626262626262626262621201e1a140d0500000000000814212e3b4754616e7b7f7f7f7f7f7f7f7f7f7f7c6f6255493c2d222d3c4955626f7c7f7f7f7f7f7f7f7f7f7f7b6e6155483b2e221508000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f322518141413100d07060503000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629333f4c5966727f8c99a5b2bfbbafa49986796d6053463a2d20130700000000000000000b1825313e4b5864717e8b8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8175685b4f4235281c0f0004101c2834404b556975828f9ca8b5beb3a99c908279726e6d666260584e43382b1f1306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535e697885919eabb8bdb2a8978a7d7064574a3d2e23170b000000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e21150800000000000000000000000000000000081119202830353b4146474b5153555657606a76828f9ca7b1bcbaaea2988c7f72665c5044382c1f160a000000000000000000000000000000000000121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb2a6998c7f7366594c403326190d00000000000001070d11131414141414141414141313100c0b1012131414141414141414141312100b060000000000000000000000000000000000000000000000000000000000000000000000000000000001070c10131419191919191919191919191413100c07010001070d10131419191919191919191919191414110e09020000000000000714202d3a46525e696e737373737373737373736f6a5f53473b2e212e3b47535f6a6f737373737373737373736e695f53473a2d211408000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0706040100000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362933404d5a6673808d99a6b3c0b9ac9f938679665c5145382c1f130600000000000000000915222f3c4855626f7c7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7d7063574a3d3024170a00000c18232e404c5966737f8c99a8b2bdb7ab9f9490847f7b79786f6a6054473b2e221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815212e3b4854616e7b8796a1adb9b9aca196877a6e6154473b2e211406000000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e21150800000000000000000000000000000008121a232b323a41464d5254545c606263646464707d8995a0acb8beb4aa9e9184796d6053463d32271b0f010000000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a6998c7f7366594c403326190d0000000000040c13181d20202020202020202020201f1c18171c1f20202020202020202020201f1c17110a0200000000000000000000000000000000000000000000000000000000000000000000000000000000000406070d0d0d0d0d0d0d0d0d0d0d070604000000000000010406070d0d0d0d0d0d0d0d0d0d0d08070502000000000000000005111e2a36424d575e6166666666666666666666625f584e43372b1f2b37434e585f6266666666666666666666615f574d42372b1e1206000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362c38434f596875828f9ba8b5c2b8ab9f9285786c544b4034281c100400000000000000000815212e3a47535f6a6f72727272727272727272727272727272727272727272727272727272727272706b6155483c2f23160900000716222f3c4955626f7c8896a1acb9bcb0a69f96918b8886857c6f6256493c2f231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313e4a5764717d8a97a9b2bdb7ab9e918478685e5246392d201407000000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000000000007101a242c353d444c52565e6165666d6e70717170707783909daab7c3b9ada1968a7e7164584e43382b1d13070000000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5998c7f7366594c403326190d00000000040d161d24292c2d2d2d2d2d2d2d2d2d2d2c282323282b2d2d2d2d2d2d2d2d2d2d2d2b28231c140c02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a25303b454d52545959595959595959595955534e463c32261b26323c464e53555959595959595959595955534d453c31261a0e02000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504334383e4854606b7884919eabb8c3b7aa9d9084776a5d51442e23180c00000000000000000006121f2b37434e585f62656565656565656565656565656565656565656565656565656565656565656361594f44382c20140700000815222e3b4754606a7884919ea9b2bdb9b0a8a09e989992897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404a546773808d9aa6b3c0b4a89b8e817568564c41362a1e1105000000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e21150800000000000000000000000000040d19232c363e474f565e61686e7276797b7d7d7e7d7c7b7e8a97a4b1bdbdb2a89d9083766a6054473a2f24180d0100000000000000000000000000000000121e2b3845515e6b788491989898989898989898989898989898989898989898989898988c7f7366594c403326190d000000010c161f282f35393a3a3a3a3a3a3a3a3a3a38342e2e34383a3a3a3a3a3a3a3a3a3a3a38342e261e140a00000000000000000000000000000000000000000000000000000000000000000000000000010507070a0d0f101111100f0d0b0707050100000000000000000000000000000000000000000000000000000000000000000000000009141f29333b4246474c4c4c4c4c4c4c4c4c4c4947433c342a2015202a343c4347494c4c4c4c4c4c4c4c4c4c4847423c332a1f150900000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433f4446505a636f7c8996a1adb9c2b5a89c8f8275695c4f4236291c07000000000000000000030f1a26313c464e53555959595959595959595959595959595959595959595959595959595959595957554f473e33281c1004000006131f2b37434e5865727f8c96a1abb4bdbab2acaaaba396897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844515c667683909ca9b6bfb4aa988b7f7265584c3f3025190d01000000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000000010c161f2b353e48505960686d747b7f838688898a8a8a898785929fabb8c5c4b8ab9f95897c6f62554b4135291d110400000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c7f7366594c403326190d00000007131d28313a404547474747474747474746454039383f444647474747474747474746443f3830261c11060000000000000000000000000000000000000000000000000000000000000000000003080d111314171a1b1d1d1d1d1c1a171413110d080300000000000000000000000000000000000000000000000000000000000000000000020d17202930363a3b404040404040404040403c3b37322a22180e18222a32373b3c404040404040404040403b3a37312a21180e0300000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa7adadada5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504f4a505359616c75818e9ba8b2bdc0b5ab998d8073665a4d4033271a0d000000000000000000000a15202a343c4347484c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a48443e352c21160b000000030f1b27323c4753606d79849199a3abb2b8bcb9b7b4a396897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7986929facb8baaea398897c6f6256493c2f23160800000000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e21150805010000000000000000000007131d28313d47505a616b707a81868c9092989697979796979297a2adbac6c8bcb1a79b8e8175675d5145392c201409000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7c6f6256493c2f2316090000010d18242f3a434b5153535353535353535353514b42424a505353535353535353535353504a42382e23170b0000000000000000000000000000000000000000000000000000000000000000060c1013191d2021242728292a2a2928272421201e1913100c06000000000000000000000000000000000000000000000000000000000000000000050e171f252a2d2e333333333333333333332f2e2b2620181006101820262b2e2f333333333333333333332e2d2b261f180f060000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d9aa0a0a0a0a0988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5c5c545c60636b707e8a939eaabac4bbafa3998a7d7064574a3d3124170a00000000000000000000030e18222a31373a3c3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3d3c38332c231a1005000000000a15202c3945515d676f7d879299a0a8acb1b5b7afa396897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c8998a3aebab9ac9f9286796d6053463a2d20130700000000000000000000000000000000061e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211515110c060000000000000000010d18242f3a434f59616c717d858d92999c9fa3aaa4a4a3a9a29fa2a9b3becacdc2b8ac9f92867a6d6054473b30251a0e020000000000000000000000000000000b1724313d4a56626c717272727272727272727272727272727272727272727272727272726f6a6054473b2e221508000004111d2935404b555d606060606060606060605c544b4a545c60606060606060606060605c544a3f34281c10030000000000000000000000000000000000000000000000000000000000030a11171c1f252a2d2e313335363737363533312e2d2a251f1c17110a030000000000000000000000000000000000000000000000000000000000000000050d141a1e20212626262626262626262622211f1b150e0600060e151b1f21222626262626262626262622211e1a150e06000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774818d939393939393938b7e7265584b3f3225180c0000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f83766969696969666d6f757d86929fa5afbac5b9ac9f92867a6d6054473a2d211407000000000000000000000006101820262b2e2f32323232323232323232323232323232323232323232323232323232323232302f2c28211a1108000000000004101d2935404b55606b717e8791969da0a7a8aaaca396897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427313d4a5764707d8a97a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1925323f4c5865727f8b98aab4bfb6a99d908376665c5145382c1f13060000000000000000000000000000020a11172b3845515e6b7884919eabb7baaea194877b6e6154483b2e2524211d1811090000000000000004111d2935414b55606b717e8792979fa3abacaeb4b0b1b0b3adabadb3bbc5d0d3c7baaea2988b7e7164574d42362a1e12050000000000000000000000000000000915212e3a45505a62656565656565656565656565656565656565656565656565656565656260584e43382b1f130600000613202c3945515d676d6d6d6d6d6d6d6d6d6d665c51505c666d6d6d6d6d6d6d6d6d6d6d665c5044382b1f120600000000000000000000000000000000000000000000000000000001070c151c23282c3036393a3d40424344444342403e3a3936302c28231c150c07010000000000000000000000000000000000000000000000000000000000000002090e111414191919191919191919191615130f0a04000000040a0f131516191919191919191919191514120e090300000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000e1b2734414e5a6774808686868686868686867e7265584b3f3225180c0000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376767676767677797c828a9298a2aeb7c1bdb2a89c8f8276675d5145392c201306000000000000000000000000060e151a1f2122262626262626262626262626262626262626262626262626262626262626262423201c161008000000000000010d18242f39434f59616c717d848b9095989b9e9fa396897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413025323e4b5865717e8b98a4b1bebcafa295897c6f6256493c2f231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d2a36414c566875818e9ba8b4c0b3a69a8d807367544b4034281c100400000000000000000000000000020b141b22273845515e6b7884919eabb7baaea194877b6e6154483b3232312e29221b12090000000000000613202c3945515d676f7d879299a1a9aeb4b9babcb8b6b4b3b4b5b8babec5cad0cabfb4aa9c8f8276695e52463a2d20140600000000000000000000000000000005111d29343f4850565859595959595959595959595959595959595959595959595959595956544e463d32271b0f0300000714202d3a4753606d797a7a7a7a7a7a7a7a796d605353606d787a7a7a7a7a7a7a7a7a786d6053463a2d2013080000000000000000000000000000000000000000000000000000040c13181e262e34383a4146474a4d4e505050504f4d4a4746413a38342e261e18130c040000000000000000000000000000000000000000000000000000000000000000020507080d0d0d0d0d0d0d0d0d0d0908060300000000000000030608090d0d0d0d0d0d0d0d0d0d08080602000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000713202d3a4653606d797a7a7a7a7a7a7a7a7a786d6053463a2d2013070000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3b8ab9f92858282828282838485898e939fa2aab4bfc4b9aca0968a7e7164554c4135291d110400000000000000000000000000030a0f12151519191919191919191919191919191919191919191919191919191919191919171614100b05000000000000000007121d28313d47505a616b6f787e83888b8f91929994897c706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121f2b3845525e6b7884919eabb8c2b5a89b8f827568564c41362a303f4c5966727f8c99a5b2bfbeb3aa95887c6e6255483b2f22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3946525e687784919eaab7beb2a9978a7d7164574a3e2e23180c00000000000000000000000000000a141d262d333745515e6b7884919eabb7baaea194877b6e6154483f3f3e3d3a342d241b11060000000005111e2a36424d56606d79849199a3abb3babfbbb9b1abaaa8a6a7a9abaeb3babec5cec6b9ac9f93867b6e6154483b2d22170b000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4947433d342b20160a000005121f2c3845525f6b788586868686868686868175685755626f7c8686868686868686867f7265584c3f2f24190d01000000000000000000000000000000000000000000000000050d161d242930383f44464c5254575a5b5c5d5d5c5b5a5754524c46443f383029241d160d050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000000000006131f2c3845515c676d6d6d6d6d6d6d6d6d6d6d665c5044382c1f12060000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3baada297928f8f8f8f8f8f9092989b9ea5aeb4bcc4bab0a69e9184786d6053463a2f24190d01000000000000000000000000000000030608090c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0a09070400000000000000000000010c161f2b353e48505960666d72777b7f8284868788887d706356493d3023160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111d2a3744505d6a7783909daab6c3b7aa9d908477685e52463b363942505a6875828e9ba8b5c1baaea298877a6d6154473a2e21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212e3a4754616d7a8796a0acb9b9ada197877b6e6154483b2e2115070000000000000000000000000006111b262f383f4446515e6b7884919eabb7baaea194877b6e61544c4c4c4b4a453f362d22180c010000000714202d3a46525e6974818e96a0abb5bdbeb6afaca79f9d9b9a9a9c9fa2aaaeb3bcc5c7bbafa4998b7e716553493f33271b0f0300000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3c3b38322b22190f04000003101c2936434f5c6976828f939393939393918578695e53606d7986929393939393938e817568564c4135291d11040000000000000000000000000000000000000000000000050e171f282f353e424a5053565e61646668696a6a69686664615e5653504a423e352f281f170e0500000000000000000000000001070b0f111213131313131313131313131313131313131211100e0b080806020000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000000000004101c2834404b555c60606060606060606060605c544a3f34281c10030000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3beb3a9a29f9c9c9c9c9c9c9d9fa2aaaaafbabfc4bbb2a89e948a7e71665c504438281e1308000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d19232c363e474f545c60656a6f727577797a7b7c796d6054473a2d2114070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2b9ac9f93877a6e61564d4642454b54616c7885919eabb8c4b8ab9f928578685d5246392d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724303d4a5763707d8a96a8b2bdb8ab9e918578695e53463a2d211407000000000000000000000000000b17222d3841495053585e6b7884919eabb7baaea194877b6e6158585858585650483f34291d11050000030f1b27333f4953616e7b86929fa8b2bdc0b6aca49f9a95908e8d8d8f92989fa2aab3bcc5c0b5ab9b8e8275655b5044372b1f12050000000000000000000000000000000009121b22292e31323232323232323232323232323232323232323232323232323232322f2e2b2720191007000000000d1a2633404d596673808c99a0a0a0a0a197877b6e61545c667683909da0a0a0a09d918477685d5245392c20130600000000000000000000000000000000000000000000050e172029313a414550545c6064686d707375767777767573716d6864605c545045403a312920170e0500000000000000000000050c12171b1d1e20202020202020202020202020202020201f1e1d1b181514120f0a05020000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000c18232e39434b515353535353535353535353504a42382e23170c000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3c5bbb3adaba9a9a9a9a9a9aaabaeb4b6bbc1c1bab2a9a0968f82756c61544a3f3428160c010000000000000000000003050607060400000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007111a242c353d424a5153585f626568666c6e6e6f6d675d5145392c2013060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a9b3bebbafa49a8b7f72685e56524d51555d66707d8a97a1adb9c2b6a99c8f837669564c4135291d110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c28333f4a546673808c99a6b3bfb5a89b8f827568574d42362a1e1205000000000000000000000000030f1b27333f49535b6065656b7884919eabb7baaea194877b6e656565656565625a50453a2e211509000005121f2b3744505b6573808c99a3afbac4bbafa49a938d888381808182858b9298a2aab3bec5b8ab9e9285786c605346392d20130600000000000000000000000000000000000911181d21242526262626262626262626262626262626262626262626262626262623221f1b160f0700000000000a1724303d4a5763707d8a96a8b2adb3a9978a7d716457546774808d9aa7adadac9f93867a6d6054473a2d211407000000000000000000000000000000000000000000030c162029323b434b515a61666d71767a7d80818383838382807d7a76716d66615a514b433b322920160c030000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c2c2b29282522211f1a15120e0903000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000007121d27303940454647474747474747474746443f3830261c1106000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3cdc5bebab8b5b5b5b5b5b6b7b8babec5c2bcb8afa8a09791847a6d615a5042382e231704000000000000000000060b0f12131313100c070e0b08070502000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008121a232b30394044464e535558545b60616162605d554b4135291d11040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707d8997a2adbac0b6ac9e92857a6e69615e575d60676d7983909da9b3bebdb2a8998c807366594d403024190d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505b6676828f9ca9b6c0b5ab998c7f7266594c3f31251a0e0200000000000000000000000005121f2b3744505b656c7272727884919eabb7baaea194877b727272727272716c62564a3d3124170b00000613202d394653606c7885919eabb5c0baafa59f9388807b7775737476797e869298a2aebac5b9ada197887c6f6255493c2f221609000000000000000000000000000000000000060c111517181919191919191919191919191919191919191919191919191919191615130f0a040000000000000714212e3a4754616d7a8796a0acb9b3a69a8d807367545764717e8a97a9b3bbafa49a897d7063564a3d302317090000000000000000000000000000000000000000000b151e28323b444c555d606c70787e82868a8d8e8f90908f8e8d8a86837e78706c605d554c443b32281e150b00000000000000050f1820282f333738393939393939393939393939393939393939383634322f2e2b26211e1a140e080200000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000000000000000b151e272e34383a3a3a3a3a3a3a3a3a3a3a38342e261e150a00000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6bfbfbfbfbfbfbfbfbfbfbfbfbfbebdbdb8b7b1aba59e9691857c6e685e52483e30261c110600000000000000020a11171b1f20201f1c181d1b181514120e0903000000000000000000000000000000000000000000000000000000000000000000000000000000000000000811191e272e34383c4347484c4a505354555554514b433a2f24180d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7985929fabb8c1b9ada29790837b736e696a676d7179828f95a0acbbc4b9aca096897c6f6256493c2f23160800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7985929fabb8bbafa399897c6f6356493c30231609000000000000000000000000000613202d394653606c777f7f7f7f85929eabb8bfb2a6998c7f7f7f7f7f7f7f7e7165584b3e3225180b00000915222f3c4855626f7b8897a1adbdc7b6a99e938b7e746e69686767666d727c86929fa9b3bebeb3a9988b7e7165584b3e3225180b000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0908060300000000000000000713202d3946525e687784919eaab7b6a99c908376665c55626e7b8897a2adbab6ac998c7f7266594c3f30251a0e020000000000000000000000000000000000000007121c27303a444c565e676d757d848a8f9299999b9c9d9d9c9b999993908a847d756d675e564c443a30271c12070000000000010c16202a323a3f43454646464646464646464646464646464646454443413e3b3a37312d2a261f19140d05000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000000030c151d23282c2d2d2d2d2d2d2d2d2d2d2d2c28231c150c0300000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b2b2b2b2b2b2b2b2b2b2b2b2b2b2b1b1b2acaaa79f9d938e847b6e6a5f564c41362c1e150a00000000000000020b141b22272b2d2d2c282329272421201e1a140f0b06000000000000000000000000000000000000000000000000000000000000000000000000000000000000070c151c23282c31373a3c3f3f44464748494745413a31281d13070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844515c6674818e9aa5afbcbeb3a99f9590857f7b7877787a7e838f949fa7b1bcbeb3a99e9184786c605346392d20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3c4855626f7b8898a2aebab9ac9f92867a6d6053473a2d201407000000000000000000000000000713202d3a4653606d79868b8b8b9297a2adb9c0b4a89c918c8b8b8b8b8b8b85786c5f5245392c1f1206000b1825323e4b5865717e8b98a9b3bebeb3a99b8e81746c615f575a545c606a717e8b97a1adb9c0b3a79a8d8074675a4d4134271a0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d2a36414c566875818e9ba8b4b8ac9f9285796d6053606c7985929fabb8b5a89b8f827568574d42362a1e1105000000000000000000000000000000000000000c18232e39424c565e686e79818a91969c9fa3aba8a9aaaaa9a8aba49f9c96918a81796e685e564c42392e23180c030000000007121d28323c444b505153535353535353535353535353535353535251504e4b4847433c3a36312a251e170e080000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000030b12181c1f20202020202020202020201f1c17110a030000000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a4a8a09d9a959089817a6e695f584e443a30241a0c03000000000000000a141d262d3337393a38342e3634312e2d2a251f1b17110a020000000000000000000000000000000000000000000000000000000000000000000000000000000000030b12181c1f262b2e2f2d3338393b3b3c3a39352f281f160c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404a54626f7c88939eaab4bfbbb1a79f97918c87858484868a91959fa6b0b9c3b9ada1978c7f72655b5044372b1f120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e8b98aab3beb6aa9d908377675d5145392c1f1306000000000000000000000000000713202d3a4653606d79869398989ea2a9b3bec4b8ada39c9998989898989285786c5f5245392c1f1206000e1b2834414e5b6774818e9aa7b4c1b9ada197897c6f625a534d4d4b5158606d7985929eabb8c2b5a99c8f8276695c4f432f23180c0000000000000000000000000000000000000000000000000000000000000407090a0b0b0b0b0b0b0b0b0b0807050200000000000000000000000000000000010d1925303f4c5865727f8b98abb5baaea298887c6f62555b6576828f9ca9b5b8ab9e918578695e52463a2d20140700000000000000000000000000000000000004101c2834404a545e686e7a838e939ea0a8acafb5b4b6b6b6b6b5b5afaca8a19e938e837a6e685e544a403428201509000000000b17232f3a444e565c5e606060606060606060606060606060605f5f5e5c5b5855534e4846423b363029201a110800000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000000000000070c1013131414141414141414141312100c0600000000000000000000000000000000000000000000000000000000101d2a3743505d6a7683909898989898989898989898989898989898979696918d89837d756d685f574e463c32291e12080000000000000006111b262f383f44464645404443413e3b3a36302b27221b140b06000000000000000000000000000000000000000000000000000000000000000000000000000000000000070c10151b1f212222282b2d2e2e2f2d2c29241d160d040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3947535f6a75828e98a2aebac0b9b1a9a19e999892919193999da0a8b0b8c2bab0a69e9185796d6053493f33271b0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935404b556774818e9aa7b4c0b4a79a8d817467554b4035291d1004000000000000000000000000000713202d3a4653606d798693a0a5abadb3bbc5cabfb5ada8a6a5a5a5a59f9285786c5f5245392c1f120600101d293643505c6976838f9ca9b6c2b8ab9e9285796c60534642404045515c6675828e9ba8b5c1b7ab9e9184786b554b4034291c1004000000000000000000000000000000000000000000000000000000050b101316161818181818181818181514120e09030000000000000000000000000000000816232f3c4956626f7c8999a3aebbb4aa988b7e726558536673808d99a6b3b9ada196877b6e6154473b2e2114060000000000000000000000000000000000030e18212c3844515c666d7a8490959ea5acb2b9bbc0c1c0bebec0c1c0bbb9b2aca59e9590847a6d665c51443c31261a0f030000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6b696765625f5855534d46413b322c231a1108000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000000000000000000000000040607070707070707070707070603000000000000000000000000000000000000000000000000000000000000101d2a3743505d6a76838c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8b8a898784807c76706b605d564d453c342a20170c00000000000000000b17222d384149505353514b51504e4b4846423b37332d261d18100800000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f121515171c1f2021222221201d18130c040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121c2b37434e58616e7b86929fa4aeb7c0bbb3adabaaa29f9d9e9fa4abacb1bac2bab1a89e948b7e71675d5141382d22170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d677784909daab7beb3a9978b7e7164584b3e2f24180c00000000000000000000000000000713202d3a4653606d798693a0acb8b9bec5cdd1c8bfb8b4b2b2b2b2ab9f9285786c5f5245392c1f120600111d2a3744505d6a7783909daab6c2b5a99c8f8276665b5044383134404b5466737f8c99a6b2bfb9ac9f928679675c5145382c1f13060000000000000000000000000000000000000000000000000000070f161c20222325252525252525252522211e1a140e0600000000000000000000000000000714202d3a4753606d7986929facb9b4a79b8e817468555764707d8a97a8b2bdb2a9978a7d7064574a3d2d22170b000000000000000000000000000000000009141f2b37434e58606d78839096a0a7afb9bdc3bcb8b6b3b2b1b3b6b7bcc2bdb9afa7a0969082786d60584e43372b1f1409000000111d2a3743505c687278797979797979797979797979797979797978777674716e6a67615f57524c443e352c231a10070000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313e4b5764717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7e7c7a77746f6a636059524c433c332a22180e0500000000000000030f1b27333f49535b60605c5f5e5c5a5754524d46443f382f2a221a11080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030608060b0f12131415161413110d07010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b26323c46535f69717e8b929da5aeb9bebeb9b8b4aeabaaabacafb5b8bdbfbab0a8a0958f82756c62554b402f261b110600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a86939facb9b9ada197887b6e6155483b2e22150700000000000000000000000000000713202d3a4653606d798693a0b4b7b9bdc4ccd2c8c0b9b5b3b2b2b2ab9f9285786c5f5245392c1f120600111e2b3844515e6b7784919eaab7c1b4a89b8e817568544a3f33282e3f4b5865727e8b98a5b1bebbaea39986796d6053473a2d2014070000000000000000000000000000000000000000000000000007111921272c2f303131313131313131312e2d2b261f180f060000000000000000000000000006131f2c3845515c677783909daab6b7aa9d918477675d54616e7a8796a1adb9b3a6998d80736653493f33271b0f03000000000000000000000000000000020e1a26313a47535f6a73808d959fa8b1b9c1bbb7b1abaaa6a5a5a6a9abb0b8bcc1b9b1a89f948d80736a5f53473b31261a0e020000121e2b3845515e6b78848686868686868686868686868686868686858483817e7b77736e69615e564f473e362c22190c0300000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000000000002070b0d0d131313131313131313131313131313131313131313131313131313130808060200000000000000000000000000000a1723303d4955616c71727272727272727272727272727272727272716f6d6867626058544f45413a312a21180f06000000000000000005121f2b3744505b656c6d666c6b696764615e57535049413c342c231a10070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306060808090706040100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a15202a36424d57626c74808d939da4adb2babec4bebab8b7b7b9bbc0bfbab4aea69f9691837a6d605a50433a2f1d140a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707c8999a4afbbb8ab9e928578695f53473a2d21140800000000000000000000000000000713202d3a4653606d798693a2aaabacb2bac2cac0b6aea8a6a6a6a6a69f9285786c5f5245392c1f120600121f2c3845525f6b7885929eabb8c0b4a79a8d8174675a4e412d22313e4b5864717e8b97a4b1bebfb5ab94877a6e6154473b2e211408000000000000000000000000000000000000000000000000050f19232b33383c3d3e3e3e3e3e3e3e3e3e3b3a37312a21180e0300000000000000000000000004101c2934404b556774818d9aa7b4b9ac9f93867a6d60545e687884919eabb7b6a99c8f8276655b5044372b1f120500000000000000000000000000000005121e2a36424d57626e7c87929fa7b1bac1b8b0aba79f9d9a9898999c9fa6abb1b9c2bab0a69f92877c6e62574d42362a1e12050000121e2b3845515e6b7884919393939393939393939393939393999292918f8e8b8884807b756e68615950483e342a1e150b00000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000080e1317191a202020202020202020202020202020202020202020202020202020201514120e09030000000000000000000000000815212d3945505a61646565656565656565656565656565656565656463615e5656544e48443d352f281f180f060000000000000000000613202d394653606c77797979777674716e6964605b534e463e352c22190d030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040e1a26313b45505a606d78818d929ea1a9adb3b8b9bebdbdbdbebab8b4aeaaa39f9490847b6e685d52483f31281d0b020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c99abb5c0b5a89c8f827569574d42372b1e120600000000000000000000000000000713202d3a4653606d79869298989ea1a8b0b8c2b9aea49c9a99999999999285786c5f5245392c1f120600121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea194887b6e6155483b2e2215080000000000000000000000000000000000000000000000000b16212b353d4448494b4b4b4b4b4b4b4b4b4846423c332a1f1409000000000000000000000000000c18232f3e4b5864717e8b97a9b3bbafa49a897d706356566875828f9ba8b5b8ab9f9285796c605346392d2013060000000000000000000000000000000714212d3a46535f6975828f99a3afb9c1b8b0a69f9c95908d8b8b8d90949d9fa7b0b8c2bbafa3998f8275695f53463a2d2114080000121e2b3845515e6b7884919e9f9f9f9f9f9f9f9f9f9f9f9f9fa39f9f9e9c9a9896918d87817a706b615a50463c30271d1207000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000000020a12191f2326272d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d22211e1a150e06000000000000000000000005111d28343e48505557595959595959595959595959595959595958575654524c4947433d383329241e160d06000000000000000000000815212e3b4854616e7b8686858483817e7b76716c655f584f473e342b1f150b01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f29333f44505c666d77808a91979fa2a9abadb3b0b0b0b3adabaaa39f98928c827a6e695e564c41362d1f160c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d576975828f9ca8b5c0b5ab998c7f7366594c4031261a0e0200000000000000000000000000000713202d3a4653606d788485888b91969ea6b0bbb5a89c928d8c8c8c8c8c8c85786c5f5245392c1f120600121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000000000000000000000000000000000000000000000004101c27333d474f545658585858585858585855534d453c31261a0e020000000000000000000000000715222f3b4855626e7b8897a2adbab6ac998c7f7266595966727f8c99acb6baada297887b6e6255483b2f2215070000000000000000000000000000000815222e3b4855616e7b87939fabb5c0bbb0a69e94908883807f7e80838890959fa6b0bcc0b5ab9f93877b6e6155483b2f24190d0100121e2b3845515e6b7884919eabacacacacacacacacacacacb4aeacabaaa9a7a8a09e99928e857d706c61584e43392e23180c000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000a141c242a2f3334393939393939393939393939393939393939393939393939393939392f2e2b2620180f0600000000000000000000000c17222c363e45494b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4b4b494746413c3b38322c272119130c0400000000000000000000000815212e3b4854616e7b879392918f8d8a87837e786f6a61594f463d31271d12070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030d182128343f4a545c656c737d848c92979b9ea1a9a3a4a3a9a29f9c98928e867f786e685e574d443a30241b0d040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535f697885929eabb8bbafa499897d7063564a3d3023170900000000000000000000000000000006121f2b3844505c666d78797b7e848f949ea9b3b3a69a8d807f7f7f7f7f7f7f7265594c3f3226190c0000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000000713202c38444f596063646464646464646464615f574d42372b1e12050000000000000000000000000613202d394653606c7985929fabb8b5a89b8f827568575663707c899aa4afbbb3a9978b7e7164584b3e2e23180c0c0c0c0b0a08050000000000000004111d2935414c566673808c99a4afbdbeb3a99e948f827c7773727273767c838f949faab4bfbbafa4998c807366564c4135291d110400121e2b3845515e6b7884919eabb7b9b9b9b9b9b9b9b9b9b9bfbab9b8b7b6b4b2acaba39f9792877e706a5f554b4034281c11060000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000008121c262e363b3f40464646464646464646464646464646464646464646464646464646463b3a37312a21180e030000000000000000000006101a242c34393d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3e3c3a3935302e2b27201c160d08010000000000000000000000000815212e3b4854616e7b87949f9e9c9a9a93908a837c706b61584e43392f24180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f17232e38424a535b606c707a80858a8e9297969697969697928f8b86817b736d665e564d453b32281e1209000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b8897a1adb9b9ac9f93867a6d6054473a2d21140700000000000000000000000000000003101c28343f4a545c606b696e7279828f97a2adaea194877b737373737373726d62574a3e3125180b0000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000000916222f3c4854606b707171717171717171716e695f53463a2d21140700000000000000000000000005121f2b3744505b6576828f9ca9b5b8ab9e918578695e54606d7a86939facb9b3a79a8d807467544b4034281c19191919181715110c0600000000000713202c3945525d687784909dabb5c0baada2978f82786f6a676565666a6f79828f98a2aebac0b5ab9d908377685d5245392c20130700121e2b3845515e6b7884919eabb7c4c6ccc6c3c2babababababababcbec2c1bdb9b5afa9a19992877c6f675c5145382e23170b0000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200020e19242e3840474b4d535353535353535353535353535353535353535353535353535353534847423c332a201509000000000000000000000008121a22282d303132323232323232323232323232323232323231302e2d2925221f1b16100b0500000000000000000000000000000815212e3b4854616e7b8794a1aaa9aca49f9c9590867d706a60554b4035291d120700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c2630384149505a61676d73797e828587898a8a8a898785827e7a746e69605c544c443b332920160c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313e4b5764717e8a97a9b3beb7aa9d908477675d5145392c201306000000000000000000000000000000000b17232e38424a5053575f61676d7a85929eabaea194877b6e666666666665625b51463a2e2216090000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000000a1623303d495663707d7e7e7e7e7e7e7e7e7e7b6e6155483b2e221508000000000000000000000000090f1b27333f49536673808c99a6b3b9ada197877b6e61545d677784919daab7b6a99d908376665c5145382c26262626262524211d171009000000000714212d3a4754606d7a8795a0acbdc5b8ab9f92857a6d665f585858585f676e7b86929facb8c5b9ac9f93867a6d6054473a2d21140700121e2b3845515e6b7884919eabb7c4c9c1bbb6b5adadadadadadaeafb1b5b9bbc0c0bbb3aba3999083796d60544a3f34281c100300000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120007131f2a36404a52585a6060606060606060606060606060606060606060606060606060606055534e453c31261a0e0200000000000000000000000810171d212324262626262626262626262626262626262625242321201d1915130f0a04000000000000000000000000000000000815212e3b4854616e7b8794a1aeb6b6afaca7a09892867c6f675d5145392e23180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141e262f383f4450555d60676d7175787a7c7d7d7d7c7b7975726d68615f57504a423b322921170e040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b556774808d9aa7afafafa79a8e817467554c4135291d11040000000000000000000000000000000006111c2630383f44464d53555d6873808d99acb6a194877b6e6159595959595751493f35291e12060000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000030f1c2936424f5c6975828b8b8b8b8b8b8b8b8b7e7164584b3e3125180b000000000000000000000009121a22282d3d4a5764707d8a97a8b2bdb3a9978a7d716457556874818e9ba7b4b9ac9f9286796d6053463a33333333333331302d29221b12090000000a1723303d4a5663707d8996a7b1bcc0b3a79a8d8074685d544e4c4b4e555e6974818d9aa7b4c0bbafa49a897d706356493d3023160a00121e2b3845515e6b7884919eabb7c4c1b7afaaa8a0a0a0a0a0a0a1a2a4a8acafb6bec5bdb4aba0958b7e72665c5044382b1f120600000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000b17232f3b47525c64676c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c5f574e42372b1e1206000000000000000000000000060c1115171819191919191919191919191919191919191818161413110d0806030000000000000000000000000000000000000815212e3b4854616e7b8794a1aeb7b9bbb9b1aaa2989184796d60554b4034281c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c141d262d333e434c51555d606468686e6f7071706f6e6c6565615e56534d443f38302920170f05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c677683909da2a2a2a2aa988b7e7165584b3e2f24190d0100000000000000000000000000000000000a141e262e34383b42464c56636f7c899aa4afa194877b6e61544c4c4c4c4a463f372d23180d010000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000030f1c2936424f5c6975828f979797979797978b7e7164584b3e3125180b0000000000000000000006101a242c34393b4754616e7a8796a1acb9b3a69a8d807367545865727e8b98aab4baaea398897c6f6256493f3f3f3f3f3f3f3e3d39342d241b100600000c1825323f4b5865727e8b98a5b1bebfb5ab96897d7063564c423f3f434d5763707d8a96abb5c0c0b6ac988b7e7165584b3e3225180b00121e2b3845515e6b7884919eabb7c4bbafa59e9b9494949494949495979b9fa4acb4bcc6bdb1a79e9184786d6053463a2d20130600000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000d1926333f4b58646e7379797979797979797979797979797979797979797979797979797979766a5f53473a2e211408000000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0b09070705010000000000000000000000000000000000000000000815212e3b4854616e7b8794aba5aaacb2babcb4aaa1968c8073675c5145382c1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b141b2227313a41454b515357565e61636364636361605b5354524c46423b342e261e170e050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d79869295959595959598887b6f6255483c2f221508000000000000000000000000000000000000020c141c23282b31363a4753606d7a86939faca194877b6e61544840403f3e3a352d251b1107000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca4a4a4a4a4978b7e7164584b3e3125180b000000000000000000000c17222c363e45494b525e687884919eabb7b6a99c908376665c56626f7c8998a3aebab4aa988b7e7265584c4c4c4c4c4c4c4c4b49453e362d22170c00000d1a2633404d596673808c99a6b3bfbbaea399877a6d6154473a30313b4754616d7a8799a3afbbbfb3a6998c807366594d4033261a0d00121e2b3845515e6b7884919eabb7c4b6aa9e938f87878787878787898b8f939aa2aab4bfc3b9aca096897c706356493d2d22170b00000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000d1a2734404d5a677380868686868686868686868686868686868686868686868686868686867c6e6255483b2f2215080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815212e3b4854616e7b879995999ea0a8b0b8bcb2a89e9285796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a11171f282f35394045474b4c52545657575756545350494746413a363128231c150c05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c89898989898989898986786c605346392d20130600000000000000000000000000000000000000020a11171c1f262c3945515d677885919ea5a194877b6e6154483b3332312e29231b130a00000000121f2c3945525f6c7885929fabb8c1b4a79a8e8174675b4e413428323e4b5865717e8b98a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b1b1b1a4978b7e7164584b3e3125180b00000000000000000005111d28343e4850555759566875828e9ba8b5b8ac9f9285796d6059606d7986929facb9b4a79b8e817468555959595959595959585650483e34291d1105000e1a2734414d5a6774808d9aa7b3c0b9ac9f9286796c605346392d2d394653606c7986929facb9c0b3a69a8d8073675a4d4034271a0d00121e2b3845515e6b7884919eabb7c2b5a89b8f817a7a7a7a7a7a7b7c7e82889298a2aebac4bdb2a89a8d807467544a3f33281c0f03000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000815222f3b4855626e7b889593939393939393939393939393939393939393939393939393887b6e6255483b2f2215080000000000000000000000000000000005080a0b0b0b0b0b0b0b0b0b0b080705020000000000000000000000000000000000000000000000000000000000000815212e3b4854616e7b8786888c91969fa6b0bdb9ada2978a7e7164574a3e2f23180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060d161e24292f35393a3e414647494a4a4a494846443f3a3935302a261f17110a0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212e3a4754616d7a7c7c7c7c7c7c7c7c7c7c6f665b5044382b1f1206000000000000000000000000000000000000000000060b10141d2935404b556a77849098989894877b6e6154483b2e2625221e18110a0100000000121f2c3845525f6b7885929eabb8c1b4a89b8e8175685b4e423126323f4c5865727f8b98a5b2bebbaea194887b6e6155483b2e22150800000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b0000000000000000000815212d3945505a6164666666727f8c98a5b2baaea298887c6f666666667683909da9b6b7aa9d9184776766666666666666666664625a5045392d211508000e1b2734414e5a6774818d9aa7b4c0b8ab9f928578655b5044372b2b3744505b657885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e82756d6d6d6d6d6e6f71757d86929fa8b2bdc3b6aa9d908377665b5044382b1f1206000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000814212e3a47535f6a7683909d9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f95887b6e6255483b2f2215080000000000000000000000000000060c111517181818181818181818181514120e0903000000000000000000000000000000000000000000000000000000000714212d3a46535e696e797a7c7f848f949fabb5beb3a99a8e817467554b4034291c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c13191d24292c2d3036393b3c3d3e3d3c3b3937332d2d29251e1a140c06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3946525e686d6f6f6f6f6f6f6f6f6f6f6a5f544a3f33281c0f030000000000000000000000000000000000000000000000030c18242f43505d6a76838b8b8b8b8b877b6e6154483b2e211516120d07000000000000121e2b3845515e6b7884919eabb7c2b5a99c8f827669574d42372b333f49536673808c99a6b3bfbbafa49a877a6e6154473b2e21140800000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b0000000000000000000a1724303d4955616c71727272727c8996a2afbfb4aa988b7e727272727274818d9aa7b4b9ac9f93877a72727272727272727272716c6256493d3024170a000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f493f332727333f495f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e827568616161616162646b717e8b96a0acb9c5b8ac9f9285786c605346392d201306000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120006121f2b37434e5865717e8b98a2aeacacacacacacacacacacacacacacacacacacacaca195887b6e6255483b2f221508000000000000000000000000000910171d21242425252525252525252521211e1a140d0500000000000000000000000000000000000000000000000000000005121e2a36424d575e61676d6f7279828f99a4afbbb7aa9d918477675c5145382c1f1306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001080d12181d2020252a2d2e30303130302e2d2b2722201d19130e0903000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d2935414c565e61626262626262626262625f584e42382d22170b00000000000000000000000000000000000000000000000000071724303d4a5763707d7e7e7e7e7e7e796d6053473a2d201407060100000000000000111d2a3744505d6a7783909daab6c3b8ab9e918578695f53473b383944505b6575828e9ba8b5c1b9ac9f9386786d6053463a2d20130700000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b0000000000000000000b1824313e4b5764717e7f7f7f7f808c99a6b3bfb6a99c90827f7f7f7f7f7f818f9ba8b5bbafa49a8d807f7f7f7f7f7f7f7f7f7f7e7164584b3e3125180b000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f52452d22222d45525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b545454545659606c7884919eaab7c4baaea298877b6e6154483b2e211508000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200020f1a26313c4754606d7a86929facb8b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9aea195887b6e6255483b2f22150800000000000000000000000009121a22282d30313131313131313131312e2d2a251f170f050000000000000000000000000000000000000000000000000000020e1a25313b454d53555d6062676e7b87939facb9b9ac9f93867a6d6053473a2d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d101314191e2021232424242321201f1b1713110d080200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1925303a444c525456565656565656565655534e463c2f261c1106000000000000000000000000000000000000000000000000000a16232f3c4855616b707272727272726d675d5145392c2013060000000000000000000f1c2935424f5c6875828f9ba8b5c2b9ada197887b6e62574d4644464b54606c7884919eabb7c4b8ab9e918578665c5145382c1f130600000000000000000000000000000000010406070a0c0d0f1c2936424f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d6976838c8c8c8c8c929ca8b4c1b7ab9f94908c8c8c8c8c8c8f939eaab6c0b6ac9d928d8c8c8c8c8c8c8c8c8c8c83776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f47474849505b6574818d9aa7b4c0bfb4aa95887c6f6255483c2f221509000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000915202c3945515d6775818e9ba8b2bdc9d0c7c0bbb9aeacacacacacacacacacacaca195887b6e6255483b2f221508000000000000000000000006101a242c34393d3e3e3e3e3e3e3e3e3e3e3b3a36312921170d03000000000000000000000000000000000000000000000000000009141f29333b42464b5153555f697784909daab7bbafa49a887b6e6255483b2f221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010406080e11141416171717161513120f0b0605010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e28323a4146474949494949494949494847433c342a1d140a00000000000000000000000000000000000000000000000000000714202c38444f596163656565656565605d554b4035291d10040000000000000000000d1a2633404d596673808c99aab4bfbeb3a9998d8073695f57535053555c66707c8996a1acb9c2b5a99c8f827669544b4034281c1004000000000000000000000000000001080d1113141718191a1c2936424f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d69768390999999999ca4aeb9c4bcb0a69f9c9999999999999b9ea5afbbc7beaea49d9a9999999999999999999083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423a3b3f495365727f8b98a5b2bebcafa295897c6f6256493c2f231609000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000004111d2935414c5563707d8996a0acb9c7c7beb6afaca19f9f9f9f9f9f9f9f9f9f9f9f95887b6e6255483b2f22150800000000000000000000000c17222c363e45494b4b4b4b4b4b4b4b4b4b4846423b33291f14090000000000000000000000000000000000000000000000000000030d17212931363a4045474d576875818e9ba8b4c0b6ac96897d7063564a3d3023170a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002050708090a0b0a09080605030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c1620283035393a3c3c3c3c3c3c3c3c3c3c3a37312a22180b02000000000000000000000000000000000000000000000000000004101c28333e474f555758585858585853514b43392f24180d010000000000000000000a1724303d4a5763707d8a98a2aebac4b8ac9f92867b6e6962605b5e61676d7883909da8b2bdbdb2a8998c807366594d402e23180c00000000000000000000000000050c1113191d202124252627262936424f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909ca5a5a6a8aeb6bfcac2b9b0aba9a5a5a5a5a5a5a8aaafb8c1d0c0b6aea9a7a5a5a5a5a5a5a5a59d9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352d3e4b5764717e8a97a4b1bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000010d19242f3a4653606c7884919eabb5c0c0b6aca49f9493939393939393939393939393887b6e6255483b2f2215080000000000000000000005111d28343e4850555758585858585858585854534d453b31251a0e020000000000000000000000000000000000000000000000000000050f171f252a2f3539414e5a6774818d9aa7b4bdb0a4978a7d7164574a3e3124170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040e161e25292d2e2f2f2f2f2f2f2f2f2f2f2e2b2620181006000000000000000000000000000000000000000000000000000000000b17212c353e44484a4b4b4b4b4b4b4745403931281d1207000000000000000000000714202d3a4753606d7a86929facb8c2baaea29891847b736f6c66696e7279818e959fabbac4b9aca196897c6f6256493c2f2316070000000000000000000000030a0f171d1e24292c2d30323333333136424f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909ca9b2b3b4b9bfc7cbcbc2bcb7b6b2b2b2b2b2b2b5b6bbc1c7cdc8c0b9b5b4b2b2b2b2b2b2b2aa9d9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000008131f2b3744505b65737f8c99a4afbbbbafa49a938886868686868686868686868686867b6e6255483b2f221508000000000000000000000815212d3945505a6164646464646464646464615e574d42362a1e1205000000000000000000000000000000000000000000000000000000050d141a1d242934404d5a6773808d9aa6b3beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c13191d202123232323232323232322211f1b150e06000000000000000000000000000000000000000000000000000000000005101a232c33383c3d3f3f3f3f3f3f3a39352f281f160c010000000000000000000006131f2c3945515d6775828e9ba6b0bdbfb4aaa0969186807b7978797b7e848e939ea7b1bcbeb3a99e9184786c605346392d20130600000000000000000000060e151b22282d2f35393a3d3f40403f3e3a424f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909ca9b5b5b5b5b9babfc6cfc7c5beb9b8b5b5b5b5b5b5b6b7bbc2cacbc5c3bdb8b7b5b5b5b5b5aa9d9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000000030f1b27333f4953616e7b87939facb9b9ac9f93877b7979797979797979797979797979766a5f53473a2e211408000000000000000000000a1724303d4955616c717171717171717171716e695e53463a2d2114070000000000000000000000000000000000000000000000000000000003090e13182734404d5a6773808d9aa6b3beb1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080d1113141616161616161616161515120f0a040000000000000000000000000000000000000000000000000000000000000008111a21282c2f303232323232322d2c29241d160d04000000000000000000000004101d2935404b5563707d89949fabb5c0bcb2a8a098928c88868586878b91969ea5afb9c2b9ada1978c7f72655b5044372b1f120500000000000000000007101820262b33393a4145474a4b4c4d4c4a47464f5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909ca8a8a8a8a8acaeb4bcc6c5bbb3adaba8a8a8a8a8a8a9abb0b8c2cfc3bab1acaaa8a8a8a8a8a89d9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235303d4a5763707d8a96a3b0bdbcafa295897c6f6256493c2f231609000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000000000b17222d3846535e6976828f9ca9b3bbafa49a8c8073656c6c6c6c6c6c6c6c6c6c6c6c6c5f574e42372b1e1206000000000000000000000b1824313e4b5764717e7e7e7e7e7e7e7e7e7e7b6e6154483b2e23180c00000000000000000000000000000000000000000000000000000000000001071a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105070709090909090909090909080603000000000000000000000000000000000000000000000000000000000000000000000810171c20232425252525252520201d18120c04000000000000000000000000000c18242f394854606b76839099a3afbbc1bab2aaa29f999993929299989ea0a8afb7c1bab0a69e92857a6d6053493f33271b0f030000000000000000071119222a31373e45494c52545758595a595754524c5c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909c9c9c9c9c9c9fa3aab4bfbeb3a9a19e9c9c9c9c9c9c9c9fa6b0bdc7bdb1a8a09d9c9c9c9c9c9c9c9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235303d4a5763707d8a96a3b0bdc0b6ac95887c6f6255483c2f221509000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb8ab9f9285786c5f5245392c1f120000000006111b2a36424d5764717e8a97a2adbab6ac9e9184786c60606060606060606060606055534e453c31261a0e0200000000000000000003101d2a3643505d6976838b8b8b8b8b8b8b8b8b7f7366554b4034281c10040000000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b101416171818181818181413100d0701000000000000000000000000000007121d2c38444f59626f7c87929fa6b0b8c1bcb4aeababa49f9e9fa3abaaacb2bac1bab2a89e948b7e72675d5141382d22170b0000000000000000061019232b343c43475055565d60636566666664615e565c6975828f9ca8b5beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d6976828f8f8f8f8f8f8f9298a3aebab9ada197928f8f8f8f8f8f8f949fabb5c0b8aca095918f8f8f8f8f8f8f8f83776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235313e4b5764717e8a97a4b1bdbbafa49a887b6e6155483b2e221508000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b2b2b2ab9f9285786c5f5245392c1f1200000000000e1a25313b4753606d7985929fabb8b9aca196897d7063564c5353535353535353534847423c332a20150900000000000000000000000d192633404c5966737f8c979797979797978f8376675c5145382c1f13060000000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003080b0d0e1313131313131313130b0a080500000000000000000000000000000000000000000000000000000000000000000004070a0a0c0c0c0c0c0c070604010000000000000000000000000000000001101c27323d4754606a73808c939ea6afb9bebebab8b5afacabacaeb4b7b9bdbfbab1a8a0968f82766d62554c412f261b110600000000000000030c18222b353d464e535a6164686d7072737372716d6863616975828f9ca8b5beb1a4978b7e7164584b3e3125180b0000000000000000000d1a2733404d5a6673808282828282828286929facb9b8ab9e9285828282828282828f99a3afbbb7aa9d918382828282828282828074675a4d4134271a0e000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423b3b3f4a5465727f8c98a5b2bfb9ac9f9386796d6053473a2d201407000000000000000000000000000000000000000e1b2734414e5a6774818d9aa5a5a5a5a59f9285786c5f5245392c1f12000000000009141f2c3845515c6774818d9aa7b1bcb2a89b8e8175685d524546464646464646463b3a37312a21180e0300000000000000000000000916232f3c4956626f7c8997a2a4a4a4a49f9286796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001080f14181a1b202020202020202020181715110c0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b16212b37434e58606c78818f949ea5adb3babec4c0bbb9b8b9babfc4bfbbb4aea79f9691847a6d615b51433a2f1d140a00000000000000000b151e2a343d474f585f626c71767a7d7e7f807f7d7a76706b6975828f9ca8b5beb1a4978b7e7164584b3e3125180b0000000000000000000d1926323f4b58636e737575757575757682909ca9b6b7aa9e91847775757575757986929facb9b4a79a8e817575757575757575746e64584c3f3326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f47474849505c6675818e9ba8b4c1b7ab9e918478675d5145382c1f1306000000000000000000000000000000000000000e1b2734414e5a6774808d989898989898989285786c5f5245392c1f12000000000004101c2934404b55626f7c8895a0acb8b8ac9f92867a6d6054473c313939393939392f2e2b2620180f060000000000000000000000000713202d3a4653606d7985929fabb1b1aea398897c706356493d2f24180c0000000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b131a202427282d2d2d2d2d2d2d2d2d2524211d17110900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050f1b27323c44505b666d79828e939ea2a9adb3b7b9bbc0bcbcbeb9b8b5aeaba39f9590847b6e685d52483f31281e0b020000000000000007121d27303c464f59606a6f767e83868a8b8c8d8c8a86827d766e75828f9ca8b5beb1a4978b7e7164584b3e3125180b0000000000000000000a17232f3b47525c636669696969696973808d99a6b3b9aca096877a6e696969677783909daab6b7aa9d9184776869696969696967645c52473c3023170b000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b54545455565a606d7985919eabb8bfb4aa9b8f827568554b4035291d1004000000000000000000000000000000000000000e1b2734414e5a6774818c8c8c8c8c8c8c8c8c85786c5f5245392c1f120000000000000c18232f394754606a7783909dabb5baaea2988b7e7265584e43372b2d2d2d2d2d22211e1a150e060000000000000000000000000006121f2b3844505c6675828f9ba8b5bfb4aa998c807366554b4035291d100400000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010b141d252b30333439393939393939393931302d29221b1209000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a152028333f4a545d676d79818b92979fa2a9aaacafb6afafb3adababa39f99928d837a6e695e564c41362d1f160c00000000000000000c18232e39424e58606b6f7c838a9092999899999999938f8a827b75828f9ca8b5beb1a4978b7e7164584b3e3125180b00000000000000000007131f2a36404a52585a5c5c5c5c5c64707d8a97a8b2bdb2a8978a7d70645c556774808d9aa7b3b9ac9f93867a6d605c5c5c5c5c5a58524a40362b1f1307000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e827568616161616263656c727e8b97a1adb9baaea2988b7e7165584b3e2f24180c00000000000000000000000000000000000000000a1723303d4a5663707d7f7f7f7f7f7f7f7f7f7f7265584c3f3225190c00000000000007121d2b37434e5865727f8c99a3aebbb4aa9d9083766a5f5347382e23172020201514120e0903000000000000000000000000000003101c28343f4a5465727e8b98a8b2bdb6a99c908376675d5145392c1f130600000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131d262f363c40414646464646464646463e3d39342d241b1106000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040b17222d38424b555d676d757e858d92979b9e9fa4aca3a2a9a19e9b99928e8680786e685e574d443a30241b0d040000000000000004101c2834404b545f6a6f7d8590959c9fa3aba6a6aba49f9c9490857b828f9ca8b5beb1a4978b7e7164584b3e3125180b00000000000000000006121d29343f495156585a5a5a5a5a616d7a8796a0acb8b3a69a8d807367555a64717e8a97a8b2bbafa49a8a7d70635a5a5a5a5a585651493f34291e1206000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e82756e6e6e6e6e6e7072777e86929fa9b3bbb2a89f92867a6d6154473a2e21140700000000000000000000000000000000000000000916222f3c4854606b70727272727272727272726d62564a3e3124180b000000000000010f1b27323c4754616d7a86929facb9b8ab9f95887b6e62544a3f34281c1013130808060200000000000000000000000000000000000b17232e3b4855616e7b8896a0acb9b9ac9f92867a6d6053473a2d20140700000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1a252f3841484c4e5353535353535353534b49453e362d22170c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c262f39434b555c606c717a80858a8e91939a9596959597918f8b86817b736d665e564d453b32281e1209000000000000000006131f2c3845515c666f7c8692979fa7acafb5b2b3b5afaca69f97918483909daab6beb1a4978b7e7164584b3e3125180b0000000000000000000915222e3a46515b6265676767676767687784919eaab7b6a99d908376676767676e7b8796a1adb9b6ac998c807367676767676765625b51463a2e221609000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b5a89b8f827a7a7a7a7a7a7b7c7f838a9298a3aebab1a9a0968d8073685d5246392d20130700000000000000000000000000000000000000000713202c38444f59606365656565656565656565625b51463a2e221509000000000000000a15202d3946525e6875828f9ba9b2bcb1a79a8d8073665c5044382c1f1308000000000000000000000000000000000000000000000614212d3a46535f697784919eaab7baaea399897d7063564a3d2f24180d01000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814202b36414a53595b606060606060606060585650483e34291d1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141d273139434b515a62686d73797d81848688898989888785827e7a746e69605c544d443b332920160c0000000000000000030f1c28333f4a54606d79839098a2a9b1b9bbc0bdb9b7b4b3b0a9a1969190959fabb8beb1a4978b7e7164584b3e3125180b0000000000000000000b1824313d4a56626d727373737373737374818e9ba7b4b9ac9f92867973737373737884919eabb7b6a99c8f8276737373737373726d62564a3e3125180b000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4b6aa9e938f87878787878788898c90959fa3aab4aea8a0979184796d60564c4135291d1105000000000000000000000000000000000000000004101c27333d474f5456595959595959595959585651493f34291e12060000000000000005111d2a36414c5663707d8a97a1adb9b8ab9e9185796d6053463a3025190d0100000000000000000000000000000000000000000005121e2a36424d576774818d9aabb5bfb4ab998d807366554b4135291d1104000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824303c48535d64676c6c6c6c6c6c6c6c6c64625a5045392d21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b151f273039404550565e61676d7174777a7b7c7c7c7b7a7875726d68625f57514a423b322921170e04000000000000000006121f2b3844505b66727f8c95a0aab3bcc2bebab2adaba8a7a7aaa9a19e9d9fa7b1bcbeb1a4978b7e7164584b3e3125180b0000000000000000000c1825323f4b5865727f808080808080808082909ca9b6baaea3988e8180808080808084919eabb7b8ac9f9286808080808080807f7265584c3f3225190c000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4bbafa59e9b9494949494949596989da0a7aeb4aaa29f9591857c6f675d51443a3024190d010000000000000000000000000000000000000000000b16212b353d44484a4c4c4c4c4c4c4c4c4c4c4a463f372d23180d0100000000000000010d1925303a4653606d7984919eabb8b9ada1978a7d7063564c41362a1d1105000000000000000000000000000000000000000000020e1a26313e4a5764717d8a99a3afbbb6a99d908376675d5145392c201306000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1a2733404c59646f74797979797979797979716c6256493d3024170a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030d151e272e343f444c52555d606468676d6e6f706f6f6d676865615e56534d444039302920170f050000000000000000000613202d394653606c7884919ea7b1bcc5bcb3aea8a19e9b9a9b9ea0a8abaaabb1b9c3beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d6976838d8d8d8d8d8d8d8d90949fabb7bfb4aa9d938e8d8d8d8d8d8d9196a1acb9baaea298928d8d8d8d8d8d8d83776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4c1b8afaaa8a1a1a1a1a1a1a1a3a5aaacb1baaea298928c837c6f6a5f554b4032281e130800000000000000000000000000000000000000000000050f19232b33383c3d3f3f3f3f3f3f3f3f3f3f3e3a342d251b110600000000000000000008131f2b3844505c6673808d99a6b0bcb3a99b8f8275685e5246392d20150a000000000000000000000000000000000000000000000914212d3a4754606d7a86929facb9b9ac9f92867a6d6054473a2d211408000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818686868686868686867e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c151d2328323a41464b515357555c606262636262605d555854524c47423c342e271e170e05000000000000000000000a1723303d4a5663707d8996a1acb9c3bdb3aaa29f96918e8d8e91969ea2a9b3bcc3cbbeb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909a9a9a9a9a9a9a9c9fa6b0bbc6bcafa59d9b9a9a9a9a9a9a9ea1a8b2bdbfb4aaa29f9a9a9a9a9a9a9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4cac1bbb6b5adadadadadadaeafb2b6b8bcb8ac9f928680796f6a5f584e43392f20160c02000000000000000000000000000000000000000000000008111921272c2f3032323232323232323232312e29231b13090000000000000000000003101c28343f4a54626e7b88949fabb7b9ac9f92867a6d6154473c32271b0f000000000000000000000000000000000000000000000713202c3945525d687683909da9b6bbafa3998a7d7063574a3d2f24190d010000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e939393939393938b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b121820283035394045474a4b5153555656565554514c4b4746413a373128231c150c050000000000000000000003101c28343f4a546774818d9aa8b2bdc0b5aba298928a84818081848a9297a2aab4bfcbbeb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909ca6a6a6a6a6a6a9abb0b8c2cfc1b7afa9a7a6a6a6a6a6a6abacb2bac4c6bcb4aeaca6a6a6a6a69d9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4cac2bbb7b5afafafafafafafb1b3b8b9beb6aa9d90837d746d665c53493f33271f140900000000000000000000000000000000000000000000000000080f161c2022232626262626262626262524221e1811090100000000000000000000000b17232e3847535f697683909caab4bbaea3998b7f7265584e43372b1d120700000000000000000000000000000000000000000004111d2935414c566673808c99aab4beb5ab9a8d807367564c4135291d11040000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9a9f9f9f9f9f978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070e161e25292f35393a3e40454748494949484745413f3a3936302b261f18120b03000000000000000000000006121f2c3844505c667683909da9b6c3bbafa49992867e78757474777d859298a3aebac7beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909ca9b3b3b3b3b3b6b7bbc2c6cbc9c1bab6b4b3b3b3b3b3b3b7b9bdc4c8cec6bfbab8b3b3b3b3aa9d9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4c2b8b0aaa9a2a2a2a2a2a2a2a4a7abadb3b8aca095908980786d655b50443b3025190e0200000000000000000000000000000000000000000000000000050b10131617191919191919191919191815120d060000000000000000000000000006111c2b37424d5765717e8b98a2aebab5ab9d9083776a605447392e23180c000000000000000000000000000000000000000000010d19242f3c4956636f7c8998a2aebab6aa9d908377685d5245392c2013070000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7acacaca4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c13191d24292c2d2f34383a3b3c3d3c3c3a39352f2e2d2a251e1a150c07000000000000000000000000000713202d3a4653606d7985929facb8c5b9ac9f93877d716c6867686c707c86929facb9c4beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909ca9b3b3b3b3b3b3b3b4b6bac1c9cbc6c2bbb7b6b3b3b3b3b3b3b6b8bcc3cbcac6c0b9b5b4b3aa9d9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4bbb0a69f9c95959595959596979a9ea1a9afb1a7a09d928d81776c60564d42362a1e11050000000000000000000000000000000000000000000000000000000407090a0c0c0c0c0c0c0c0c0c0c0b0906010000000000000000000000000000000e1a26313c4754606d7a85929facb8b8aca095887c6f62554b4034281c10040000000000000000000000000000000000000000000813202d3a4653606d7985929fabb8b9ac9f93867a6d6054473a2d2114080000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4b9b1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080d12181d1f2023292c2d2f2f302f2f2d2c292421201d19130e090300000000000000000000000000000815212e3b4854616e7b8798a2aebabfb5ab9b8e81746b615a5a5a616a73808c99a8b2bdbeb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909ca6a6a6a6a6a6a6a6a8aaafb7c1d0c2b8b0aba9a6a6a6a6a6a6aaabb1b9c3cbc0b6aea9a7a6a69d9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4b7aa9f948f888888888888898a8d92979ea5afb1aca49d938c7f72695e52463a2d2015090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915202c3945515d6774818e9ba8b2bcb1a79a8d8074675c5145382c1f140900000000000000000000000000000000000000000006121f2c3844505c6675828f9ca8b5bbafa4998a7d7064574a3d3025190d0100000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070c101314181c1f20222323232221201d191413110d0802000000000000000000000000000000000915222f3c4855626f7b8895aab4bfbbaea399897c6f6359504d5058616e7b8796a1acb9beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d697683909a9a9a9a9a9a9a9a9a9b9ea5afbdc7bbb0a69f9c9a9a9a9a9a9a9d9fa7b1bcc5b9aea49d9a9a9a9a9083776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b5a99c8f827c7c7c7c7c7c7c7e80858e939ea6b0b8aea59f92867b6e6154473c31261a0e02000000000000000000000000000003060809131313131313131313130b0a080500000000000000000000000000000000000000000000000000000004111d2935414b55636f7c8996a0acb9b8ab9f9285796d6053463b30251a0e02000000000000000000000000000000000000000003101c28343f4a5465727f8b98a5b2c0b5ab9a8d807467564c41362a1d110500000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406070c10131415161616151413110d08070501000000000000000000000000000000000000091623303c4956636f7c8996a2afbcb9ac9f9286796d6053464146525e697884919eabb7beb1a4978b7e7164584b3e3125180b000000000000000000101d2a3643505d6976828d8d8d8d8d8d8d8d8d8d8e939eabb5c0b7ab9f948f8d8d8d8d8d8d90959fabb8c2b5a99d928d8d8d8d8d83776a5d5044372a1d11000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e82756f6f6f6f6f6f717479818e949fabb7baaea2988c807366574e42372b1e1206000000000000000000000000040a0f13151620202020202020202020181714110c0600000000000000000000000000000000000000000000000000010d18242f3a4854606b7784919eabb5baada2978a7e7164574d42362a1e1205000000000000000000000000000000000000000004101c2834404a5466727f8c99a5b2bfb7aa9d908377685e5246392d20130700000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004060708090a090907060401000000000000000000000000000000000000000000000a1724303d4a5763707d8a96a3b0bdb7aa9e918477665c514538424d576976828f9ca9b5beb1a4978b7e7164584b3e3125180b0000000000000000000c1825323f4b5865727f80808080808080808080818e99a4afbbb6a99c8f8280808080808083909daab6c0b4a79a8d80808080807f7265584c3f3225190c000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e827568626262626364676d7882909cabb5bfb4aa9e9184786a5f53473a2e2114080000000000000000000000060e151b1f21222d2d2d2d2d2d2d2d2d2d2423211d1710080000000000000000000000000000000000000000000000000007131d2c38444f5966737f8c99a4afbbb3a99c8f8276695e52463a2d20160a000000000000000000000000000000000000000006121f2c3844515c6676828f9ca9b5c2b9ac9f93867a6d6154473a2e21140800000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6aa9d9083776a544b4034424f5b6875828e9ba8b5beb1a4978b7e7164584b3e3125180b0000000000000000000b1824313d4a56626d72737373737373737373737987939facb9b4a79a8d817473737373737e8b98aab4beafa296897c73737373726d62564a3e3125180b000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b55555556555d66707d8a99a3afbbb9ada196887b6e6255483b2f2215080000000000000000000006101820262b2e2f3939393939393939393931302d28221a1208000000000000000000000000000000000000000000000000010f1b27323d4754616e7b87939facb9b9ac9f93877b6e6154483d32271b0f01000000000000000000000000000000000000000713202d3a4653606d7985929facb8c5bbafa49a8a7d7164574a3e3025190d01000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000050a0d10101313131313131313130f0e0c0804000000000000000000000000000003070b0d0e1313131313131313131312100d08020000000000000000000000000406070a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a090704000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d50432e414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000915222e3a46515b6265676767676767676767677784909daab7b6aa9d908377676767676f7b8898a2aebab2a5988c7f7267676765625b51463a2e221609000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4949494b54606d7a86929facb9bdb2a8978b7e7164584b3e3125180b000000000000000000040e18222a32373b3c464646464646464646463e3d39332c241a10060000000000000000000000000000000000000000000000000b16202d3a46525e6976828f9ca9b3bbafa4998c7f7266594f43382c1d130700000000000000000000000000000000000000091623303c4956636f7c8998a2aebac6c0b6ac9a8d817467564c41362a1e1105000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000030a11161a1c1d2020202020202020201c1b18140f09020000000000000000000001080e13171a1a2020202020202020201f1f1c19140d06000000000000000001070c10131417171717171717171717171717171717171717171613100b0500000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000006121d29343f495156585a5a5a5a5a5a5a5a556774818e9aa7b4b9ac9f9286796d605a606c7985929fabb8b5a89b8e827568565a585651493f34291e1206000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423c3c45515d677784919daab7bfb3a6998c807366594d4033261a0d0000000000000000000a15202a343c434749535353535353535353534b49453e362c22170c0000000000000000000000000000000000000000010407070d111e2a36424d5764717e8a97a2adb9b5ab9e9184776b6054483a2f24180d01000000000000000000000000000000000004101c2934404b5566737f8c99aab4bfcac4b7aa9d918477685e5246392d201407000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000000040d151c2226292a2d2d2d2d2d2d2d2d2d282725201a130c030000000000000000020b12191f2326272d2d2d2d2d2d2d2d2d2c2b29251f181008000000000000030b12181d1f20242424242424242424242424242424242424242322201c160f08000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000010d18232d373f464a4b4d4d4d4d4d4d4d4d5865717e8b98aab4bbaea399897c6f63565b6676838f9ca9b6b7ab9e918478695e524c4a463f372d23180d01000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423535404b556a7683909da9b6c1b4a79b8e8174685b4e4135281b0e0200000000000000030f1b26323c464e535560606060606060606060575550483e33281d1105000000000000000000000000000000000001080d1113141a1a1a25303b4653606d7985929eabb8b9aca096897c6f63554b4035291d1104000000000000000000000000000000000006131f2c3845515c6776838f9ca9b6c2d0c5b8aca095877a6e6154473b2e211409000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000000030d161f272d3236373939393939393939393534312c251e150c02000000000000010b141d242b303334393939393939393939393835302a221a100600000000030d151d24292c2d31313131313131313131313131313131313131302f2c27211911080000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000006111b252d343a3d3f404040404040404855626f7b8898a2aebab5ab988c7f726559546673808d99a6b3b9ada196877a6e6154473b3a342d251b110700000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352f43505c6976838f9ca9b6c1b5a89b8e8275685b4f4235281c0f020000000000000006131f2b37434e585f626c6c6c6c6c6c6c6c6c6c64615a5045392d21140800000000000000000000000000000000040c13191d2021262626262c3845515c6674808d9aa7b1bcb2a89b8e8174675d5145392c20140900000000000000000000000000000000000714202d3a4753606d7986929facb9c5d2c8bcb1a7978a7e7164574b3e30251a0e020000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000000a151f2831383e424346464646464646464642403d372f271e130900000000000008121d262f363c3f414646464646464646464644413b342c22180d020000010b151f272f35393a3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3c38332b23190f0500000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000009131b23292e3132343434343434394653606c7985929facb8b5a89b8e827568565764707d8a97a8b2bdb2a8978a7d7064574a3d2e29231b13090000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42353643505c6976838f9ca9b6c2b5a89c8f8275695c4f4236291c0f03000000000000000815212e3b47535f6a7679797979797979797979716c6155493d3023170a000000000000000000000000000000040d161e24292c2d333333333334404b54626f7c8895a0acb8b8ac9f92857a6d6053473b31261a0e00000000000000000000000000000000000a1623303d495663707d8998a3aebac7d3cec1b4a79a8e817467574d42362a1e12050000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000005111c27313a434a4e505353535353535353534f4d4841392f251a0f0400000000030e19242f3840474c4d53535353535353535352514d463e342a1f1408000007121d2731394045474a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a48443d352b21160b00000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000010911181d22242527272727272b3844505b6676838f9ca9b6b7ab9e918478685e54616e7a8796a1acb9b3a6998d807366544a3f34281c1009010000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42353643505c6976838f9ca9b6c2b5a89c8f8275695c4f4236291c0f03000000000000000916222f3c4955626f7c868686868686868686867e7164574b3e3124180b0000000000000000000000000000010c1620282f35393a4040404040404047535f6a7783909daab4baaea2988b7e7164574d42362a1c110600000000000000000000000000000004111d2935404b556673808c99aab4bfcbd7d1c4b7aa9e918477695e52463a2d2014070000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000a16222d38434d555b5d6060606060606060605b59534b41372c2014080000000007131f2b36404a52585a6060606060606060605f5d5850463b3025190d00000c18242f39434b51535757575757575757575757575757575757575756544f473d33271c1004000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000060d121518181a1a1a1a1c28333f4a546673808d99a6b3b9ada196877a6e61545e687884919eabb7b6a99c8f8376665c5044382b1f1206000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423534404b546a7683909da9b6c2b5a89c8f8275695c4f4236291c0f03000000000000000916222f3c4955626f7c8893939393939393938a7e7164574b3e3124180b000000000000000000000000000008131e28323a4145474d4d4d4d4d4d4d4d4e5865727f8b98a3aebab4aa9c908376695f5346382d22170b0000000000000000000000000000000613202c3945515d677683909da9b6c3d1dcd2c5b8aca096877b6e6154483b2e2115090000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000d1a26323e4a555f666a6c6c6c6c6c6c6c6c6c68655d53483d3125180c000000000b1723303c47525c64676c6c6c6c6c6c6c6c6c6c6962584d4135291c100004101d2935404b555d60646464646464646464646464646464646464646360594f44382c201307000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000106090b0c0d0d0d0b17222d3d4a5764707d8a97a8b2bdb2a8978a7d706457566875818e9ba8b5b8ac9f9285796d6053463a2d201307000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42333845515c667784919daab7c2b5a89b8f8275685c4f4235291c0f02000000000000000916222f3c4955626f7c88959f9f9f9f9f9f978a7e7164574b3e3124180b00000000000000000000000000010d19242f3a444c525459595959595959595959616d7a86929facb9b7ab9f94887b6e61544a3f33281c0f0300000000000000000000000000000714202d3a4753606d7a86929facb9c5d2dfd4c8bdb2a8978a7e7164574b3e31251a0e0200000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101c2936424e5b667176797979797979797979756f65594d4034271b0e000000000d1a26333f4c58646e747979797979797979797974695d5144382b1f120006131f2c3945515d676d70707070707070707070707070707070707070706b6054483c2f221609000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000101000614212e3b4754616e7a8796a1acb9b3a6998d807366545965727f8c98abb4baaea298887c6f6255483c2f221508000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f433f444653606d7986929facb9c1b4a89b8e8175685b4e4235281b0f02000000000000000916222f3c4955626f7c8895a2acacacaca4978a7e7164574b3e3124180b0000000000000000000000000004111d2935414c565d6066666666666666666666666875828e9babb5bbb0a6998c8073665b5044382b1f130800000000000000000000000000000a1724303d4a5763707d8a99a3afbbc7d3d2d3cec1b4a79b8e817468574d42362a1e120500000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a76838686868686868686868175685b4f4235281c0f0c0c0c0c0e1a2734414d5a67748086868686868686868686796c5f5246392c1f13000714202d3a4753606d797d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7063564a3d3023170a000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000714202d3946525e687884919eabb7b6a99c8f8376665c56626f7c8999a3aebab4aa988b7e7165584b3e2f24190d010000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4f4a50535a63707d8999a3afbbc0b4a79a8d8174675a4e4134271b0e01000000000000000916222f3c4955626f7c8895a2afb9b9b1a4978a7e7164574b3e3124180b000000000000000000000000000713202c3945525d686d737373737373737373737373737d8999a4afbbb7ab9e9184786c6053463a3024190d0100000000000000000000000004111d2935414c566773808d9aabb5c0cac6c5c6cac4b7ab9e918478695e53463a2d21140700000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a768390939393939393938e8275685b4f4235281c1919191919191a2734414d5a6774808d939393939393939286796c5f5246392c1f13000815212e3b4854616e7b878a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a84776b5e5144382b1e11000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000005111e2a36414c566875828e9ba8b5b8ac9f9285796d6053606d7986929facb9b4a79b8e817468564c4135291d11040000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685c5c5c545b60626c75828f9babb5c0bfb2a5998c7f7266594c3f3326190c00000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000714212d3a4754606d7a808080808080808080808080808087939facb9b9ada196897d7063564c4135291d11040000000000000000000000000713202c3945525d687783909daab6c3bfbab8babfc6b9aca196877b6e6154483b2e21150900000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909d9f9f9f9f9f9b8e8275685b4f42352823262626262626242734414d5a6774808d9a9f9f9f9f9f9f9285796c5f5246392c1f13000815212e3b4854616e7b8794979797979797979797979797979797979184776b5e5144382b1e11000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000020e1925303f4c5965727f8c98abb5baaea298887c6f62555c677683909da9b6b7aa9d918477685d5245392c2013060000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e82756969696969666c6f747e8a939eaabdc7bcb1a7978a7d7064574a3d3124170a00000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000815212e3b4854616e7b878c8c8c8c8c8c8c8c8c8c8c8c8d9399a4afbbbdb2a89b8e8175685d5245392c20150a0000000000000000000000000714212d3a4754606d7a86939facb9bcb4aeacaeb4bcbdb2a8978b7e7164584b3e31261a0e02000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9acacaca89b8e8275685b4f42352f30323232323232302f34414d5a6774808d9aa7acacacac9f9285796c5f5246392c1f13000815212e3b4854616e7b8794a1a3a3a3a3a3a3a3a3a3a3a3a3a3a39e9184776b5e5144382b1e11000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000081623303c4956636f7c8999a3aebbb4aa988b7e726558556774808d9aa7b3b9ac9f93867a6d6054473a2d2114070000000e1b2734414e5a6774818d9aa7b4bfb8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8bfb4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c1b5a89b8e8176767676767677797c8187929fa6b0bbc5b8aca095877b6e6154483b2e21150800000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000815212e3b4854616e7b87949999999999999999999999999fa4abb5c0c4b8ac9f92867a6d6054473c31261b0f0000000000000000000000000a1724313d4a5764707d8a99a4afbbb4aaa29fa2aab4bfb4a79b8e817468574d42372b1e1206000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6b9b5a89b8e8275685b4f42383c3d3f3f3f3f3f3f3d3c38414d5a6774808d9aa7b3b9b8ac9f9285796c5f5246392c1f13000815212e3b4854616e7b8794a1aeb0b0b0b0b0b0b0b0b0b0b0b0aa9e9184776b5e5144382b1e11000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000714202d3a4753606d7986929facb9b4a79b8e817468565764717e8a97a9b3bbafa49a897d7063564a3d302317090000000e1b2734414e5a6774818d9aa7b2b2b2ab9f9285786c5f5245392c2c3945525f6c7885929fabb2b2b2a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4b8ab9e91858282828282838485888e9299a3afb8c1bfb4aa9d908377695e52463a2d20140700000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000815212e3b4854616e7b8794a1a6a6a6a6a6a6a6a6a6a6a6acafb5bdc7c7baaea3988b7e7265584e43372b1c12070000000000000000000005111e2a36414c566774808d9aabb5baaea2989298a2aebab7ab9e918478695f53473a2d211408000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4f4244484a4c4c4c4c4c4c4a4844414d5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000815212e3b4854616e7b8794a1a7a7a7a7a7a7a7a7a7a7a7a7a7a79e9184776b5e5144382b1e11000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000006131f2c3845515c677783909daab6b7aa9d918477685d55616e7b8897a1adb9b6ac998c7f7366594c4031261a0e0200000e1b2734414e5a6774818d9aa5a5a5a5a59f9285786c5f5245392c2c3945525f6c7885929fa5a5a5a5a59a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4b9ada197918f8f8f8f8f909092989a9fa3abb5c0c4baaea2988c7f7266574d42362a1e120500000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000815212e3b4854616e7b8794a1aeb3b3b3b3b3b3b3b3b3b3b9bbc0bfbfbfbfb4aa9d9083776a5f5347392e23180c000000000000000000000713202d3946525e687784909daab7b8ac9f9285929faab4b9ada196887b6e6155483b2e221509000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4f474f545659595959595957554f474d5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000815212e3b4854616e7b87949a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9184776b5e5144382b1e11000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000004101c2934404b556774818d9aa7b4b9ac9f93867a6d60545f697885929eabb8b5a89c8f827569574d42362a1e120500000e1b2734414e5a6774818d989898989898989285786c5f5245392c2c3945525f6c788592989898989898988d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4beb3a9a19e9c9c9c9c9c9c9d9fa2aaacafb5bdc3bab1a79f92867a6d6054473b30251a0e0200000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000815212e3b4854616e7b8794a1aeb2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2ab9f95887c6f62544a4034281c10040000000000000000000714212e3a4754616d7a86939facb9b4aa9a8d818d98a2aebab2a8988b7e7165584b3e31261a0f020000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4f4f5960636565656565656361594f4d5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000815212e3b4854616e7b878d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d84776b5e5144382b1e11000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000c18232f3e4b5864717e8b97a9b3bbafa49a897d706356576975828f9ca8b5b8ab9e928578695f53463a2d21140700000e1b2734414e5a6774808c8c8c8c8c8c8c8c8c85786c5f5245392c2c3945525f6c78858c8c8c8c8c8c8c8c8c8074675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4c4bbb3adaba9a9a9a9a9a9aaabaeb4b9bbc0c1b9b1a89f958c7f72685d524539291f14090000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000815212e3b4854616e7b8794a1a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a79a8d8073665c5144382c1f12060000000000000000000b1724313e4a5764717d8a9aa4afbaaea398897c85929fabb8b4a89b8e817568584e43372b1f12060000000000000000000000000000000000000000020d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4f54606b70727272727272706b61554d5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000714212e3a4754616d7a81818181818181818181818181818181818181807366594d4033261a0d000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000715222f3b4855626e7b8897a2adb9b6ac998c7f7366595966737f8c99acb6b9ada197887b6e6155483b2e22150700000a1723303d4a5663707d7f7f7f7f7f7f7f7f7f7f7265584c3f322525323f4c5865727f7f7f7f7f7f7f7f7f7f7d7063564a3d3023170a00121e2b3845515e6b7884919eabb7c4cdc4beb9b8b5b5b5b5b5b6b7b8babec5c2bbb7afa7a0969083786d60564c413529170d020000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000815212e3b4854616e7b879499999999999999999999999999999999999999999999999285796d6053463a2d201307000000000000000005111e2a36424d576774818d9aacb6b8ac9f928678838f9ca9b6b8ab9e9185786a5f53473a2e21140600000000000000000000000000000000000002090e121a2734404d5a6773808d9aa6b3beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4d5763707d7f7f7f7f7f7f7d7063584e5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000713202d3946525e686d74747474747474747474747474747474747474736e63574b3f3225190c000a1724313d4a5764707d8a97a3b0bdb6a99d9083766a5d504330414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000814212e3a47535f697885929eabafafa89c8f827569575663707d899aa4afafb3a9978a7e7164574b3e2e23180c00000916222f3c4854606b70727272727272727272726d62564a3e312424313e4a56626d72727272727272727272706b6054483c2f22160900121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbebebdbfbab9b6b0aba59e9591847a6e665c50443a30241905000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000815212e3b4854616e7b878c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8a7d7064574a3d3124170a00000000000000000714202d3a46525e697784919eaab7b6a99c908376808d99a6b3b9ada197887b6e6255483b2d22170b0000000000000000000000000000000000050d141a1e202534404d5a6773808d9aa6b3beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b535e6977838c8c8c8c8c8c84786a5f545a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f130005111d2935414c565e616767676767676767676767676767676767676766635c52473b2f23160a000a1724313d4a5764707d8a97a3b0bdb7aa9d9084776a564d42363f4a546875828f9ba8b5beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000006121e2b37424d576976828f9ca2a2a2a29e928578695f54606d7a86939fa2a2a2a29a8d807467544b4034281c1004000713202c38444f59606365656565656565656565625b51463a2e22222e3a46515b62656565656565656565656360594f44382c20130700121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b1b1b4aeaca9a69f9c938e837b6e685e544a3f32281e1308000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000714212d3a4754606d7a7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7d7063574a3d3024170a00000000000000000814212e3b4754616e7b8796a0acb8b3a69a8d80737d8a97a8b2bdb3a9988b7e726553493f33271b0f03000000000000000000000000000000050f171f252a2d3036414d5a6774808d9aa7b3bdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b54616e7b87959898989896887c6f62555a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300010d1925303a444c52545a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5957524940352a1f1307000a1723303d4a5663707d8996a3b0bcb8ab9e928578695e52463944505b667683909da9b6beb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000020e1a2631404c5966737f8c95959595959597887b6e61555d68778491959595959595908376665c5145382c1f13060004101c27333d474f5456595959595959595959585651493f34291e1e29343f4951565859595959595959595956544f473d33271c100400121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a4a4aba39f9c99948f8981796e695f564d42382e20160c02000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000613202c3945525d686d737373737373737373737373737373737373737373737373737373706b6155483c2f23160900000000000000000b1825313e4b5864717e8b97a8b2bdb3a9978a7d717a8796a1adb9b5a89b8e8275655b5044372b1f12050000000000000000000000000000020d17212930363a3b42464d576875818e9ba8b4bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b5665727f8b98a7a5a5a8998c807366575a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000008131e28323a4146474e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4d4b4740372e24190e02000916232f3c4956626f7c8995a2afbcb9ada197877b6e61544b444653606c7985929fabb8beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000091723303d4a5663707d8989898989898989897e71645756687481898989898989898986796d6053463a2d20130700000b16212b353d44484a4c4c4c4c4c4c4c4c4c4c4a463f372d231818232d373f464a4c4c4c4c4c4c4c4c4c4c4a48443d352b21160b0000121e2b3845515e6b7884919898989898989898989898989898989897969992908c88827d746d675f574d443b30261c0e0400000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000004111d2935414c565d606666666666666666666666666666666666666666666666666666666361594f44382c2014070000000000000005121e2a36424d576874818e9ba7b4b9ada197877b6e7884919eabb8b8ab9e9285796c605346392d201306000000000000000000000000000009141f29333b4246484d52545f697784909daab7bdb2a895887b6f6255483c2f221509000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b5d6876838f9ca9b2b2aa9d908377695e5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000020c1620283035393a41414141414141414141414141414141414141403f3b352e251c120700000815222f3b4855626e7b8895a9b2bdbeb3a9988b7e72665c5350535b63707d8998a2aebabeb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000714202d3a4753606d797c7c7c7c7c7c7c7c7c7b6e615454616e7b7c7c7c7c7c7c7c7c7c796d6053463a2d2013070000050f19232b33383c3d3f3f3f3f3f3f3f3f3f3f3e3a342d251b11111b252d343a3e3f3f3f3f3f3f3f3f3f3f3d3c38332b23190f050000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8b8b8a898886837f7b766f6b605d554d453b32291e150a0000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000010d19242f3a434c525459595959595959595959595959595959595959595959595959595957554f473e33281c1004000000000000000714212d3a46535f697884919eabb7b8ab9e9185786975828f9ba8b5b9ada197887c6f6255483c2d22170b00000000000000000000000000020e1a25303b454d5254575e61666e7b8895a0acb8b9aca196877a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0400000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b616d7a86929facb9b8aca095877b6e615a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000040e161e25292d2e3434343434343434343434343434343434343433322f2a241c130a0000000714212e3a4754616d7a8796a1adb9c4b7aa9d9184796d65605c5f626d76828f9caab4bebeb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000006131f2c3845515c676d6f6f6f6f6f6f6f6f6f6e695e52525e696e6f6f6f6f6f6f6f6f6f6d675c5145382c1f130600000008111921272c2f3032323232323232323232312e29231b130909131b23292e3132323232323232323232302f2c27211911080000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7e7d7b7976736e6a636059514b433b332a20170c030000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000008131e28313a4145474c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a48443e352c21160b00000000000000000815222e3b4855616e7b8896a1acb9b5a89b8f827568727f8c99abb5beb3a9988b7f7265544a3f33281c0f0300000000000000000000000005121e2a36424d575e616b696e7178828f9ca7b1bcb7ab9e918478675d5145392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e31251814100b050000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685564717e8b99a3afbbbcb1a7988b7f7265566774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000040c13191d2021272727272727272727272727272727272727272625231f19120a010000000713202d3946525e687885919eabb8c4b8aca0968e8177706d666a6f757f8c949fabbcc5beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000004101c2934404b555c60626262626262626262615e574d4d575e61626262626262626262605c554b4034281c100400000000080f161c2022232626262626262626262524221e18110901010911181e2224252626262626262626262322201c160f08000000000b1724313d4a56626c71727272727272727272727272727272727171706e6d6666625f58544f45413a312a21180e05000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000010c161f282f35393a4040404040404040404040404040404040404040404040404040403d3c38332c231a100500000000000000000b1825323e4b5865717e8b98a8b2bdb5ab998c7f7266707c8999a4afbbb5a89b8f8275665b5044382b1f12060000000000000000000000000714202d3a46525e696e78797b7e838f949fabb9bfb4aa9b8e817568554b4135291d110400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009101b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e312523201c16100800000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685c6775828f9babb5c0c2b6a99c8f8276685d6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000002080d1113141b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1a1916130e07000000000005111d2a36414c566975828f9cacb6c0bdb2a89d938e827c7978797c818c919ca6b0bbcebeb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000000c18232f39434b515356565656565656565654524d45454d525456565656565656565653514b43392e23180c000000000000050b10131617191919191919191919191815120d0600000000060d12151819191919191919191919171613100b0500000000000915212e3a45505a62656565656565656565656565656565656565646361605c5455534e48443d352f281f180f0600000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000040d161e24292c2d333333333333333333333333333333333333333333333333333333302f2c28211a1108000000000000000006121f2b37434e586875818e9ba8b4bbafa499897c70636d7a86939facb9b8ab9f9285796c605346392d2013060000000000000000000000000815212e3b4854616e7b8585878b90959fa6b0bbbaaea2988b7e7165584b3e2f24180d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121a222834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e32302f2c27211a1108000000101d2a3743505d6a7683909da9b6c1b5a89b8e827568606d7985929facb8c5c5b9ac9f92867a6d606774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000000000010507070e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0d0c0a0702000000000000010d192530404c5966737f8c9aa4afbbc3baafa59d948f89868585888e939ca3adb8c2cabeb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000007121d2731394045474949494949494949494746423b3b4246474949494949494949494645403930271d120700000000000000000407090a0c0c0c0c0c0c0c0c0c0c0b0906010000000000000106090b0c0c0c0c0c0c0c0c0c0c0a0907040000000000000005111d29343f48505658595959595959595959595959595959585857565553504a4847433c383229241d160d060000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000040c13191d20212626262626262626262626262626262626262626262626262626262423201c1610080000000000000000000814212e3a47535f6a7885919eabb8b9ac9f93867a6d60677784909daab7baada297887c6f6255493c2e23170c0000000000000000000000000815212e3b4854616e7b879298979da0a7b0b8bdb3a99f92867a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006101a242c3439414e5b6774818e9aa7b4beb1a4978b7e7164584b3f3f3d3c38332c231a10050000101d2a3743505d6a7683909da9b6c1b5a89b8e82756863707d8a98a2aebac6c7bbafa3998a7e71646774808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b87939facb9c0c0b7afa69f9c99929192989b9ea5a9abb0b8c2beb1a4978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000000010b151f272f34383a3c3c3c3c3c3c3c3c3c3b3a363030363a3b3c3c3c3c3c3c3c3c3c3a38342e271e150b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4b4b4a4846443f3b3a37312c272118130c04000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000001080d111314191919191919191919191919191919191919191919191919191919171614100b05000000000000000000000815222f3b4855626e7b8897a1adb9b7aa9d908477675d6774818e9aa7b4beb3a9988c7f7265544a3f34281c100300000000000000000000000815212e3b4854616e7b8794a2aaaaacb1b9bdb5aba2978d8174685d5245392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c17222c363e45494e5b6774818e9aa7b4beb1a4978b7e7164584c4c4c4a48443d352c21160b0000101d2a3743505d6a7683909da9b6c1b5a89b8e8275686674818e9aaab4bfc7c5c0b5ab9b8e8275676774808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535f6976828f9ca5afb9c2c0b8b0ababa39f9e9fa2aaa69f9c9fa6b0bbbeb1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000030d151d23292c2d2f2f2f2f2f2f2f2f2f2e2d2a25252a2d2e2f2f2f2f2f2f2f2f2f2d2c28231d150c03000000000000000003080b0d0e1313131313131313130d0c0a0602000000030608091313131313131313131313070705010000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3e3e3d3b3a38342e2e2b26201b160d070100000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000010406070d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0a0907040000000000000000000000030f1b27333f495365727e8b98a9b2beb4a79a8e8174675565717e8b98aab4bfb5a89c8f8275665c5044382c1f120600000000000000000000000815212e3b4854616e7b8794a1b4b7b8bcb9b3aba49992857a6d61564c4135291d11040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d28343e485055575b6774818e9aa7b4beb1a4978b7e71645858585856554f473d33271c100400101d2a3743505d6a7683909da9b6c1b5a89b8e8275686c7985929eabb8c0bbb9bbb8ac9f9285796d6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d5763707d89929da7b0b9bec2bbb7b4aeacabacaea79f948f949fabb7beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000000000030b12181c1f2023232323232323232321201e1a1a1e2021232323232323232323201f1c18120b030000000000000001080f14181a1b202020202020202020191916120d07040a0f121515202020202020202020201f1413110d080200000000000000000009121b22292e3132323232323232323232323232323232323231302e2d2c2823211f1a150f0b04000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6575828e9ba8b5bfb4aa988b7e716558626f7c8898a2aebab8ab9f9285796d6053463a2d20130700000000000000000000000815212e3b4854616e7b8794a1aeb8b6b3ada9a19993877e70685e52433a2f24190d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815212d3945505a6164656774818e9aa7b4beb1a4978b7e7165656565656361594f44382c20140700101d2a3743505d6a7683909da9b6c1b5a89b8e8275686f7c8997a1adb9b5afacafb5aea2988a7d706774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a26313b4854606b74818e959ea6adb2b7b9bbbbb9b7b2ada69e958f838f9ca9b2b2b1a4978b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000001070c1013141616161616161616161414110e0e1114141616161616161616161313100c070000000000000000020b131a202427272d2d2d2d2d2d2d2d2d2625231e19120e151b1f21222d2d2d2d2d2d2d2d2d2d2c21201d19130c050000000000000000000911181d2124252626262626262626262626262626262525242322201f1c1714120f09030000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000030506080b0e0f1011100f0d0a07060401000000000000000000000000000000000000000000000000000000000613202d394653606c7985929eabb8baaea298887b6f6255606d7985929facb8baaea298897c6f6256493c2e23180c00000000000000000000000815212e3b4854616e7b8794a1acaba9a9a19e9792877f726c61564c4131281e130800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724303d4955616c71727274818e9aa7b4beb1a4978b7e727272727272706b6155483c2f23160900101d2a3743505d6a7683909da9b6c1b5a89b8e82756873808d9aa9b3b2aba39fa3abb4aa9a8d81746574808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f2c38444f59606d79838f949ea1a9abacaeafacaba9a19e948f837b8894a1a6a6a6a4978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000000000000000000406070909090909090909090807050202050708090909090909090909070604000000000000000000010b141d252b30333439393939393939393933322f2a231c1820262b2e2f39393939393939393939392e2d2a251e160e05000000000000000000060c1115171819191919191919191919191919191919181817151312100c06060200000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000060b0f121315181b1c1d1d1d1c1a171413110d080300000000000000000000000000000000000000000000000000000915222f3c4855626f7c8897a1adb9b8ac9f9285796d60535c667683909ca9b6beb4aa998c7f7266544b4034281c1004000000000000000000000815212e3b4854616e7b8794a49f9e9c9997918c857d726d625a50443a301f160c0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313e4b5764717e7f7f7f82909da9b6c1b4a89b8e817f7f7f7f7f7f7d7063564a3d3023170a00101d2a3743505d6a7683909da9b6c1b5a89b8e82756a7784919eaab2a8a0999299a3afab9e9184786c74808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c27333d45515d676d79828b91979b9e9fa3a49f9e9b96918b827a7a87949999999999978b7e7164584b3e3125180b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131d262f363c4041464646464646464646403e3b352e25222a31373a3c46464646464646464646463a3936302820160c020000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0b0b0a080706030000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000003090f11171b1f20222527292a2a2928262421201d19130f0b06000000000000000000000000000000000000000000000003101c28343f4a5465727f8c98a9b3beb6a99c8f8376665c50546773808d9aa6b3c0b5a99c8f8276665c5145382c1f1306000000000000000000000815212e3b4854616e7b87949a93918f8d89858079706b625b51483e32291e0d04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a77848b8b8b90959fabb7c2b6aa9e938e8b8b8b8b8b8b8175685b4f4235281c0f00101d2a3743505d6a7683909da9b6c1b5a89b8e82756e7b8896a0acaca0969186929facada197897c6f74808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b16212935414b555d676d787e848a8e9192999a93918e8a847f756d7a878c8c8c8c8c8c8c8b7e7164584b3e3125180b000000000000050a0d1010131313131313131313100f0d0a0500000000000002070a0c0d1313131313131313130e0d0b080300000000000000000000000000000000000000000000030f1a252f3841484c4e5353535353535353534c4b4640372e2a343c43474853535353535353535353524746413a32281e1308000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000002080e151a1b22272b2d2f3234353637363533312d2c29241f1c17110a0200000000000000000000000000000000000000000006121f2b3844505c6675828f9ca8b5c0b3a6998d807366544a5764717d8a97a9b3beb8ac9f9285796d6053463a2d201307000000000000000000000815212e3b4854616e7b878887868583807d79736d67615951493f362c20170c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a77849198989d9fa7b1bcc6baafa59e9b98989898988e8275685b4f4235281c0f00101d2a3743505d6a7683909da9b6c1b5a89b8e8275727f8c99a8b2aa9e9184828f9bacb2a9998d807374808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050d18242f3a434b555d666d71797e81848687878684817e79726d6d797f7f7f7f7f7f7f7f7f7c6f6255483c2f22150900000000030a11161a1c1d2020202020202020201d1c1916100a03000000070e1317191a2020202020202020201b1a18140f080100000000000000000000000000000000000000000814202b36414a53585a606060606060606060595751494035313c464e5355606060606060606060605f54524c443a3025190d01000000000000000004061313131313131313131313131313131313131313131313131313131313131313131311100e0a0600000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000050d141920262b2d3337393b3e414243444342403d3a39352f2b28221c140b0802000000000000000000000000000000000000000713202d3a4653606d7985929fabb8bdb2a8978a7d7064574a54616e7b8797a1adb9baaea298897c6f6356493c2f23180c000000000000000000000713202d3a4653606d787c7b7b79787673706d66605d554f473f372d241a0e0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a7784919da5a9abb1b9c2cbc1b7afaaa8a5a5a5a59b8e8275685b4f4235281c0f00101d2a3743505d6a7683909da9b6c1b5a89b8e82757683909da9b4aa9a8d807e8b9aa4afaa9d91847774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007131d28313a434b545c60676d717478797a7a797874716d6662676d7373737373737373736f6a5f53473a2e211508000000040d151c2226292a2d2d2d2d2d2d2d2d2d292926211c150d04010a12191f2326262d2d2d2d2d2d2d2d2d272724201a130b02000000000000000000000000000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6c66635b51463b37434e585f626c6c6c6c6c6c6c6c6c6c6c615e564c41362a1d1105000000000001070c1013202020202020202020202020202020202020202020202020202020202020202020201e1d1a16110b040000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000080e171e252a3137383f4446484b4e4f5050504f4d4a4745413a38332d261d19140d050000000000000000000000000000000000000916232f3c4956626f7c8997a2adbab9ada196877a6e615447535e697885919eabb8bfb4aa998c7f7366554b4034291c100400000000000000000006131f2c3845515c666d6f6e6e6d66696663605c54514b433e352d251b11080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a7784919daab6b7bcc2cbd3c9c1bab6b4b2b2b2a89b8e8275685b4f4235281c0f00101d2a3743505d6a7683909da9b6c1b5a89b8e82757b87939facaea298897d7b87939facaca095887b74808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c161f283139424a50555d6064686b686d6e6d666864605c555d60666666666666666666625f584e43372b1f12060000030d161f272d3236373939393939393939393635322d261f160d0a131c242a2f32333939393939393939393433302b251d140b010000000000000000000000000000000000000d1a2733404c58646e74797979797979797979736d63574b3e3a47535f6a7679797979797979797979796d685e5246392d20130700000000030b12181c1f2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2a2927221c150d0500000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000020a121a202930363c434749505355585a5c5d5d5c5b595754524c46443f382f2a251f170e060000000000000000000000000000000004101c2834404a5466727f8c99a9b3beb7ab9e918478685e52464d576875828f9ba8b5c2b6a99c8f8376675c5145382c1f130600000000000000000004101c2834404b545c60626261605c545a5653504a45413a312c231b1309000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a7784919daab6b8bcc3cbd3c9c1bbb6b5b2b2b2a89b8e8275685b4f4235281c0f00101d2a3743505d6a7683909da9b6c1b5a89b8e82757e8b9aa4afac9f9285797783909daab1a7988c7f74808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d161f2830383f444b5153575b565d6061605c545753514b515359595959595959595955534e463c31261b0f0300000a151f2831383e424346464646464646464643423e3831281f150c1c262e353b3f4046464646464646464641403c362f261d13080000000000000000000000000000000000000e1b2734414e5a6774808686868686868686867f7366594c40404b55626f7c86868686868686868686867a6d6154473a2e211407000000030d151d23292c393939393939393939393939393939393939393939393939393939393939393939393736332e271f170d04000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000020b141c242c323b41464e53535b6062656768696a69686664605d5653504a423e3630292018100600000000000000000000000000000006121f2c3844515c6676828f9ca9b5c1b5a89b8e827568564d414c5966727f8c99acb6c0b9ac9f9286796d6053473a2d201407000000000000000000000c18232e39424b515355555453514b4d4a46443f38352f281f1a110901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a7784919da6aaabb1b9c3ccc1b7afaaa8a6a6a6a69b8e8275685b4f4235281c0f00101d2a3743505d6a7683909da9b6c1b5a89b8e8276828f9cacb6ac9b8f827573808c99a9b3a99c908376808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d161e262e34394045474a4e4c52545453504a4a46444045474c4c4c4c4c4c4c4c4c4847433c342a20150a000005111c27313a434a4e50535353535353535353504e49423a31261c151e2e3840474b4d5353535353535353534e4c4841382f251a0f0300000000000000000000000000000000000e1b2734414e5a6774818d939393939393938c7f7366594c4045515c6774808d93939393939393938e8174685e5246392d2013070000010b151f272f34384646464646464646464646464646464646464646464646464646464646464646464644423f3931291f150b000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000010b141d262e363e444c52585f62656c6e7174757677767573706d6864605b545046413b322a2218100600000000000000000000000000000713202d3a4653606d7985929facb8c0b5ab988c7f7265594c3f495663707d899aa4afbbbaaea398897c706356493d2f24180d0100000000000000000007121d273039404546494848464540403d3a38342e29241d160d080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a77849199999d9fa7b1bcc6bbafa59e9b99999999998e8275685b4f4235281c0f00101d2a3743505d6a7683909da9b6c1b5a89b8e827986929facafa49a8b7e716f7c8997a1adac9f93867a808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c141c23282f35393a3e414145474746443f3e3a3835383a4040404040404040403c3a37312a22180e0400000a16222d38434d555b5d6060606060606060605c5a544c42382d211c2630404a5257596060606060606060605a58534a41362b20140800000000000000000000000000000000000e1b2734414e5a6774818d9a9f9f9f9f9f998c7f7366594c404753606d7985929f9f9f9f9f9f9f94887c6f62564c41362a1d1105000007121d273139404553535353535353535353535353535353535353535353535353535353535353535353514f4a433b31271c11060000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000a131d262f38404850565e616a6e74787b7e818283838382807d7a76716c66615a524d443c342a22180e0500000000000000000000000000091623303c4956636f7c8998a2aebabbafa399897c6f6356493c4754606d7a86939facb9bfb4aa998c807366554b4035291d1004000000000000000000000b151e272e34383a3c3b3b3a38342e302d2b28231c18130c04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a77848c8c8c90959fabb8c3b6aa9e938f8c8c8c8c8c8c8275685b4f4235281c0f00101d2a3743505d6a7683909da9b6c1b5a89b8e817e8a99a3aeac9f93877b6e6c7885919eabafa4998b7e808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a11171d24292c2d312f35393a3b3a38342e2d2c292c2d3333333333333333332f2e2b26201810060000000d1a26323e4a555f666a6c6c6c6c6c6c6c6c6c69665e54493e3226232e3842525c63666c6c6c6c6c6c6c6c6c67645c53483c3024180b00000000000000000000000000000000000e1b2734414e5a6774818d9aa7acacaca6998c7f7366594c424d5764717e8a97a2adacacb2a89c8f82766a5f53443a3025190d0100000c18232f39434b515f6060606060606060606060606060606060606060606060606060606060606060605d5b554d43392e22160a0000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000007101c252f38414a525a61686e757b8085888b8d8f90908f8e8c8a86827d78716c615e564e463c342a20160c02000000000000000000000004101c2934404b5566737f8c99aab4bfb9ac9f92867a6d6053473a45515d677784919daab7c3b6a99c908376675d5145392c20130600000000000000000000030c151d23282c2d2f2f2e2d2c282323201f1c17110d0701000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e7f7f7f83909daab6c2b5a89b8f817f7f7f7f7f7f7d7164574a3e3124170b00101d2a3743505d6a7683909da9b6c1b5a89b8e81818e9babb4aa9d908377696574818e9babb4ab9b8f82808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b12181d20202424292c2d2e2d2c2823201f1d1f2026262626262626262622211f1b150e0600000000101c2936424e5b6671767979797979797979797670665a4e42352928343f4a54636e73797979797979797979746e64584c4033271a0d00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4b9b2a6998c7f7366594c47535f697683909ca9b3beb8aca0968a7d7063584e4332281e1308000004101c2934404b555c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6a675f554a3f33271a0e0100000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000020b19222d37414a535c636c717a81878d9297989a9b9c9d9c9b9999928f8a847e756e685f584e463c32281e1308000000000000000000000006131f2c3845515c6776838f9ca9b6c2b6aa9d908377675d514538414c556874818e9ba7b4c1b9ac9f92867a6d6053473a2d2014080000000000000000000000030b12181c1f20222221201f1c18171312100b06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313d4a56626d72737374818d9aa7b4beb1a4988b7e737373737373716c6155493c3023160a00101d2a3743505d6a7683909da9b6c2b5a89b8f8185929fabb3a9998c80736664717d8a99a3aeac9f9286818e9aa7b4c1b8ac9f9285796c5f5246392c1f130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d10131417191d202121201f1c1713121013141919191919191919191515120f0a040000000000101d2a3743505d6a76838686868686868686868276695c504336292c3844505c6673808686868686868686868174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4a54626e7b88949fabbbbeb3a99d9184786c6053463c3120160c02000006131f2c3845515c67767979797979797979797979797979797979797979797979797979797979797979797771675b4f4236291d100300000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000a141d2b343f49535c646e737e858e93999ea1a9a7a8a9aaa9a8aba39f9c96918a827a6f6a5f584e443a3025190d05000000000000000000000714202d3a4753606d7986929facb9bfb4a79a8d817467554b40353f4b5865727e8b98aab4bfbbaea399897d7063564a3d2f24190d01000000000000000000000000070c1013131615151313100c070706030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222e3a45515b6265666774808d9aa7b3beb2a5988b7f72666666666664615a5044392d21140800101d2a3743505d6a7683909da9b6c3b8ab9e92859297a2adada197897c6f62606d7a86929facaea2989184919eaab7c4b8ac9f9285796c5f5246392c1f1300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040607080d111314141312100c06060406070d0d0d0d0d0d0d0d0d0908060300000000000000101d2a3743505d6a768390939393939393938f8376695c504336292d3a4653606d798491939393939393938d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c515c6673808d9aa6b0bbbaada2978b7e72655b5044372b1f12050000000714202d3a4753606d7986868686868686868686868686868686868686868686868686868686868686868683776a5d5144372a1e110400000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000006111c262f3d46515b646e74808a92979fa4abadb3b4b5b6b6b6b5b4aeaca8a09e948f847c6f6a5f564c41362a21160b000000000000000000000a1623303d495663707d8998a3aeb2b2b3a9978b7e7164584b3e2f3c4955626f7c8898a2aeb2b2b5ab998d807366554c4135291d11040000000000000000000000000000040607090808070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d29343f495156585a6773808d9aa6b3bfb2a6998c7f736659595959575550483e33281c100400101d2a3743505d6a7683909da9b6c3b9ada1979297a1a9b3ab9e9185786c605d6776828f9ca9b4aaa0969196a0acb9c5b8ac9f9285796c5f5246392c1f13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040707080706030000000000000000000000000000000000000000000000000000101d2a3743505d6a7683909d9f9f9f9f9f9c8f8376695c5043362a36424d5764717d8a97a19f9f9f9f9f9a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c53606d7985919eabb8c0b5ab9f9285796d6053493f33271b0f030000000714202d3a4753606d7a86939393939393939393939393939393939393939393939393939393939393939084776a5d5144372a1e110400000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000b17222d38424e58636d74808d929fa2a9afb5b9bec0c0bebebfc1bfbab9b2aca69e9691857c6f685e52463e33281c1005000000000000000004111d2935404b556673808c99aaa6a6a6a6a297887b6e6255483b2f3a4653606d7985929fa6a6a6a6a69d908376675d5145392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c18232d373f454a4c5966737f8c99a6b2bfb4a79a8e817467554b4c4c4a49443e362c22170b0000101d2a3743505d6a7683909da9b6c3beb3a9a19ea1a9b3b4ab9b8e8174655b5565727f8c98a8b2b2a8a09ea0a8b2bdc5b8ac9f9285796c5f5246392c1f13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9acacaca99c8f8376695c5043362d3a46535f6976828f9ca9b2acacaca79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594d5764717d8a97a1adb9bbafa3998d8073675d5141382d22170b000000000714202d3a4753606d7a86939f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9d9084776a5d5144372a1e1104000000000000030a0f16222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000030f1c28333f4a54606a727f8c929ca4adb3bbc0bdb8b7b3b1b1b2b5b9babfbdb8b0a8a19791847a6d61594f44382c21160b00000000000000000613202c3945515d67768390999999999999999285796c605346392d3844505c667683909999999999999992867a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111b242d343a3f4b5865727e8b98a5b1beb6a99c908376675d514b4b4a49443e362c22170b0000101d2a3743505d6a7683909da9b6c3c5bbb3adabadb3baaea3998a7d71645355616e7b8896a0acb8b2acaaacb2bac4c5b8ac9f9285796c5f5246392c1f13000000000001070b0f1112131313131313131313100f0d0a050000000002080c1012121313131313131313130e0d0b08030000000000000000000000000104070709090807060300000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6b9b6a99c8f8376695c50433634404b54616e7b87939facb9b9b9b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659535e6976828f9ca9b3beb9ac9f92867b6e61554b402f261b1106000000000714202d3a4753606d7a8693a0acacacacacacacacacacacacacacacacacacacacacacacacacacacaa9d9084776a5d5144372a1e11040000000000060e151b1f222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000006121f2b3844505b666f7c87929fa4aebabebfbab2acaaa6a5a4a5a8acaeb4bcc1bab2a9a1968f82756b6155483d33271c1000000000000000000714202d3a4753606d7a868c8c8c8c8c8c8c8c8c8276655b5044372b343f4a546773808c8c8c8c8c8c8c8c8c8a7d7063574a3d3024170a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b2329313e4a5764717d8a97a4b0bdb8ac9f92867a6d60595858575550483e33281c100400101d2a3743505d6a7683909da9b6c3cdc5beb9b8b9beb9ac9f92867a6d6054535f697784919daab7bdb9b7b9bdc4ccc5b8ac9f9285796c5f5246392c1f1300000000050c12171b1d1e2020202020202020201d1c1916100a0300060d13181c1e1f2020202020202020201b1a18140f0801000000000000000002080d1113141616151312100b060603000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043363845515c6673808d9aa4afbbc8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665954616e7b87939facb9bcb1a79b8e8175695e5243392f1d140a00000000000714202d3a4753606d7a8693a0adb9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b7aa9d9084776a5d5144372a1e11040000000006101820262b2e2f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000613202d394653606c78839099a3afb6c0bcb4aea8a09e9a9897999b9fa3aaafb7c0bbb2a89e938a7d7063594f44382c1d1207000000000000000814212e3b4754616e7b7f7f7f7f7f7f7f7f7f7f7d706353493f33272e3c4955626f7c7f7f7f7f7f7f7f7f7f7f7d6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091116232f3c4956626f7c8995a8b2bdbaaea3988b7f726b66656564615a5044392d20140800101d2a3743505d6a7683909da9b6c3d0cfc9c6c5c6c2b5a99c8f8276675d514d576773808d9aaab3bec5c4c5c9ced2c5b8ac9f9285796c5f5246392c1f13000000060f161d23272a2b2d2d2d2d2d2d2d2d2d292926211c150d0710181f24282b2c2d2d2d2d2d2d2d2d2d272724201a130b02000000000000040c13191d2021232221201f1c1715130f0a0400000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043363a4653606d7985929eacb6c0ccc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366595b6673808c99a4afbbb8ab9f95897c6f62574d4231281d0b0200000000000714202d3a4753606d7a8693a0adb9d1c6cbc6c2c1bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7aa9d9084776a5d5144372a1e1104000000030e18222a31373a3c454955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000005121e2a36424d5764707d8a959fabb5c0bbb3aaa29f96918d8b8b8c8f92989ea5aeb6c0baafa59d9083776b605448392e23180c000000000000000714202d3a46525e696e73737373737373737373706b605441382d222e3b47535f6a6f737373737373737373736f6b6054483b2f22150900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a8796a1adb9bfb4aa9f92867d77737271706c6155493c3023160a00101d2a3743505d6a7683909da9b6c3d0dad5d2d1c8bdb2a8988b7f7265554b495663707d8998a2aebac6d1d2d5d9d2c5b8ac9f9285796c5f5246392c1f130000050f1820282f3337383939393939393939393635322d261f1610192229303538393939393939393939393433302b251d140b0100000000040e161e24292c2d302f2e2d2b2823221f1b16100b050000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504337424d5764717e8a97a1adbec7d2c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659606c7884919eabb5bdb2a89d9083766a6054453b301f160c0000000000000714202d3a4753606d7a8693a0b5c0cbc9c0bab6b4aeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaa9d9084776a5d5144372a1e11040000000a15202a343c434748515255626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000714212d3a46535e697683909ca7b1bdbeb3a9a298928a84807e7e7f82868e939ca4aeb9c1b8aca095897d7063544b4034281c100400000000000005111e2a36424d575e61666666666666666666666360594f442f261b2b37434e585f62666666666666666666666360594f43382c1f130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d677884919eabb7c4baaea298928a83807e7e7e7064574a3d3124170a00101d2a3743505d6a7683909da9b6c3d0dce2ded1c5b8aca096887b6e6155484653606d7985929fabb8c5d2dde1dfd2c5b8ac9f9285796c5f5246392c1f1300010c16202a323a3f434546464646464646464643423e3831281f18222b343b41444546464646464646464641403c362f261d1308000000020c1620283035393a3c3c3b3a38342e2e2b27201c160c0701000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433a47535f6976838f9ca9b3bed0cdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665663707d8a96a1adbdb9ada1968a7e7164584e4333291f0d040000000000000713202d3a4653606d798699a3afbbc7c0b7afa9a7a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a29d9084776a5d5144372a1e11040000030f1b26313c464e53555e5e5e626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000815212e3b4854616e7b87949fabb9c3baada29792867e7773727172757a818d929ca7b1bcbcb1a79b8e8275665c5145382c1f1306000000000000020e1a25303b454d52545959595959595959595956544f473d331d1b26323c464e53555959595959595959595956544f473d32271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c556874818e9ba9b3bebeb4aaa29f95908d8b8b8376695d5043362a1d1000101d2a3743505d6a7683909da9b6c3d0dce9ddd0c4b7aa9d918477695f534644515c6675828e9babb5c0ccd7e3dfd2c5b8ac9f9285796c5f5246392c1f130007121d28323c444b5051535353535353535353504e49423a31261f29343d464c51525353535353535353534e4c4841382f251a0f03000008131e28323a41454749494846443f3c3b38322c272118120b030000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043404b55626e7b88949fabbbc5cfcdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665e6875828f9ba8b2bdb4aa9e9184796d6053463d3220170d0000000000000006131f2c3845515c677986929facb9c5baafa59d9a9595959595959595959595959595959595959595959084776a5d5144372a1e1104000006121f2b37434e585f626b6b6b696f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000c1925323f4c5865727f8b98a6b0bbbeb3a99f92857c716c67656466686e75808d95a0acb8c3b8ab9f9285796d6053463a2d2013070000000000000009141f29333b4246474c4c4c4c4c4c4c4c4c4c4a48443d352b2115202a343c4347494c4c4c4c4c4c4c4c4c4c4948433d352b21160a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d19242f3e4b5764717e8a97a1adb9c2bcb4aea79f9d9998908376695d5043362a1d1000101d2a3743505d6a7683909da9b6c3d0dce2d6cabeb3a99a8d807367574d42404a5464717e8b99a4afbbc7d4e0dfd2c5b8ac9f9285796c5f5246392c1f13000b17232f3a444e565c5e6060606060606060605c5a544c42382d24303b464f575d5f6060606060606060605a58534a41362b20140800010d1924303a444c525456555453504a4947433d383329231d150d0300000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504345515c6773808d9aa6b0bbcdd6cdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366616e7a86929facb9baaea2988c7f72665c5044382c1f12050000000000000004101c2834404b556c7885929fabb8c5b6a99d938e8888888888888888888888888888888888888888888883776a5d5144372a1e110400000815212e3a47535f6a6f78787776747c8895a2afbbbdb1a4978a7e7164574b3e3124180b0005111d2a36414c566975828f9ca8b5c2b9ada1978c7f726a615a5858565e616d7883909daab7c3baaea298897d7063564a3d3023170a00000000000000020d17202930363a3b404040404040404040403d3c38332b231a0f18222a32373b3c404040404040404040403c3b38322b23190f04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000813202d3a4653606d7985919ea6b0bbc0bebab1abaaa69c908376695d5043362a1d1000101d2a3743505d6a7683909da9b6c3d0dcdfd3c6baada297897c706356493d3a4754616d7a86939facb9c6d2dfdfd2c5b8ac9f9285796c5f5246392c1f13000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c69665e54493e322835414c5761696c6c6c6c6c6c6c6c6c6c67645c53483c3024180b0004111d2935414c565d60636261605c5456544e48443d342f271f150d03000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50434753606d7985929eabb8c2cddacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736666727f8c99a3aebbb6ac9f92867a6d60544a3f34281c100300000000000000000c18232e44515e6b7784919eaab7c1b4a79a8e817c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e6155483b2e2215080000000915222f3c4855626f7c84858483807f8c98a5b2bfbdb1a4978a7e7164574b3e3124180b000713202d3946525e687885929eabb8c5b8ab9e9285796d6058504b4b4c525c66717e8b97a8b2bdbeb4aa998c7f7266594c3f3326190c0000000000000000050e171f252a2d2e33333333333333333333302f2c27211a1108101820262b2e2f33333333333333333333302f2c2721191007000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c66727f8b949fa7afb5b8bcbcb8b6a99c908376695d5043362a1d1000101d2a3743505d6a7683909da9b6c3d0dcded2c5b8ab9f9285796d6053463a3946525e687683909da9b6c3cfdadfd2c5b8ac9f9285796c5f5246392c1f1300111d2a3743505c6872787979797979797979797670665a4e42352b3844515d697378797979797979797979746e64584c4033271a0d000713202c3945525d686d6f6f6e6d6667626058554f45403931271f150b010000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50434e5864717e8b97a2adb9c6d4dacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73666b7784919eabb5bbafa49a8d8174685d5242382e23170c000000000000000000071c2936424f5c6975828f9ca8b5c1b4a79b8e81746f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e695f53463a2d2114070000000916222f3c4955626f7c8891918f8d8c919ba7b4c0bdb1a4978a7e7164574b3e3124180b000714212e3a4754616d7a8797a1adb9c1b5a89b8e8275675c51463f3e414a54616e7a8796a0acb9c1b4a89b8e8175685b4e4235281b0f000000000000000000050d141a1e2021262626262626262626262322201c160f0800070e151b1f21222626262626262626262623221f1b160f0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b54606c788290959fa4abacb1b0b1b1a99c908376695d5043362a1d1000101d2a3743505d6a7683909da9b6c3d0dcd7ccc0b5ab9b8e8275665c51443836414c5666737f8c99a8b2bdc9d5dfd2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b78848686868686868686868276695c5043362c3945525f6c78858686868686868686868174675a4e4134271b0e000714212d3a4754606d7a7c7c7b7976736f6a636159514b433931271d12070000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5047535f6a7683909ca9b3becad6dacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366707c8996a0acbdb9ac9f93877b6e62564c4130261c11060000000000000000000d1a2733404d5a6673808d99abb5c0b7aa9d918477696262626262626262626262626262626262626262615f574d42362a1e12050000000916222f3c4955626f7c88959e9c9a989ba3adb8c4bdb1a4978a7e7164574b3e3124180b000916232f3c4956626f7c8995a9b3bebeb2a5988b7f7265554b4034303846525e687784919eaab7c3b6a99c908376695d5043362a1d100000000000000000000002090e11141419191919191919191919171614100b05000000040a0f131516191919191919191919191615130f0a0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3944505b666d7a838e93999da0a7a3a4a4a49c908376695d5043362a1d1000101d2a3743505d6a7683909da9b6c3d0dcd4c7bbafa4998b7e7164544a4034303c4955626f7c8896a1adb9c5d2dfd2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b788491939393939393938f8376695c5043362c3945525f6c788592939393939393938d8174675a4e4134271b0e000a1723303d4a5663707d8988878683807c77706b605c554b43392f23180c0500000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504b55626f7b88949fabbbc5cfdbdacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736875818e9ba8b2bcb1a79c8f82756a5f53443a301e150a000000000000000000000b1724313e4a5764717d8a99a3afbbb8aca095887b6e615755555555555555555555555555555555555555534d453b31261a0e020000000916222f3c4955626f7c8895a2a9a7a5a7adb5bfc9bdb1a4978a7e7164574b3e3124180b000a1723303d4a5663707d8996a3b0bcbdb0a3978a7d7064574a3d2e2a36414d566976838f9ca9b6c2b7aa9d9084776a5d5144372a1e11000000000000000000000000020507080d0d0d0d0d0d0d0d0d0d0a09070400000000000000030608090d0d0d0d0d0d0d0d0d0d090907030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d28333f4a545d686d7981878d9095959797989797908376695d5043362a1d1000101d2a3743505d6a7683909da9b6c3d0dcd2c6b9ac9f93867a6d6154473a2e2e3b47545f6a7884919eabb8c4d1dcd2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919e9f9f9f9f9f9c8f8376695c5043362c3945525f6c7885929f9f9f9f9f9f9a8d8174675a4e4134271b0e000a1723303d4a5663707d89959892908d89837d746d675c554b40342921160b00000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50515d6774808d9aa6b0bccdd7e1dacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f75757a86929facb8b8aca095897d7063574e4232281e0c03000000000000000000000714212d3a4754606d7a86929facb9bcb1a79a8d8074695f5349484848484848484848484848484848484846423b332a1f1409000000000916222f3c4955626f7c8895a2afb3b2b4b8bfc7cabdb1a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa296897c6f6356493c302530424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d38424c565d676d747b808487888a8a8b8b8a898276695d5043362a1d1000101d2a3743505d6a7683909da9b6c3d0dcd0c3b6a99d908376685e5246392d2b37434e586774818e9aaab4bfcbd7d2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabacacaca99c8f8376695c5043362c3945525f6c7885929fabacacaca79a8d8174675a4e4134271b0e000a1723303d4a5663707d8996a39f9d9a95908981796d675c51453d33271c1004000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5053606d7985929fabb8c2cddee9dacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7aa9d90838282829098a3aebab3a99d9184776b6054453c3120160c00000000000000000000000713202c3945525d687683909caab4bfb9ac9f92877b6e655b50443d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3b3a36312a21180e03000000000916222f3c4955626f7c8895a2afbbbfc0c4c9d1cabdb1a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c262f3a444c555d60696e73777a7c7d7e7e7e7e7d7b6e6154483b2e21150800101d2a3743505d6a7683909da9b6c3d0d5c9bdb2a8998c7f7366564c41362a26323d4a5764707d8a98a3aebac7d3d2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7b9b6a99c8f8376695c5043362c3945525f6c7885929fabb8b9b4a79a8d8174675a4e4134271b0e000a1723303d4a5663707d8996a3aca9a7a09d938e82796d60594f44382c21160b000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c4e5865717e8b97a2adbac6d3dfe7dacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8aca095908e8e90949faab4b9ada1978b7e7165594f44332a200e04000000000000000000000004111d2935414c5665727e8b98a2aebabbaea3998f82776c60594f463d342f2f2f2f2f2f2f2f2f2f2f2f2e2d2a261f180f0600000000000916222f3c4955626f7c8895a2afb8babec5ced2cabdb1a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141d28323a434b51575f6167676d6f7071717171706e695e53463a2d21140700101d2a3743505d6a7683909da9b6c3d0d2c5b9ada196887c6f6255493c3025202d3a4753606d7a86929facb9c5d2d2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000a1723303d4a5663707d8996a3b0b6b1aba59d948e81746b6054483d32271b10040000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c535f6a7683909da9b3becad6e2e7dacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bcb1a7a09d9b9b9c9fa6b0bcb8ab9e9285796d6053473d3320180e000000000000000000000000010d19242f3a4754606d7a86929faab4bfb5ab9f948c7f726b61584e463c342b2222222222222222222222211e1a140e060000000000000916222f3c4955626f7c8895a2a8abadb3bcc1c9cabdb1a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b162028313940454d5355555d6062646465646463615e574d42362a1e120500101d2a3743505d6a7683909da9b6c3d0d1c4b7ab9e9184786a5f53473b2e1e202c3945515d6776828f9ca9b5c2ced2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000a1723303d4a5663707d8996a3b5babcb8afa69d93897d7063594f44382c2013070000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c55626f7c88959fabbcc5d0dbe0e4dacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c3b9b1acaaa8a8a9abb0b8c0b3a6998d8073675d5145382c1f1306000000000000000000000000000813202c3945515d6774818d98a2aebabdb0a69f92877d706a60584e463d342b231a151515151515151514120e0903000000000000000916222f3c4955626f7c8895999b9fa2a9afb7c1ccbdb1a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040e161f282f353c4246484c51545557575858575654534d453b31251a0e0200101d2a3743505d6a7683909da9b6c3d0cbbfb4aa9a8d817467584e43372b1f1d2935404b5565727f8b98a7b1bcc8d2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000a1723303d4a5663707d8996a3abaeb4bcb8afa59d9083776b6054483b2f2216090000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5d6774818d9aa7b1bccecfd0d3d8dacdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0cbc3bcb8b7b5b5b6b7bcc2bbaea194887b6e61554b4035291d10040000000000000000000000000004111d2935414c55616e7b86929fa8b2bdbbafa39992867c6f6a5f584e463d352c241b120909090909080705020000000000000000000916222f3c4955626f7c888b8c8e92979ea5afbac3bdb1a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d161d242931373a3b414547494a4b4b4b4b494846423b33291f14090000101d2a3743505d6a7683909da9b6c3d0c7baaea3988a7d7063574a3d32261b18242f3b4854616e7b8795a0acb8c5d2c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000a1723303d4a5663707d8992999fa3aab4bfb8aca095897c706356493d31261a0e0200000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c606d7a85929fabb8c2c4c3c4c7cdd4cdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c3bab2acaaa8a8a9abb1b9beb1a4988b7e71655b5044372b1f150a00000000000000000000000000010d19242f3a46525e6973808c96a0abb5bfb5aba29892857c6f6a60584f473e362d241c130a020000000000000000000000000000000714212d3a4754606d7a7e7e7f82858e939ea8b2bdbdb1a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c12181f262b2d2f35393a3c3d3e3e3e3e3d3b3a36312921170d030000101d2a3743505d6a7683909da9b6c3d0c5b8ac9f92867a6d6053473a2d201414212d3a46535e697784919daab7c4cfc5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000916232f3c4956626f7c84868b9298a3aebabcb1a79a8e817467574d42372b1e120600000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695865727e8b98a2aebabcb7b6b7bcc2cbcdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bdb2a8a09d9c9c9d9fa7b1bcb7aa9d9184786c6053463c32261b0f020000000000000000000000000008131e2a36424d56606d79849199a3aebbbdb4aaa29792857c6f6a605950483f362d251c140a0200000000000000000000000000000713202c3945525d686d717173757a818e96a0acb2b2b1a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d141a1e2124292c2d2f3131323131302e2d2a251f170f05000000101d2a3743505d6a7683909da9b6c3cfc2b5a89c8f8275675d5145392c1f13121e2a36424d576773808d9aa9b3becac5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000815222e3b4754606a6f777a7f86929fa7b1bcb8ab9e928578695f53473a2d21140800000000101d2a3743505d6a7683909da9b6c2b6a99c8f837669606a7783909daab4b9b0aba9abb0b9c2cdc0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8aca096918f8f90959faab4b8aca0958a7d7063584e43372b1f140900000000000000000000000000010e1925303b45515d676f7c87929fa5afb8bcb3a9a19792857c706b615a50483f372e261c140b020000000000000000000000000004111d2935414c565d60646466676d7884919ea5a5a5a5a4978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e1214191d20212224242525242321211e1a140d0500000000101d2a3743505d6a7683909da9b6c3c8bcb1a7988b7e7265554b4035291d100e1a25313c4956636f7c8997a2adbac6c5b8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0006131f2b37434e586062676d727e8a95a0abb8b9ada197887b6e6155483b2e22150800000000101d2a3743505d6a7683909da9b6c2b6a99c8f837669626f7c8995a0acbcb0a69f9c9fa6b0bcc7c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7aa9d91848282839098a3aebab1a79c8f82766a5f53473b30251a0e010000000000000000000000000009141f2935404b55606a727f8c939ea6b0babbb3a9a19792867d716c625a514940382e261d140b01000000000000000000000000010d19242f3a444c52545758555d6673808c989898989898978a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000205080d111314161718181818161514120e09030000000000101d2a3743505d6a7683909da9b6bfbfb8aca095877b6e6154483b2f24180c0913202d3a4653606d7985929fabb8bfbfb8ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00030f1b27323d464e54555d606c7783909daab6beb3a9978a7d7164574a3e3124170b00000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376696874818e9aa7b1b7ab9f9490949fabb7c4c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f75757a86929facb8b7ab9f94887c6f62574d42362a1d130700000000000000000000000000020d18242f39434e58606c77818e949fa8b1b9bbb3a9a29892867e716c635b524a40382e261d140a0100000000000000000000000008131e28323a4145474a4b4b5464717e8a8c8c8c8c8c8c8c8a7e7164574b3e3124180b000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040607090a0b0b0b0b0a0807050200000000000000101d2a3743505d6a7683909da9b2b2b2b2aa9d908477695e53463a2d1d120706121f2b3844505c6675818e9babb5b2b2b2ac9f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000a16202b343d43474c515a6673808d99a6b3bfb2a6998c7f7366594c403326190d00000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376696d7a86929facb8b3a99c9083909ca9b6c3c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736875818e9ba7b1bbb0a69b8e8175695e52463a2f24180d000000000000000000000000000007121d28313d44505b656d79829095a0a7b1b9bbb3aaa29892877e726d635c524a40382e261c130a000000000000000000000000010c1620282f35393a3e3e4855616e7b7f7f7f7f7f7f7f7f7f7b6e6255483b2f221508000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da5a5a5a5a5a9998d807366574d42362a1e0b0103101c28343f4a5464717e8a99a3a5a5a5a5a59f9285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000040f19222b32373a414b5865717e8b98a4b1beb4a79a8d8174675a4e4134271b0e01000000101d2a3743505d6a7683909da9b6c2b6a99c8f837669727f8b98a2aeb9ada1978b7e8b97a4b1bec0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73666f7c8995a0acb8b9ac9f92867b6e61554b4035291c110600000000000000000000000000010c161f27333f49535c676d7a839195a0a7b1b9bcb4aaa399938b7f736e645c524a40382e251c1208000000000000000000000000040d161e24292c2d313a46535f696e7272727272727272726e695f53473a2e211408000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3743505d6a7683909898989898989897897c6f6356493c31251a0e00000b17232e3a4754616d7a8692989898989898989285796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000007101920272b2f3e4a5764717d8a97a4b0bdb5a89b8f8275685c4f4235291c0f02000000101d2a3743505d6a7683909da9b6c2b6a99c8f83766b7783909daab4b8ab9e92857a8793a0adbac0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73666b7784909daab4bbaea3998d8073675d5145382e23170b0000000000000000000000000000040d17222d38414b555d686e7a839095a0a7b0b8bcb4aba49f918c80736e645c524a40372e241a1007000000000000000000000000040c13191d20212a36424d575f61656565656565656565625f574d42372b1e1206000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3743505d6a76838c8c8c8c8c8c8c8c8c85786d6053463a2d20130900000613202d3946525d6876828c8c8c8c8c8c8c8c8c85796c5f5246392c1f1300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000070f161b24313d4a5764707d8a97a3b0bdb5a99c8f8276695c4f4336291c1003000000101d2a3743505d6a7683909da9b6c2b6a99c8f83766f7c8995a0acbcb0a69a8d80798693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736665727f8b98a2aebab5ab9f92857a6d60544a3f34281c1003000000000000000000000000000006111b262f39434c565e686e7a8390959fa6b0b8bdb5afa39c928d80746e645c52493f362c22190e0400000000000000000000000001080d11131a26313b454d535559595959595959595955534d453c31261a0e02000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313e4b5764717e7f7f7f7f7f7f7f7f7f7e71665c5044382b1f1206000005111d2935414c5663707d7f7f7f7f7f7f7f7f7f7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000040a1724313d4a5764707d8a97a3b0bdb6a99c8f8376695c504336291d1003000000101d2a3743505d6a7683909da9b6c2b6a99c8f837674818e9ba7b1b7ab9f94887b798693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366606d7a86929facb8baada2978b7f72665c5044382b1f160a0000000000000000000000000000000a141d27303a444d565e686d7a8390949ea6afb7c0bbada49c928d80746e635b51483e342b20160c0200000000000000000000000000010409141f29333b4246484c4c4c4c4c4c4c4c4c4847423c332a20150900000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1723303d4955616c71727272727272727272716c61544a3f34281c10030000010d1924303a4854606b70727272727272727272726d62564a3e3124180b00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c2b6a99c8f83767a86929facb8b3a99c9083767a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665d6874818e9ba7b1bcb3a99e9184786d6053463d32271b0f030000000000000000000000000000020b151e28323b444d565e686d7a828f949ea5aeb6bfb6aea49d928d80736d635a50463d32281e1308000000000000000000000000000000030d18212931363a3b3f3f3f3f3f3f3f3f3f3b3a37312a21180e0300000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815212d3945505a616465656565656565656564615a5042382e23170b0000000008131e2c38444f59606365656565656565656565625b51463a2e22160900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c2b6a99c8f83767f8c98a3aebaada2978b7e717a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736656626f7c8995a0acb8b9aca1968a7e7164594f43382c1f1409000000000000000000000000000000030c162029323b444c565e686d79828e939da4aeb6bfb6aea49c928c7f726c61584e443a3024190c03000000000000000000000000000000060f181f262a2d2e3232323232323232322f2e2b2620180f060000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d28343e48505557595959595959595959575550483e30261c11060000000002101b27323d474f5456595959595959595959585651493f34291e120600121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c2b6a99c8f837784919daab4b8ab9f9285796d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659606a7783909daab4bdb2a89d9083766b6054483c31261a0e02000000000000000000000000000000040e172029323a444c565d676d78818d929ca4adb5bfb6aea49f93887e716a60564c4135291e150a00000000000000000000000000000000060d141a1e212226262626262626262622211e1a150e06000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c17222c363e45494b4c4c4c4c4c4c4c4c4c4a49443e362c1e140a0000000000000b16212b353d4448494c4c4c4c4c4c4c4c4c4c4a463f372d23180d0100121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336353945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c2b6a99c8f837d8995a0acbcb1a79a8d80746d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366595865727e8b98a2aebab8ab9f95897c6f63574d42372b1e130800000000000000000000000000000000050e172029323a434c555c666d77808c929ba3adb5bfbbafa49a92867c6f685d52463e30261c11060000000000000000000000000000000003090e1214151919191919191919191514120e090300000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006101a242c34393d3e3f3f3f3f3f3f3f3f3f3e3c39332c241a0c02000000000000040f19232b32383b3d3f3f3f3f3f3f3f3f3f3f3e3a342d251b11060000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504342424245525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c2b6a99c8f82818e9ba8b1b8ab9f95887c6f6d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665954606d7a86929facb8bcb1a79b8f8275695f53463a3025190d0000000000000000000000000000000000050e172028313a434b545c656c74808c919ba3adb6c0b6aca39891847a6d61594f42382e23170c000000000000000000000000000000000000020507080c0c0c0c0c0c0c0c0c08080602000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008121a22282d303132323232323232323231302d28221a1208000000000000000007111921272c2f3032323232323232323232312e29231b1309000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504e4e4e4e4e525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3b7aa9d908386929facb9b4aa9d9083766a6d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659515d6774818e9aa7b1bcb9ac9f93877b6e61564c4135291d12070000000000000000000000000000000000050e161f283139424a535b606e737f8b919ba4adb7beb4aaa1968e81756b61544a3f34281c100300000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810171d2123242626262626262626262423211c17100800000000000000000000070f161b2022232626262626262626262524221e18110901000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5b5b5b5b5b5b5b5f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3b8aca095909299a3aebaaea2988b7e71656d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c55626f7c88959fabb8bbafa4998d8174685e5246392e23180c000000000000000000000000000000000000050d161f2730384149505b636d727f8b919ca5afb9bcb2a89e938a7d70665c5044382c1f160a000000000000000000000306070f1010101010100e0d0b0703000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c11151718191919191919191919171614100b05000000000000000000000000040b10131616191919191919191919191816120d060000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696868686868686868686c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3bcb1a7a09d9fa3abb4b8ab9f9285796d606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c54606a7783909daab4beb5ab9f92867a6d61554b4034281c1004000000000000000000000306060b0b0b0b0b0b0d151e262f383f44525b626d737f8c939ea7b1bdbaafa59e9184786d6053463d32271b0f0300000000000000060c1012131c1c1c1c1c1c1c1a1a17130e080100000000000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0b0a0804000000000000000000000000000000000407090a0c0c0c0c0c0c0c0c0c0c0b090601000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f837675757575757575757575757885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3c3b9b1acaaacaeb4bdb1a79a8d817467606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4e5865717e8b98a2aebabaaea2988c7f73675c5145382c1f160b0000000000000000060b0f12131818181818181818151d262d334049515b636d74818e95a0abb5c0b9aca0968b7e7165584e43382c1f13070000000000030a11171c1f20292929292929292726241f1a130b02000000000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8ab9e92858181818181818181818181818187929facb9c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3cbc3bcb8b7b9babfb8aca095887c6f62606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4753606d7a85929fabb8bfb4aa9e9185796d6053463d33271c10010000000000020a11171c1f2025252525252525252525212227373f49515b606d79839199a3afbbbdb2a89d9083776a6054483b2e22150800000000030c151c23282c2d363636363636363433302b241d140b000000000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003080b0d0e1313131313131313130c0b090501000004090e111213131313131313131313080705020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b9ada197928e8e8e8e8e8e8e8e8e8e8e8e8e9299a3aebbc0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0cec8c5c3c5c7bfb4aa9d9083776a60606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c45515d6774818d9aa7b1b2b2ada1978b7e7164594f44382c1d120700000000020b141c22282b2d313131313131313131312e2d2a2d374045515d676f7c87929fabb5c0b8aca095897c6f6256493c3024190d010000000a151e262e34383a42434343434343413f3c362f261d0f060000000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001080f14181a1b202020202020202020181815110c06080f151a1d1f202020202020202020201414110e0802000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4beb3a9a19e9b9b9b9b9b9b9b9b9b9b9b9b9b9fa3abb5bfc0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0d9d4d1d0d2c6baaea2988b7e726558606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c404b55626f7c88959fa6a6a6a6a99d9083776b605548392f23180c000000000a141d262d3338393e3e3e3e3e3e3e3e3e3e3b3936302935404b555f6a74818d99a3afbbbcb1a79a8d807367564c4135291d1105000006111c2630383f44464f4f4f4f4f4f4f4d4c4740382f21180e0300000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b131a202427272d2d2d2d2d2d2d2d2d2524221d1811121920262a2c2c2d2d2d2d2d2d2d2d2d21201e19140d050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c5bbb3adaba8a8a8a8a8a8a8a8a8a8a8a8a8acaeb5bdc6c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0dce0deddd2c5b8ac9f92867a6d6054606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4047535f6a7683909999999999999995897d7063554b4034291c1004000006111c262f383f44464b4b4b4b4b4b4b4b4b4b4746413b322f39434e58616e7b86929facb9c3b7aa9d918477685d5246392d20130700000c17232e38424a50535c5c5c5c5c5c5c5a58524a40332a1f150900000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010b141d252b30333439393939393939393932312e29231b1b242b313638393939393939393939392e2d2a251e170e0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cdc5beb9b8b4b4b4b4b4b4b4b4b4b4b4b4b4b9bbbfc6cfc0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0dce9e0d4c8bcb1a79b8e8174675d53606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c40434e5865717e8b8c8c8c8c8c8c8c8c8c8276675c5145382c1f130600000b17222d38424a50535858585858585858585854524c443b30313c46525e6875828e9ba8b5c1b9ac9f93867a6d6154473a2e2114070003101c28343f4a545c606969696969696967645c52453c31261a0e00000000000000000000000a1724303d4a5763707d8a96a3b0bdbcafa396897c706356493d302834404b546975828f9ca8b5c2b7aa9d9184776a5e5144372b1e1100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131d262f363c40414646464646464646463f3d3a342d24242d353d4245464646464646464646463b3936302920170d02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cdc4beb9b8b4b4b4b4b4b4b4b4b4b4b4b4b4b9bbbfc6cfc0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0dce9ded1c5b8aca095897c6f625553606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403c4753606d797f7f7f7f7f7f7f7f7f7f7f796d6053473a2d20140700030f1c28333f4a545b6064646464646464646464615e564c41362a36414d5664717e8a97abb5c0bbafa49a897c706356493d3023160a0006121f2c3844505c666d75767676767676746e64574d42372b1d1207000000000000000000000a1623303d495663707d8996a3afbcbdb1a4978a7e7164574b3e312c3845515c667783909daab6c3b6a99d9083766a5d5043372a1d100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1a252f3841484c4e5353535353535353534b4a453f372d2b353f474e52535353535353535353535346413b32291e1408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c4bbb3adaba7a7a7a7a7a7a7a7a7a7a7a7a7acaeb5bdc6c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0dce3d6cbbfb4aa9d9083776a605453606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403945515d676d73737373737373737373736d675c5145382c1f13060006121f2b3844505b666c717171717171717171716e685e5246392d303b4854616e7b8799a3afbbc0b6ac988b7e7165584b3e3225180b000713202d3a4653606d78828282828282828074695f5347392e23180c000000000000000000000815222f3b4855626e7c8895a8b2bdc0b3a6998d807366574d4238383d4653606d7985929facb8c2b5a89c8f8275695c4f4236291c0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814202b36414a53585a606060606060606060585651493f34313d4751595e5f6060606060606060605f524c443b3025190e020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4beb3a9a19e9b9b9b9b9b9b9b9b9b9b9b9b9b9fa3abb5bfc0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0dce0d3c7baaea3988b7f7265584e53606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4035404b555d606666666666666666666666605c554b4034291c1004000613202d394653606c797e7e7e7e7e7e7e7e7e7e7a6e6154473b2e2d394653606c7986929facb9bfb2a5998c7f7266594c3f3326190c0006121f2c3844505c6676838f8f8f8f8f8f877b6e61554b4034281c10040000000000000000000714202d3a4753606d798696a0acb8c3b6a99c908376695e534a4645464f5863707c8998a2aebac0b3a69a8d8073675a4d4034271a0d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6c65625b51453a36424e59636a6c6c6c6c6c6c6c6c6c6c6c5e564c41362a1e11050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b9ada197918e8e8e8e8e8e8e8e8e8e8e8e8e9299a3aebbc0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0dcdfd2c5b8ac9f92867a6d60544753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c402f39434b5153595959595959595959595953514b43392f23180c000006121f2b3844505b6679878b8b8b8b8b8b8b8b8a7d7063574a3d302c3845515c667885929fabb8bfb3a6998c807366594d4033261a0d0003101c28343f4a5466737f8c999c9c9c9a8d8073675c5145382c1f150900000000000000000006131f2c3945515d677784919eaab7c4b9ac9f92877b6e615c5452515359606a75818e9baab4bfbcb1a7978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2733404c58646e74797979797979797979726d62564a3d3845525e6a757979797979797979797976685e5246392d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8ab9e91858181818181818181818181818187929facb9c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0dcd4c8bdb2a89b8e8175685d524753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403331394045474c4c4c4c4c4c4c4c4c4c4c4745403931271d12070000030f1c28333f4a5f6c788592979797979797978b7e7265564c4137353c4653606d7986939facb9bfb2a6998c7f7366594c403326190d00000c17232e3c4955626f7c8897a1a9ac9e9285796d6053463c31261a0e00000000000000000004101d2935404b556874818e9ba9b3bebbafa3998e81756d66615e5c60636b707c88939facb9c6b8aca095877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774808686868686868686867f7265584b3f3946535f6c79878686868686868686867a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f837674747474747474747474747885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0dcd1c5b8aca096897c7063564c4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4033272f35393a40404040404040404040403a38342f271f150b010000000b17222d44515d6a7783909da4a4a4a4a49b8e8175685e52474341464e58636f7c899aa4afbbbeb1a5988b7e7265584b3f3225180c00000613202d394653606c7885929eabada1978a7e7164574d42372b1d12070000000000000000000c18242f3e4a5764717d8a97a2adbac0b5ab9e938d8078716e68676d6f747d85929aa4afbbbfb4aa9d908377695e52463a2d20140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d939393939393938b7e7265584b3f3946535f6c79869293939393939393877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696868686868686868686c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0d7cbbfb4ab9d9184776b6054444753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c40332624292c2d33333333333333333333332d2c29231d150d0300000000061b2835424e5b6875818e9ba8b1b1b1ac9f92867a6e615c534e4c52575f6a74808d9aacb6c0bcb1a796897d7063564a3d3023170a000005121f2b3744505b6575818e9ba8b3a99c8f8376695f5347392e23180c0000000000000000000714202d3a4753606d7985929faab4bfbdafa59d928d837e7a7978797c81879297a2acb6c0baaea2988c7f7266574d42362a1e120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9a9f9f9f9f9f988b7e7265584b3f3946535f6c7986929f9f9f9f9f9f94877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5b5b5b5b5b5b5b5f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0d3c7baaea3998c7f7265594f444753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326181d1f202626262626262626262626201f1c18120b0300000000000c1925323f4c5865727f8b98a7b1bcbaaea3988e81756e625f58565e61696e7c86929facb9c5b8aca095877a6e6154473b2e2114080000030f1b27333f495364717e8b97a7b1ab9f94887b6e62554b4034281c1004000000000000000006131f2c3945515d6773808d98a2aebac1b7aea49d95908b87858586898e9299a2a9b3bebeb3a99f92867a6d6154473b30251a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7acacaca5988b7e7265584b3f3946535f6c7986929facacacaca194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504e4e4e4e4e525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0d2c5b9ac9f92867a6d6154473d4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4033261910131419191919191919191919191413100c07010000000000000815222e3b4855616e7b8895a0acb8bfb4aa9e938c80766f6a6968686d727b839199a3aebac4b7aa9d918477685e5246392d2014070000000b17222d3b4754616e7a8795a0acb0a69a8d8073675c5145382c1f1509000000000000000004101d2935404b55616e7b86929fa7b1bac0b6aea7a09d9798929292999a9fa3abb3bbc1b9ada1978d8074685d524639291f14090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3946535f6c7986929facb9b9ada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504341414145525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0c9bdb2a89b8e8275685e52463a4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d06070d0d0d0d0d0d0d0d0d0d0d0706040000000000000000000814212d3a47535f697784919da9b3bebcafa59c928c827c777575777a7f859195a0abb4bfbdb0a6998d807366564c41362a1e11050000000614202d3946525e687784909daab7ab9e9285796d6053463c31261a0f0100000000000000000c18242f3946525e68737f8c959fa8b2bac0b9b1acaaaaa29f9e9fa3abacafb5bdc0bbaea49e92857a6d60564c413529170d030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336353945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3d0c5b9aca096897d7063564c413a4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000006121e2b37424d5765727f8b97a2adbac1b7aea49c948f8884828283868c9297a0a8b1bdc0b5ab9e94887b6e6255483b3025190d0100000005111e2a36414d566773808d9aaab4ada1978a7e7164584e43372b1d1207000000000000000007121d2a36414d56606d78839096a1a8b1bbc0bcb8b7b4aeacabacafb5b9bbc0beb6afa59d928a7e71685d52443a30241905000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3cbc0b5ab9e9184786c6053463a3a4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000020e1a26313c4753606d7985929fa7b1bbbfb6aea69f9c96918f8f9092989fa2a9b1bac2bbafa4998f82756a5f53473a2e1e140800000000020e1925303d4a5663707d8998a2aeb3a99c9083766a5f5347392f23180c0000000000000000010e1925303b44505c666e7b849196a0a7afb5bbc0c3bfbab8b8b9bbc0c3bdb8b2aca49f938d80736c61564c4132281e1308000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6c3c7bbafa3998c7f72655b5044373a4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000915202c3945515d67727f8b95a0a9b3bcbfb8b0aaa8a09e9c9b9d9fa3aaadb3bcc1b9b0a69f93877c6f62584e43372b1f0d0200000000000813202d3a4653606d7985929facb8ab9f94887b6e62554b4034291c1004000000000000000008141f28343f4a545e696e7c8490959fa3abafb5b8babfbdbdc0bbb9b7b2aca8a09a938c81786d605a50443a3020160c02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b6bfbfb9ac9f92867b6e6153493f333a4753606d7a8693a0adb9bdb4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4b9b2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000004101d2935404b55606d78839097a1aab2bbc0bbb7b2acaaa8a8aaacaeb4babebeb9afa79f948d80746a6054463c31261a0f00000000000006131f2c3845515c6775828f9ca8b5b0a69a8d8074675c5145382c1f150a0000000000000000020c17232e38424d565f6a6e7b838d92999fa4abacaeb4b0b0b5afacaaa8a09d96918880746d665c50483e32281e0e0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da9b2b2b2b2a89b8f8275685e5241382d3a4753606d7a8693a0adb1b1b1a79a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa7adadada6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000010d18242f3944505c666e7b859298a1a8afb6bbc0bdb9b7b5b5b7b9babfbebab3ada59e959082796d60584e43342a20150a00000000000004101c2834404b5565727f8b98a8b2b8ab9f9285796d6053473c31261a0f01000000000000000006111c26303b444e575f696e7980878e93999c9fa2aaa3a3aba49f9d9a96918b847d736e605c544a3f362c20160c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a7683909da5a5a5a5a5a1968a7d7063564d412f2d3a4753606d7a8693a0a4a4a4a4a49a8d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d9aa0a0a0a0a0998c7f7366594c403326190d00000000000000000000000000000000000000000000000000000007121d28343f4a545f696f7d8691969fa4acafb5b8babebdbdc0bbb9b7b3ada9a19e938e837a6d675c51463d3222180e03000000000000000c18232e3b4855626e7b8896a1acb9ada2978b7e7164584e43372b1d12070000000000000000000a151e29323c454e575e676d737c81878c8f9298969797969993918d89847e796f6b635c504a42382e241a0e040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a768390989898989898989184786c6053463b302d3a4753606d7a8693979797979797978d8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774818d939393939393938c7f7366594c403326190d000000000000000000000000000000000000000000000000000000010b17232e38424d57606b6f7c848e939a9fa3ababaeb4b0b0b5afacaaa9a29f97928b81796d685d554b40342b200f0600000000000000000714212e3a47535f6a7884919eabb7b3a99c9083766a5f5347392f24180c000000000000000000030c17202a333c454d555c606a6f757b7f838588898a8a89888684807c78716d66605952443f3830261c1208000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000101d2a3743505d6a76838c8c8c8c8c8c8c8c8c8073665b504438292d3a4753606d79868a8a8a8a8a8a8a8a8a8174675a4e4134271b0e00000000000000000000000000000000000e1b2734414e5a6774808686868686868686867f7366594c403326190d0000000000000000000000000000000000000000000000000000000006111c26303b454f59606a6f7a81878e92999c9fa2aaa3a3aba49f9d9b97928d857e756d675d564c43392e22190f00000000000000000006121f2b37434e586774818e9aabb5b7ab9f94887b6f62554b4035291d1004000000000000000000050e18212a333b434b51585f62696e7276797b7c7d7d7c7c7a77746f6c66605c544f4740342e261e140a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000b1824313e4b5764717e7f7f7f7f7f7f7f7f7f7a6e61544a3f33282d394653606c787e7e7e7e7e7e7e7e7e7e7c6f6256493c2f23160900000000000000000000000000000000000713202d3a4653606d797a7a7a7a7a7a7a7a7a786d6053463a2d20130700000000000000000000000000000000000000000000000000000000000a141e29333d474f585f686d747c82868b8f9298969697969993908e8a85807a716c605d554c443a30271d1007000000000000000000020f1a26313e4a5764717d8a99a3afbbb0a69a8d8074675d5145382c1f150a00000000000000000000060f182129313940454e53575e6165666d6e707070706f6d676763605b54514b423d3528231c140c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000a1723303d4955616c717272727272727272726e685e5242382d222b3844505b666c717171717171717171716f6a6054473b2e221508000000000000000000000000000000000006131f2c3845515c676d6d6d6d6d6d6d6d6d6d6d665c5144382c1f12060000000000000000000000000000000000000000000000000000000000020c17212b343d464e565d616a6f757b7f838588898a8a89888684817d79736d68625a514b433a32281e150b00000000000000000000000914212d3a4754606d7a86929facb9b8ab9f9285796d6053473c31261b0f0100000000000000000000060f171f272f343c43474d5254545c60616364646362605d555653504a454039302b2317110a020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000815212d3945505a6164656565656565656565615e564c412f261c28333f4a545b60646464646464646464646260584e43372b1f1306000000000000000000000000000000000004101c2834404b555c60606060606060606060605c544a4034281c1004000000000000000000000000000000000000000000000000000000000000060f19222b343c444c52586062696e7276797b7c7d7d7c7b7a7774716d67615d5650454039312820160c0300000000000000000000000713202c3945525d687683909da9b6baada2978b7e7164584e43372b1d12070000000000000000000000050d151d232931373b4246474a505355565757565553514b4946443f38342e271e19110600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000005111d28343e4850555759595959595959595954524c443b301d17222d38424a50535757575757575757575756544e463d32271b0f030000000000000000000000000000000000000c18232e39434b515353535353535353535353514a42392e23180c0000000000000000000000000000000000000000000000000000000000000000071019222a323a41464e54575e6165656c6e6f7070706f6d676864605d55524c443f352f271f160e0400000000000000000000000004111d2935414c566673808c99a9b3b5b3a99d9083766a5f5347392f24180c000000000000000000000000030b121820262b30363a3b3f444648494a4a49494745403c3938332d28231d150c070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000c17222c363e45494b4c4c4c4c4c4c4c4c4c4746413b32291e111c262f383f44464b4b4b4b4b4b4b4b4b4b4947433d342b20150a0000000000000000000000000000000000000007121d2730394045464747474747474747474644403930271c1207000000000000000000000000000000000000000000000000000000000000000000071018202830353d43474d5254535b60616363646362605d555753514b46413a3229241d150d0400000000000000000000000000010d19242f3c4956626f7c8997a2a8a8a8a89f95887c6f62554b4035291d100400000000000000000000000001070c151a1f252a2d2e34383a3b3d3d3d3d3c3a39352f2d2b28221c18120b03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000006101a242c34393d3e3f3f3f3f3f3f3f3f3f3b3936302920170d141d262d3338393e3e3e3e3e3e3e3e3e3e3c3b37322b22190f0400000000000000000000000000000000000000000b151e272e34383a3a3a3a3a3a3a3a3a3a3a38342e271e150b0000000000000000000000000000000000000000000000000000000000000000000000060e161e242932373b42464849505355565757565553514b4a474540393530282018120b030000000000000000000000000000000813202d3a4653606d7985929b9b9b9b9b9b9a8d8074675d5145392c1f13060000000000000000000000000000030a0f141a1e2023282b2d2e303131302f2d2c2924201f1c17110c070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000008121a22282d30313232323232323232322e2d2a251e170e050b141c22282b2d313131313131313131312f2e2b2720191007000000000000000000000000000000000000000000030c151d23282c2d2d2d2d2d2d2d2d2d2d2d2c28231c150c03000000000000000000000000000000000000000000000000000000000000000000000000040c131920272b30363a3b3f444648494a4a49484745403e3a39352f29241e160e07010000000000000000000000000000000006121f2b3844505c6675828e8e8e8e8e8e8e8e8e857a6d6053473a2d2014070000000000000000000000000000000002090e1114171c1f20222324242322201f1d1813120f0b0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000810171d21232426262626262626262621201e19140d0500020a11171c1f202424242424242424242423221f1b150f070000000000000000000000000000000000000000000000030b12181c1f20202020202020202020201f1c18120b03000000000000000000000000000000000000000000000000000000000000000000000000000002080d151b1f252a2d2d3337393b3c3d3d3d3c3a39352f2d2c29241d19130c0400000000000000000000000000000000000003101c28343f4a5463707d828282828282828282817c6f6256493c2f2316090000000000000000000000000000000000000205060b1012131516171716161413100c070603000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7bfb6a99c8f8376695c5043362c3945525f6c7885929fabb8bfb4a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000060c111517181919191919191919191414110e080200000000060b0f1213181818181818181818181615130f0a040000000000000000000000000000000000000000000000000000070c1013131414141414141414141312100c07000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f141a1e2022272b2d2e303031302f2d2c2924201f1d18120d080200000000000000000000000000000000000000000b17232e384855616b70757575757575757575756f6a6054473b2e22150800000000000000000000000000000000000000000000030607080a0a0a0a0907060400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2a99c8f8376695c5043362c3945525f6c7885929fabb2b2b2a79a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000005080a0b0c0c0c0c0c0c0c0c0c0807050200000000000000000306060b0b0b0b0b0b0b0b0b0b090806030000000000000000000000000000000000000000000000000000000000000406070707070707070707070706040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e1214171b1f2022232424232220201d181413100c07010000000000000000000000000000000000000000000006111c2c38444f596163686868686868686868686260584e43372b1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a59c8f8376695c5043362c3945525f6c7885929fa5a5a5a5a59a8d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000205060b0f12131516171716151413100d0706040000000000000000000000000000000000000000000000000000101c28333e474f55575b5b5b5b5b5b5b5b5b5b56544e463d32271b0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b788491989898989898988f8376695c5043362c3945525f6c788592989898989898988d8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000000000000040607090c0e0f101110100f0d0b0807050200000000000000000000000000000000000000000000000000000000000000000000000000030606090c0e0f101110100e0c09070603000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003050608090a0a0a090706040100000000000000000000000000000000000000000000000000000000000b16212c353e44484a4f4f4f4f4f4f4f4f4f4f4947433d342b20150a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8376695c5043362c3945525f6c78858c8c8c8c8c8c8c8c8c8174675a4e4134271b0e0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000000000000070c10131316191b1c1d1d1d1d1c1a181514120e0905020000000000000000000000000000000000000000000000000000000000000000060b0f121316191b1c1d1d1d1c1b19161312100c0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005101a232c33383c3d424242424242424242423c3b37322b22190f04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7e7164574a3e3125323f4c5865727f7f7f7f7f7f7f7f7f7f7d7063564a3d3023170a0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000000040a0f12181c1f20232627292a2a2a2928272422211e1a14120e090300000000000000000000000000000000000000000000000000000003090e11171c1f20222527292a2a2a29282623201f1c17110f0a030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a21282c2f30353535353535353535352f2e2b272019100700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313d4a56626c71727272727272727272716c6155493d3024313e4a56626d72727272727272727272706b6054483c2f2216090000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000040a0f161b1d23282c2d30323436363737363533312e2d2b26211e1a140d0802000000000000000000000000000000000000000000000002080d141a1c22282b2d2f323436363737363432302d2c28231c1a150e08020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810161c2023242828282828282828282823221f1b150f070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915212e3a45505a626565656565656565656564615a5045392d222e3a46515b62656565656565656565656360594f44382c2013070000000000000a1724313d4a5764707d8a97a3b0b2b2a99c908376695d5043362a1d1003000000000000000000000000060b151b21272c2e34383a3c3f41424344434342403e3b3a37312d2a251f19140d05000000000000000000000000000000000000000000050c13191f262a2d3338393c3f414243444343413f3c3a38342e2b262019140d05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b101416171c1c1c1c1c1c1c1c1c1c1615130f0a04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d29343f48505658595959595959595959575550483e33281e29343f4951565859595959595959595956544f473d33271c10040000000000000a1724313d4a5764707d8a97a3a6a6a6a69c908376695d5043362a1d100300000000000000000000020a111720262b323839404546494c4e4f505050504f4d4b4846423c3a36312a251e170e0800000000000000000000000000000000000000080e171e252a3136383f4446494c4e4f5050504f4e4c4946443f3837312a251f170e08000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407090a0f0f0f0f0f0f0f0f0f0f090806030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4a49453e362c2218232d373f464a4c4c4c4c4c4c4c4c4c4c4a48443d352b21160b000000000000000a1724313d4a5764707d8a97999999999999908376695d5043362a1d1003000000000000000000030b141c222832373d43484b515356595a5c5d5d5d5c5b5a5755534d4846423b363029201a110a010000000000000000000000000000000009111a202930363b42464a505355585a5c5d5d5d5c5b595653504a47433c363029201a120a0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020202020202020202000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3e3d39332c241a111b252d343a3e3f3f3f3f3f3f3f3f3f3f3d3c38332b23190f05000000000000000a1724313d4a5764707d8a8c8c8c8c8c8c8c8c8376695d5043362a1d10030000000000000000030c151d262d333c43474f54545c6063656769696a6a69686664615f5754534d46413b322c231c130a01000000000000000000000000000009121b232b323a41464d53545b6062656769696a6a69676563605c54534e46413b322c241c130a02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b22292e313232323232323232323231302d28221a1209131b23292e3132323232323232323232302f2c272119110800000000000000000815222f3b4855626e7b7f7f7f7f7f7f7f7f7f7e7164584b3e3125180b0000000000000000020c151e272f383f444e53596063666d6f727475767776767573716e6966615e57524c443e362e251c130a0000000000000000000000000009121b242d353d444c52575f61666c6f7274757677767674726f6d66625f58524d443e362e251c140a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3844515c667986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000911181d2124252626262626262626262423211d171008010911181e2224252626262626262626262322201c160f080000000000000000000814212e3a47535f696e737373737373737373716c6156493d3024170a00000000000000000a141e273039424a50585f626b6f75797c7f81828383838382807e7b77736e69615e5650483f372e251c1108000000000000000000000007111b242d363f474f565e61696e74797c7f818283838382817f7c79746f6a615e56504840372e261c12090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3a4653606d798699a3afbbbaada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c11151718191919191919191919171714110c05000000060d12151819191919191919191919171613100b050000000000000000000006121e2b37424d575f6266666666666666666664615a5045392d2115080000000000000006111c263039424b545b606a6f767c8185898c8d8f9090908f8e8d8a8884807b746e68615a51493f372d231a0d04000000000000000000040e19232d363f48515960686d747b8084888b8d8f9090908f8e8c8985817c746e68615a524a40382e241b0f0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f3a4754616d7a8794a0b5c0baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0b0a08050000000000000106090b0c0c0c0c0c0c0c0c0c0c0a090704000000000000000000000000020e1a26313c454d5355555d60646565625f58585650483e34281d1101000000000000030c17232e38424b545c666c737c83898e9297989a9c9c9d9d9c9b999796918c86817a706c635b51493f352c1f160c0100000000000000020c16202b353f48515b626b707a81878d9197989a9c9c9d9d9c9a9897928e87817b716c635c524a40362d21180e0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020608080a090706040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366544a3f3c4955626f7c8895a2afbbbfb4aa93877a6d6054473a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d384149535b60676d7072716f6a625f584e463d31281d13070000000000000a151e28343f4a545c666d787f8790949b9fa2a9a7a8a9aaa9a9a8a6a8a09e99928e857e726d635b51473e31281e13080000000000000008131e28323d47505a626d727d858e93999ea1a9a7a8a9aaa9a9a7a9a29f9a938e857e736e645c52483f332a201509000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e12141517161413100c07010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b4a79b8e8174665b5046464d5764717e8b97a4b1bebaaea29886796d6053463a2d20130700000000000000000000000000000000000000020608080b0e0f1011100f0e0c09080603000000000000000000000000000000000000000000000000000000000000000000000000000005080a0b1212121212120f0e0c08040000000000000000000000000000000000000000000000030f1b27333f49535b656c727a7d7f7e7c766f6a60584e433a2f24180d010000000006111c26303844505c666d78818c92999fa6abadb3b4b5b6b6b6b6b5b3b2acaba39f9792887f726d63594f433a2f24190d010000000000010d1924303a444f59626c727f8792979fa4abadb2b4b5b6b6b6b5b4b3adaca49f97928a80736e645a50453c31261a0e050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b10151a1e21222323201f1d18120d0802000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7ab9e9184786c60575353555f6975828e9ba8b5c1b8ac9f928579665c5044382b1f1206000000000000000000000000000000000104090e121415181a1c1d1d1d1c1b191615130f0a0502000000000000000000000000000000000000000000000000000000000000000000060c111517181e1e1e1e1e1e1b1b18140f090200000000000000000000000000000000000000000005121f2b3744505b656c777f868a8c8b88837c6f6a60554b4035291d1104000000000c17232e38424f59606d78818e939fa3abb0b8babec0c2c1c0c1c2c1c0bdb9b5afa9a19a938c7f726b61564c4135291e1308000000000005111d2935414c56606b717e8b9399a1a9afb5b9bec0bfbdbdbdbfc1bebab6afa9a29f928c80736d62574e42372b21160b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810161c1f262b2e2f302f2d2c29241d19130c040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b9ada1968a7e716962606061676e7b87929facb9c4b7ab9e9184786b544a3f34281c1003000000000000000000000000000001080d11151a1e21222527292a2a2a29272522211f1b15110e08020000000000000000000000000000000000000000000000000000000000000910171d2124252b2b2b2b2b2b282725201a130b030000000000000000000000000000000000000003101c28343f4a54606c77818c929898989590867c6f675d5145392c20130600000003101c28343f4a54606b73808d939ea5afb5bdc2c0bbb9b6b4b3b4b5b8babec5c0bbb3aca49f93887d70685d52453a2f24190d01000000000713202d3946525d68707d87929fa4abb3bbc0bcb8b7b3b1b0b1b2b6b8bcc0bbb3ada49c928b7e716a5f53473d33271c1002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000109111a21282c31373a3b3d3c3a39352f29241e160e0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bdb2a89e91857b736e6d6d6e7179839099a3afbbc2b5a99c8f8276695c4f432e23170b0000000000000000000000000000070c13191d20262b2d2e3234363637363634322f2e2b26201e19140d070100000000000000000000000000000000000000000000000000000009121b22292d30313838383838383534312c251d150b0200000000000000000000000000000000000006121f2b3844505c66727f8b939fa2aaa79f989184796d6053473a2d20140700000006121f2c3844505c66707d88939fa6afbbc0c0bbb5afaca9a7a7a7a9abadb3b9bdc4beb6afa49a92857a6d60554c4135291d110400000005121e2a36424d57616d7a849199a3afb5bdbfbab1acaaa6a4a3a4a5aaabb1b9bdbebaaea49f92867b6e62594f44382c1e13080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009131b232c33383c4247484a494745403935302820170f05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c4b9ada19791857f7b79797b7e8490959fabb5c0bfb4aa998d8073665a4d4033271a06000000000000000000000000030b12181e24292c31373a3b3e414243444342413f3c3b37322d2a251f18120c040000000000000000000000000000000000000000000002060808101b242d34393d3e45454545454542403d372f271d13080706040000000000000000000000000000000713202d3a4653606d7985919ea5aeb4b1aaa1968c7f7265594c3f3226190c0000000713202d3a4653606d7884919aa4afb8c1beb6afaba39f9d9b9a9a9c9fa2a9acb2bac3c0b6aca1978d8073675d5145392c2013060000000714212d3a46535e6974808d96a1abb5c0bcb4aea7a09d99979697999d9fa7acb2babfbaaea2988f82766b6054483a3024190d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111b252d353e44484d5355565653514b46413a322921170c030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c9beb3a9a198928c888686878b91969fa7b1bdc7baaea2988a7e7164574a3e3124170b0000000000000000000000060c151c23282f35393c4247484b4d4f5050504f4e4c4947433c39363029241d160d070000000000000000000000000000000000000003090e12141517222d363e45494b5151515151514e4d4841392f251a151313100c07000000000000000000000000000916222f3c4955626f7c8897a1adbabfbcb2a99c8f8276695c4f4336291c10000006121f2b37434e5864717e8b96a0acb6c0beb6aca49f9992908e8d8e8f92979ea1a8b1b9c3beb3a99f92857a6d6054473a2d22170b0000030f1b27333f4953616e7b86929fa9b2bdbdb4aaa29f95908c8a8a8a8c90959ea1a8b2bcbfb4aa9f94897d7063564c4135291d110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050f1a232d373f474f55575f626362605d55524c443b33291e150b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c4bab2acaaa29f9995999399989ea1a8b1b9c3c0b5ab9f92867a6d6053473a2d20140700000000000000000000080f181e272e343a4145474d5355585a5c5d5d5d5c5a5855534e4746413b352f281f1910090000000000000000000000000000000000060e151a1e21222129343e485056585e5e5e5e5e5e5b59534b41372c2122201f1c18120b0300000000000000000000000a1724303d4a5763707d8a96a9b3becac3b7aa9d9084776a5d5144372a1e1100000814212e3a47535f6a7783909da8b2bec0b6aca49a938d868381808182858a9196a0a7b1bcc5baaea2988b7e7165544a3f33281c0f030005121f2b3744505b6573808d99a3afbbc0b5aba298928a83807e7d7e7f83899196a1a9b3bebcb0a69c8f8275685d5246392d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b16212b353f4951596163696e706f6d67615d564d453b30271c120700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bdb2a8a19ea1a8a6aba49fa4ababacb2bac3c2bbafa4998e8175675d5145392c20130600000000000000000008111a212a303940444c5254575f61656769696a69696765625f5854524d454039312b221b1209000000000000000000000000000000090f1820262b2e2f2e2d3945505a62646b6b6b6b6b6b68655d53483d312d2e2d2c28231d150c03000000000000000000000916232f3c4956626f7c8997a2adbac1bdb3a99c8f8376695c504336291d1000000815222f3b4855626e7b8895a0acbac3bbafa49a9388807a7674747476797e849095a0aab4bfbeb4aa9c8f8275665b5044382b1f1206000613202d394653606c7884919eabb5c0bbafa49992867e787371707172777c849197a2adbac2b9ac9f92867a6d6154473a2e21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c27333d47515b626b70777b7d7c7a746d685e574d42392e23180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b9aca19691969ea5aeafacafb5b7b9bdc4bebab1a79f93877c6f62554b4035291d1104000000000000000008111a232b333c424a51565d6066696e7174757677767574726f6a66615e56514b433d342d241b12090000000000000000000000000009121a212a31373a3b3a373d4956626c71787878787878756f65594d40363a3b3a38342e271e150b000000000000000000000713202d3a4653606d7985929fa6afb5b3aba2978c7f7366594c403326190d00000c1926333f4c5966727f8c99a7b1bcbfb4aa9f93887e746e68686767666d717a839098a3aebac5b8ac9f9285796c605346392d201306000916232f3c4956626f7c8997a1adbdc6b9ac9f93877d716c65646364666b6f7b85929fabb4bfbbafa3998a7e7164574b3e312418070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202c38444f59626d727d8488898986817a6e695e544a4034281c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7ab9e91848f939da4acb1b7b9bbbbb9b8b4aea79f958d80746a6054433a2f24180d0100000000000000060f1a232b353d454e545c60686d72777b7e808283838382817f7c78736e68605d554e463f362d241b11070000000000000000000000040e1a242c333c42474847423e4b5864717e8484848484848175685b4e424246484645403930271d120700000000000000000006131f2c3845515c6673808c949ea5a8a9a19992857a6d6154473a2e2114070004101c2834404a546875828f9ba8b5c0baaea3988d80746c615e565a545c60686e7b86929facb9c5baaea298887b6e6255483b2f221508000c1926323f4c5965727f8c98a9b2bebfb4aa9a8e81746b605b535757596069727f8c99a3aebac0b5ab9a8d8073675a4d402e23180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4854606b727f8891959698928d847b6e665c5144382c1f1206000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7f828d929da0a7aaacafafacabaaa29f959083796d60584e4331281d130700000000000000030c18212b353d474f575f666d727a7f84888b8d8f9090908f8d8b8884807b736d67605850483f362d23190d03000000000000000000020c16202c363e454e5355534e464b5865717e8b919191918f8275695c4f454d535553514b43392e23180c03000000000000000004101c2834404b54606d78828e93999b9a9792877e70685e5246392d2013070006121f2c3844515c667884919eabb3b3b3ac9f92867a6d615a524c4d4a50565f6974818e9ba7b4c1bfb4aa978a7d7064574a3d3124170a000f1b2835424e5b6875818e9ba8b4c1baaea298897c6f635950494a4b4f57606d7a86929facb9c3b6a99c90837669544b4034281c10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121e2b37424d5763707d88939aa0a7a39f969083786d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e79808990959a9d9fa3a39f9e9b98928c837a6d675d51463d321f160c01000000000000000b151e2a333d474f59606a6e787f858c9195989a9c9c9d9c9c9a9896918d8680796f6a625a50483f352b1f150b01000000000000000008131e28323e4850575f625f57524c5864717e8b979e9e9b8e8175685b4b51575f61605c554b4034281e150a0000000000000000000c18232e3944515c666d7981898d8e8e8b857d706c61564c41362a1d1105000713202d3a4653606d7986939fa6a6a6a6a69c8f8275685e524641413f444d5764717d8a97a4b0bdbeb1a5988b7e7265584b3f3225180c00101d2a3643505d697683909ca9b6c3b8ac9f9285796c6053463f3d3e45515d677683909ca9b6c3b8ab9f928578665c5145382c1f1306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212d3a47535f697783909aa4acb1aea8a0958b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e72747d83898d9092999992918f8b857f796d685d554c41342b200d040000000000000007121c27303c464f59606b707c838c92979da0a7a7a8a9aaa9a8a7a9a19e98928d847c716c625a50473d31271d120700000000000000030c1924303a44505a616a6e6a615e565764717e8a97a4a79a8e8174675b555d60696e6d675c51453c30261c1106000000000000000007121d2834404a545d676d757c8082817e7a706b61594f443a3025190d01000815212e3b4854616e7b87999a9a9a9a9a9a998c7f7366564c413630343b4855616e7b8894a1aebbbfb2a5998c7f7266594c3f3326190c00111e2b3844515e6b7784919eaab7c3b6aa9d908377655b5044372d35414c556774808d9aa7b3c0baaea29886796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b8895a0acb6bebab1a79c8f8376695c504336291d10030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e726b70777c80848687878685827e7a726d675d564c433a2f22190f00000000000000000c18232e39424e58606b707d8690959fa2a9acb1b3b5b6b6b6b5b4b2adaaa39f9691877e716d62594f43392f24180c020000000000000a151e2935414c56616c717b746d68605b64707d8a97a3a79a8d8074675a61676d737b796d60584e42382e23170c0300000000000000000c18232e39424b555d606a6f737574716d6761594f473e32291e130800000815222f3b4855626e7c888d8d8d8d8d8d8d8d8b7e7164584b3e30252d3a4754606d7a8793a0adbabfb3a6998c807366594d4033261a0d00121f2c3845525f6b7885929eabb8c2b5a89b8f82756853493f33272f3f4c5966727f8c99a5b2bfbeb3aa94877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1723303d4a5663707d8996a7b1bec7c3b7ab9e9184786b5e5145382b1e12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265636b6f7477797a7a797875716d68605c554c443a31281e10070000000000000004101c2834404a545f6a707d879298a0a7adb3b8bcc0c1bfbebfc1c0bdb9b4aea8a099928b7f716b60554b4035291f1409000000000006111c26303845525d68717e86817a726c6663707d8a96a3a6998c807366626c7179808680736a5f544a3f3428201509000000000000000007121c273039434b5158606266686765605d554f473e352c20170c0200000814212e3b4754616e7a808080808080808080807c6f6255483c2f222d3a4653606d798693a0acb9bfb3a6998c807366594d4033261a0d00121f2c3945525f6c7885929fabb8c1b4a79b8e8174685b4e412d22323f4b5865727e8b98a5b1bebbaea195887b6e6255483b2f221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707c8999a3afbbc4c0b7aa9e9184776b5e5144382b1e11050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e726559606367666c6d6d6c656865615e56514b433a32281f160c000000000000000006121f2c3844515c666e7c869299a2aab1babebeb9b8b4b2b1b2b4b8babebfbab2aba39f92877d6f675d51453b30251a0e01000000000c17232e38424f59606d7a85928e857e786f6b707c8996a3a5998c7f726a6e767e848c92877c6f665c50443c31261a0e0200000000000000000b151e28313940454e54565a5b5b5854514c433e352c231a0e050000000714202d3a46525e696e737373737373737373736f6a5f53473a2e202d3a4653606d798693a0acb9bfb2a6998c7f7366594c403326190d00121f2c3945525f6c7885929fabb8c1b4a79a8e8174675b4e413428313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212e3a4754616d7a86929fa9b2b8b7afa59b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265585456545b606161605b535854524c454039312820160d040000000000000004111d2935414c55606d78839098a2abb4bcc0bbb3adaba7a5a4a5a7abadb3babfbdb5afa3999184796d60574d42362a1d130700000003101c28343f4a54606b74818e9797928b837c746f7c8996a2a5988b7e72737c828a9196999083786d60574d42372b1e12060000000000000000030c161f282f353d4347494d4f4e4b4745413a312c231a11080000000005111e2a36424d575e6167676767676767676767625f584e43372b212d3a4754606d7a8793a0adbabfb2a5988c7f7265594c3f3226190c00121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3946525e6875828f97a1a8abaaa59d93897d7063564a3d3023170a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b494a505354545350494b4746413a342f271f160e0400000000000000000613202c3945515d67727f8c95a0aab3bdbeb6afa9a19e9b9897999b9fa2a9aeb4bcc0b5aba0968d8074695e52463a2f24180d01000006121f2c3844505c666f7c88939fa29e959087817a7c8995a2a4978b7e7a80878f949ea1a0958c7f72695f53473a2e211408000000000000000000040d161d242932373b3c4042413e3a39352f281f1a11080000000000020e1a25303b454d52545a5a5a5a5a5a5a5a5a5a55534e463c3126232f3b4855626e7b8895a1aebbbeb1a4988b7e7165584b3e3225180b00121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f2215080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d2935414c56616e7b8591969d9e9e9b938e81746b6054483c2f221609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3f4446474746443f3e3a39363029231d150d040000000000000000000714212d3a4754606d7a85929fa7b1bcc0b6aca49f97928e8c8b8c8e92979fa2aab4bcbdb2a89f92867b6e61554b4035291d110400000713202d3a4653606d7883909aa3aba7a09a938e85818d9aa7a89b8e81858d92999fa6aba69f92867b6e6255483b2f22150800000000000000000000040c121820272b2e2f333534322d2c29241e160d080000000000000009141f29333b4246474d4d4d4d4d4d4d4d4d4d4847433c3432322e343f4a5464707d8a97a3b0bdbeb3a996897d7063564a3d3023170a00121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1925303a46535e696f7c848c9091918e8981786d60594f44382c201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3338393a3a3937332d2e2d2a251e18120b0300000000000000000005121e2a36424d5765727f8b97a2adb9c3bbafa49a938d85817f7e7f81858b9298a2aab4bfbbaea3998d8073675d5145392c20130600000a1623303d495663707d868e92999fa4aca49f98928d929da9aa9e938e91979fa3aba79f9d9490898073665a4d4033271a0d000000000000000000000001070d151b1f22232728282521201d19130c040000000000000000020d17202930363a3b404040404040404040403c3c3f3f3f3f3f3f4045505b6674808d9aa7b3c0b9ada197877b6e6154473b2e21140800121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e2a36424d575f6a6f797f838584817d746d665c51473d33271c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f322b2d2e2e2d2b272221201d19130c0701000000000000000000000714212d3a46535f697783909da9b3bebaafa59f9388807a7472717274797f869298a2aebabfb5ab9f92857a6d6053473a2d20140700000916222f3b4854606b707b81878e939a9ea6aaa29f9a9da4aeafa59e9b9ea1a9a7a09d959089837d736e63574b3f3226190c00000000000000000000000000040a0f1315161a1c1b181413110d080100000000000000000000050e171f252a2d2e34343434343434343d4348494c4c4c4c4c4c4b5158606c7884919eaab7c4b8ab9e918578695e52463a2d20140700121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f2215080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a25313b454e585f676d7376787775706b605c544a40352b21160b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225202121201f1b171413110d08020000000000000000000000000815222e3b4855616e7b8895a0acbbc5b6aa9e938b7e736d67656466676d727c86929fabb4bfbaaea2988a7d7164574a3e3124170800000713202c38444f5960696e747b81878f949c9fa6aba7a9aeb6b7afaaa8aba8a09e95908a837d766f6b635c52473b2f23170a000000000000000000000000000000030608090d0f0e0b0706040100000000000000000000000000050d141a1e2021272727272727323d474f5456595959595959545c606a717e8b96a0acb9bcb1a79a8e817467574d42362a1e110500121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f29333c464e555d60666a6b6b68636059514a42392e23190f0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f322518141413120f0b0607050100000000000000000000000000000b1825323e4b5865717e8b98a7b1bcbdb2a89b8e81756c605d5558555d606a727f8c99a3aebabfb4aa9a8e8174675b4e413024190d010003101b27323d474f575e61696e757c828990949fa9b3b5bac0c1bab6b5aba096918a837d77706b636059524a40352a1f1307000000000000000000000000000000000000000000000000000000000000000000000000000000000002090e1114141a1a1a1a1f2c38434f59606365656565656566666d727c85929fa8b2bdb8aba095897d7063564a3d30251a0e0200121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030d17212a343c434b5154595d5e5e5b56544f44403930271c11080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c07060503000000000000000000000000000000000000000e1b2834414e5b6774818e9aa7b4c1b9aca196887b6f625a514b4b4b5158606d7a86929facb9c3b7aa9d9084776a564c4135291d110500000b16212b353d454d52575f626a6f757d829097a1adb9c6cbcbc7bbafa39991847e78706c636059544f4740382e24190e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000020507080d0d0d15222f3b4854606b6f7272727272727375797f869297a2adbab8aea49d9083776b6054483c2f1f14090000121f2b3845525e6b7885919eabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050f18222a313a4145474c5052514e4948443d342e271e150b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000101d293643505c6976838f9ca9b6c2b7ab9e9184786a5f5345403e4045515d6776838f9ca9b6c2b8ac9f928579685d5246392d201307000009141f2a333c42464e545960636b70767d85929eabb8c5d0d1c5b9ac9f92867f79716d66605c54504a423e352c21160b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101091623303c4956636f7d7f7f7f7f7f7f8082858b9298a2a9b3b7aea59d92897d7063594f44382c200d020000111e2b3744515e6a7784919daab7c1b4a79a8e8174675b4e413025323e4b5865717e8b98a4b1bebfb4aa94877b6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000710181f282f35393a40434544423d3b383228231c150c03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c2b5a89b8f827568584e43352f35414b556673808d99a6b3c0baaea298877a6d6154473a2e21140700020e1a26313c454d535860626b6f767d838a9297a1adb9bec5c6bfbaafa399928b847e78716d66605b544f473e33281c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c8c8c8c8c8c8c8e92979fa2aab3b0aba49d938d80746b6054473d33271c10000000101d2a3743505d6a7683909da9b6c2b5a89c8f827569574d42362e303f4c5965727f8c98a5b2bfbaaea39886796d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070d161d24292c2d3337383835302f2c272118120b0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000121f2c3845525f6b7885929eabb8c1b4a79a8e8174675b4e41383a3a3f4c5865727f8b98a5b2bebfb4aa94877b6e6154483b2e2115080005121e2b37424d575f616a6f767c828990959ea1a9abaeb3bcbcb4aeacaba39f96918b847e78716c6661594f44382c201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c9898989898999b9fa2a9aeb4b0a69f9c928d81786d60594f44352b21160b000000101c2936434f5c6976828f9ca9b5c2b7aa9d918477695e52463c3b3b424f596774818e9aa7b4c1b9ac9f928679675d5145392c1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c13181d2021262a2b2b282322201b160c07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7adadada5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e3f444647474b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000714212d3a46535f696e757c82898f949d9fa7aaa29fa2aab3b4aaa39fa3aaa8a19e96918b847e78706b6155483c2f231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c99a5a5a5a5a6a8abadb3bab2a89f94908981786d665c51473d33231a0f050000000e1b2734414e5a6774818d9aa7b4c0b8aca095877b6e61574e4947484c54606b7784919daab7c4b7ab9e9184786b554b4035291d1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d111314191d1f1e1b161613100b0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa0a0a0a0a0988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4a50535353535864717e8b97a4b1bebbaea195887b6e6255483b2f221508000815222e3b4855616e7b81898f949c9fa6aba39f989298a2aeaea39892989fa3aaa8a09e96918a837d7063574a3d3024170a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c99a6b2b2b2b3b5b8babeb8aca09690827d746d665c544b40352b211108000000000c1825323f4b5865727e8b98a5b1bebdb1a8998c7f73696058565455565d666f7c8995a0acb8c1b5a89b8e8275685b4f422f24180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010406070d1012110f0a090704000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d939393939393938b7e7265584b3f3225180c0000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4a545c606060606064717e8b97a4b1bebbaea195887b6e6255483b2f221508000815222e3b4855616e7b86929c9fa6aba69f99928d85929fabac9f92868c92989ea5aca8a09d948b7e7164584b3e3125180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c99a6b3b4b5b6b9babfc4b7aa9d91847d756e685f584e453b2f261b1106000000000a1623303d495663707c8996a8b2bdc3b8ac9f92867b6f6a6462616263686d7883909da7b1bcbcb1a7988c7f7265594c3f32261907000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774808686868686868686867e7265584b3f3225180c0000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a505c666d6d6d6d6d6d717e8b97a4b1bebbaea195887b6e6255483b2f221508000714212d3a46535f69737f8c96a0a9a19e948f87807d8996a2a4978b7e80868e939da0a7a2988f82766c6256493d3024170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c99a6a7a7a8a9acaeb4b9b8aca0969189827a6e6a5f574d41382d22170b000000000714212e3a4754616d7a8796a0acb8c5baaea29891847c75716f6e6e70737a828f95a0acb9c3b8aca095897c6f6256493c2f231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d797a7a7a7a7a7a7a7a7a786d6053463a2d2013070000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a53606d787a7a7a7a7a7a7f8b98a5b1bebbaea195887b6e6255483b2f2215080005121e2a36424d57606d7984919e9f96918a827c737c8995a2a4988b7e737b818990959f9f92867b6e615a5045392d211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c999b9b9b9b9c9fa3aaadb2b2a8a09d948f857c6e695e53493f33271b0f030000000713202d3946525e687784919daab7c4bfb4aaa1969187827e7c7a7b7d80858f949fa7b1bcbeb3a99d9184776a6054473b2e2215080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c676d6d6d6d6d6d6d6d6d6d6d665c5044382c1f12060000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8686868686868b919ba7b3bfbbaea195887b6e6255483b2f22150800020e1a26313b45515c67707d8a93928d847e766e707c8996a3a5988b7f726e757d838b92958c7f72695f53483f34291d1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c8e8e8e8e8e9092989ea1a8b0b2aca69e9791857b6e655b5044372b1f140900000005111e2a36414c566774818d9aabb5c0c6bcb2a9a199938f8a898788898d92979fa6b0b9c2b9ada1978b7e7265584e43372b1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b555c60606060606060606060605c544a3f34281c10030000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b9393939393989ba3acb7c3bbaea195887b6e6255483b2f221508000009141f2834404b55616b75828f878079716c63707d8996a3a5998c7f72666b70787f858d83786d60574d42362d22170c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010a1724313d4a5764707e81818181818283868b91969fa6b0b8b0a9a1978f82776c6053463b31261a0e020000010d1925303d4a5764707d8a99a3afbbc7c4bbb2aba49f9c9795949596999fa2a9b0b8c1b8afa59e9285796d6053473d32271b0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e39434b515353535353535353535353504a42382e23170c000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a0a0a0a0a5a7acb5bec9bbaea195887b6e6255483b2f2215080000030c18232e39434f59616e7b827c736d676163707d8a96a3a6998d80736660666d727a817c6f665c50453b31241b1106000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002060a0c0c0e0e1623303c4955616c7074747474747576797e8490949fa8b2bbb3a99f948a7d7064574d42362a1e12050000000814212d3a4754606d7a86929facb9c5cdc4bdb5afaca8a4a2a1a1a3a6abadb3bbbebab0a69d938a7d70675d5145392b20150a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d27303940454647474747474747474746443f3830261c1106000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a5adadadb1b3b7bec7c8bbaea195887b6e6255483b2f22150800000007121d27303e46535e696e766f6a605d5564717d8a97a4a79a8d807467545c60686d746f6a5f544a3f332a1f12090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070d121618191a1a1a202d3944505a6164686868686868676d717a829096a1adb9bbb0a69d908376695f53463a2d2114070000000613202c3945525d6875828f9ca9b3becad0c7c0bbb9b5b1afadaeb0b3b8babdb9b4aea69e948e81746c61554b403529190f04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b151e272e34383a3a3a3a3a3a3a3a3a3a3a38342e261e150a00000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a5b1b9b9bcbcbcbcbcbcbbaea195887b6e6255483b2f221508000000000b151e2a36424d575e6169625f58515764717e8a97a4a79a8e8174675b50565e6167625f584e42382e21180e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000010a12181e2225262727272728333e485055575b5b5b5b5b555d60686d7a84919eabb5c0b8ab9f95887b6e6155483b2e22150800000004111d2935414c5664717e8a97a2adbac6d3d2ccc0b9b5b3b1b4b4b5b5b5b3b2acaaa29f938f82796d605a5043392f2418070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c151d23282c2d2d2d2d2d2d2d2d2d2d2d2c28231c150c0300000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a5afafafafafafafafafafaea195887b6e6255483b2f22150800000000030c1a25313b454d53545c55534e4b5864717e8b979d9d9b8e8275685b4f4c52545a55544e463c30261c0f06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a131c232a2f3233343434343434363e44494a4e4e4e4e4e4b51565e68727f8b99a3afbbbcb1a7988b7f7265584c3f3225190c000000010d19242f3a4653606d7985929fabb8c2cccac0b6aea8a6a5a7a8a8a8a8a6a8a09e98928b82796d675d51473e31271d1207000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b12181c1f20202020202020202020201f1c17110a030000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a2a2a2a2a2a2a2a2a2a2a2a2a195887b6e6255483b2f221508000000000009141f29333b4246484f4847434b5865727e8b909090908f8275695c4f4146474e4947433c342a1e150a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121c252e353a3e3f4141414141414141413e3d414141414140454c56606d7a86929facb9c1b4a79b8e8174685b4e4135281b0e0200000008131f2c3845515c6774818e9aa6b0bbc7c5b9aea49d9a989a9b9c9c9b9a9896918c857f776d675d554b40352c1f150b010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070c1013131414141414141414141312100c0600000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b969696969696969696969696969695887b6e6255483b2f2215080000000000030d17212931363a3b433c3a3e4b5764717e8384848484838174675b4e41393a413c3b37322a22190c03000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d18232e373f464b4c4d4d4d4d4d4d4d4d4d4a49453e36352f353a45515d677783909daab6c3b6a99d9083766a5d5043372a1d100400000004101c2834404b55626f7c88949fabb7c3c1b5a89d928d8b8d8e8f8f8e8d8b88847f7a726c655d554b43392f231a0d030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040607070707070707070707070603000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e89898989898989898989898989898989887c6e6255483b2f221508000000000000050f171f252a2d2e362f303d4955616c71777777777777746f64584c40332e342f2e2b26201910070000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121e2a353f495157595a5a5a5a5a5a5a5a5a575550483e33282935404b556875818e9ba8b4c1b7ab9e9184786b5e5145382b1e1205000000000c18232e3947535f6a76828f9ca7b1bcc0b3a69a8d807f8181828282807e7b77736d68605b534b433a31271d1108000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a54616e7a7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c796d6053473a2d20140700000000000000050d141a1e212129222d3945505a61646a6a6a6a6a6a67645c53483c30212722221f1b150e0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a16222f3a46515b636667676767676767676764615a5045392d242f414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12060000000007121d2b37434e5863707d8995a0acb8c3b6a99d908376747575757573716e6a66615d565049413a31281f150b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030709090b0b0b0b0b0b0b0b0b090806030000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a525e686e6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6d675d5145382c1f1306000000000000000003090e1214151c1d28333e485055575d5d5d5d5d5d5b58534a41362b201b1615130f0a040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323e4b57636d72747474747474747474716c6155493d302734404d5a6773808d9aa6b3c0b9ac9f9286796c5f5346392c20130600000000000f1b26323c4855616b7783909da9b2bdb8ab9f95897c70686969686765625f5854524c443f382f281f160d0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f1315161818181818181818181515120f0a04000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4c565e616363636363636363636363636363636363605d554b4035291d100400000000000000000000020507080c17222c363e45494b5151515151514e4c4841382f251a0f0908060300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8080808080808080807e7164574a3e2f2434404d5a6773808d9aa6b3c0b9ac9f9286796c5f5346392c20130600000000000a15202c38444f5964717e8b96a1adb9bcb1a79c8f82756a5f5c5b5a5855534e4746413a332d261d160d0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070f161b1f222325252525252525252522211f1b150e060000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4c5254565656565656565656565656565656565653514b43392f24180c00000000000000000000000000000006101a242c33393d3e44444444444441403c362f261d1308000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2a3744505d6a77838d8d8d8d8d8d8d8d8d817568554b40352e343f4a546874818e9ba7b4c1b8ac9f9285796c5f5246392c1f1306000000000004101c27333d4653606d7984919eaab4bfb7aa9e94887c6f62574d4d4b4847433c39353027221b140b040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007101921272c2e2f3131313131313131312f2e2b262018100600000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41464749494949494949494949494949494949494745403931271d12070000000000000000000000000000000008121a22282d30313737373737373433302b251d140b01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101d2a3643505d697683909a9a9a9a9a9a9a908376675d51453c3b3b44505c6676828f9ca9b5c2b8ab9e9285786b5f5245382c1f12050000000000000b161f2c3845515c66727f8c98a2aebabbb0a69b8e8174695e53463e3b3a37312d29241e17110a0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040f19222b32383b3c3e3e3e3e3e3e3e3e3e3c3a37312a22180e04000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41393b3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3a38352f271f150b0100000000000000000000000000000000000810171d2123242a2a2a2a2a2a282724201a130b02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f1b2835424e5b6875818e9ba7a7a7a7a79f9286796d60564d4848484c55606d7985929fabb8c4b7aa9e9184776b5e5144382b1e110500000000000004101c2834404b54606d7a85929fabb5c0b9ac9f92867b6e61564c41352e2b26201d19130b060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a16212b343d4348494b4b4b4b4b4b4b4b4b4847433c342a20150a000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342e30303030303030303030303030303030302d2c29241d150d0300000000000000000000000000000000000000060c111417181e1e1e1e1e1e1b1a18140f080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c99abb5b3b3aea3988b7e71685e57555455565e67707d8a97a2adbac2b6a99c8f8376695c504336291d1003000000000000000c18232e3945525d6874808d99a3afbbbbafa3998d8074685d5245392f231a15110d0802000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27323d464e545658585858585858585855534e463c31261b0f030000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272323232323232323232323232323232323201f1d18120b030000000000000000000000000000000000000000000005080a0b1111111111110e0d0b0803000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a99a3afbbbfb4aa9e91847a6e696462616263686d7984919da9b3bec0b5ab9a8d8074675a4d4134271a0e010000000000000007121d2935414c56616e7b87929facb9c0b5ab9f92857a6d60554b4034291c110601000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007131f2c38434e586062646464646464646464625f584e43372b1f12060000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b16161b1f22232727272727272727272721201d19130c0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212e3a4754616d7a86929facb9c4b9ada19690837b74706f6e6e70747a829096a0acbbc5bbafa3998a7e7164574b3e3124180b0000000000000000000d19242f3a46535e6975818e9ba6b0bbbaaea2988c7f73675c5145382d22170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222e3b4854606a6f7171717171717171716f6a5f53473a2e2115080000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b1920272b2e2f343434343434343434342e2d29251e160e04000000000000000000000000000002050708131313131313131313130b0b090501000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3946525e687683909ca9b2bebdb2a9a0959086817d7b7b7b7d808690949fa8b2bdc5b9ac9f92867a6d6154473a2e21140700000000000000000008131e2a36424d57626f7c88949fabb7bfb4aa9e9285796d60544a3f33281c0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c7e7e7e7e7e7e7e7e7e7c6f6255483c2f2215090000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342719222b32383b3c414141414141414141413a3935302820160c02000000000000000000000003090e12141520202020202020202020181715110c0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d2935414c5664717e8b97a1adb9c2bbb1a7a098928d8a8887888a8d92989fa6b0bac3bdb0a69c8f8276685d5246392d201307000000000000000000010e1a25313b4754606a7683909ca8b1bdb9ada1978b7e72665b5044382b1f160b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818b8b8b8b8b8b8b8b8b7f7366594c403326190d0000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427202b343d4347494d4d4d4d4d4d4d4d4d4d4746413a32281e130800000000000000000000060d141a1e21222d2d2d2d2d2d2d2d2d2d2524211d1811090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1925303a4753606d7984919ea6b0bbc3b9b1aaa39f9a97959495969a9fa2aab0b8c2bfb4ab9f948a7d7063564c4135291d11050000000000000000000009141f2b37434e5864707d8a95a0acb8beb3a99e9184786c6053463d32271c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d979797979797978c7f7366594c403326190d0000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342727323d464e54565a5a5a5a5a5a5a5a5a5a54524c443a3025190d010000000000000000060f181f262a2d2e3939393939393939393932312e29221b1209000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131f2c3845515c67717e8b949fa9b3bbc3bcb4aeaca7a3a2a1a1a3a7acaeb4bcc2c0baaea3999083766b6155443a3024190d0100000000000000000000030f1b27323c4653606c7884919da9b3beb9aca0968a7e7164594f44382c20150a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa4a4a4a4a4998c7f7366594c403326190d0000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272b38434e58606267676767676767676767615e564c4135291d110500000000000000030d18212931363a3b464646464646464646463e3d3a342d241b11060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2934404b55606c77828f97a1a9b2bac1bfbab8b4b0aeaeaeb0b3b8babfc4beb6afa49f92867c6f62594f4432281e13080000000000000000000000000a151f2b3744505b65717e8b97a1adb9bdb2a89d9083776b6054483c31261b0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b1b1b1a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272e3b4754606a6f747474747474747474746d685e5246392d2013070000000000000009141f29333b424648535353535353535353534b4a453f362d22180c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232f3944505b656e7b859197a1a8afb7bcc2c5c0bdbbbabbbdc0c5c3beb9b2aca49f928b7f726a5f53473e3320160c02000000000000000000000000030f1b27333f4953606d7985929eaab4bfb8ab9f95897d7063584e43372b1f14090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000121f2c3845525f6b7885929eabb8c1b4a79b8e8174685b4e4130252f3c4956626f7c808080808080808080807a6d6154473a2e211407000000000000020e1a26313b454d535560606060606060606060585650483f34291d11050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d27333f49535e696f7c8591969ea5abb0b6b9babfbdbdbdc0bbb9b7b2ada8a19a938c80746d62584e43352c210e0400000000000000000000000000000b17222d3845515c67737f8c98a2aeb2b2b1a79c8f82766a5f53473b31251a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000111e2b3744515e6a7784919daab7c2b5a89c8f827569574d42362b2f3f4c5965727f8c8d8d8d8d8d8d8d8d877a6d6154473a2e21140700000000000005121e2a36424d575f6c6c6c6c6c6c6c6c6c6c6c65625a50453a2e21150900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010b17222d38414d57606a6f7c848f939c9fa6a9acaeb4b0b0b0b5afacaaa9a19e9691887f746e645b51463c32231a1000000000000000000000000000000006111b2934404b55616d7a86929faba5a5a5a59f94887c6f62574d42362a1e120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000101d2a3643505d697683909ca9b6c3b7aa9e918477695e52463b3839424d576773808d9a9a9a9a9a9a9a9386786d6053463a2d2013070000000000000714212d3a46535f697679797979797979797979716c62564a3d3124170a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111b262f3b454e58606a6f7a82899094999d9fa3aaa3a4a3aba49f9d9a97918c847d736d645c52493f342a201108000000000000000000000000000000000c18232f3946525e6874818d99989898989898988e8175695e53463a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d0c0b0a07060400000000000000000000000000000000000e1b2835414e5b6874818e9ba7b4c1b9aca096877b6e61564d4644464b545f697683909da7a7a7a7a79e918478665c5144382c1f12060000000000000815222e3b4855616e7b868686868686868686867e7165584b3e31261b0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141d29333c464e585f686d757d83888c90929896969797969993908d8a847f79706b635b524a40372d22180e000000000000000000000000000000000007121d2935414c56616e7b878c8c8c8c8c8c8c8c8c867b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326191a1918161313100c070000000000000000000000000000000c1825323f4b5865727e8b98a9b3bebdb2a8998c7f72685e56535053555c666e7b87939facb3b3b3a89c8f827569544a4034281c10040000000000000714212d3a46535f69778491939393939393938e817568584e43372b1f12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b17212b343c464e565e616b70767c80838688898a8a8a89888684817d79726d676059524940382e251b10060000000000000000000000000000000000010d1925303a47535f69717e7f7f7f7f7f7f7f7f7f7f7c6f6255493c2f22160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4033262627262523201f1c18120f0a040000000000000000000000000916222f3c4955626f7c8897a1adb9c4b8ab9f92857a6e6862605b5f61676d78828f9aa4afbbbcb1a7998c7f7266594c3f2e23180c0000000000000005121e2a36424d576774818e9a9f9f9f9f9f9e9185786a5f53473a2e211506000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050f19222b343c444c525960636a6f7376797b7c7d7d7d7c7b7a7774706d66605d554f4740372e261d13090000000000000000000000000000000000000008131e2b37424d57616c71727272727272727272726f6a6054473b2e22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c40333133333332302d2c28231d1b160d0802000000000000000000000713202d3a4653606d7985929eacb6c0baada29790837a736f6c66696e7279818e949eacb6c0b8aca095887c6f6255483c2f22150700000000000000020e1a26313e4b5764717e8a9aa4afacacada197887b6f6255483c2e23170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071019222a323a41464f54585f6266666d6e70707170706e6d676763605c54514b433d352e251d140b0100000000000000000000000000000000000000020e1a26313c45505a6164656565656565656565656260584e43372b1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403c3e40403f3e3d3a38342e2b272019130c0400000000000000000006121f2b3844505c6674818d9aa4afbbbeb3a9a09590857f7b7978797b7e848e939da6b0bebcb1a79d9083776a5f53473a2e21150800000000000000000914212e3a4754616d7a87939facb9beb3a9988b7f7265544a3f34281c100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071018202830363d44484e5355545c6061636364646362605d555753514a454039312c231c130b0200000000000000000000000000000000000000000009151f2a333e485056585959595959595959595955544e463c32271b0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c47484b4c4d4c4b4946454039383229251e160e05000000000000000003101c28343f4a54626e7b87939faab4bfbcb1a7a097928c88868586888b91969da5afb8c1b8aca0958b7e7164584e43372b1f120600000000000000000713202d3946525e687783909daab7c2b5a89b8f8275665c5044382b1f12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e161e252a33383c4347484a51535556575757565553514b4a46444039352f271f1a110a0100000000000000000000000000000000000000000000030e18212d363e45494b4c4c4c4c4c4c4c4c4c4c4947433c342b20150a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594e535558595a59585653514b47433d35302820170f0500000000000000000b17232e3847535f6a75818e98a2aebac1b9b1a9a29f999993929299989ea0a8afb7c1b8aea49d9183786d6053463c31261b0f03000000000000000005111d2a36414c566773808d9aabb5bfb8ab9f9285796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050c131921272c31373a3c40444648494a4a4a49484745403d3a38342e29241d150d0800000000000000000000000000000000000000000000000000060f1b242d34393d3e3f3f3f3f3f3f3f3f3f3f3c3b37322b22190e040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659585f62646666666563605c54544e46413a322921170d040000000000000006111c2b37434e58616e7b86929fa5afb8c1bbb3adababa49f9e9fa3abaaacb2bac1b9b0a69d92897d70665c5044382a20150a000000000000000000010d1925303d4a5763707d8a99a3aebbbaada297897c6f6256493c2e23180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080d161c20262b2e2e34383a3b3d3d3e3d3d3b3a38352f2d2c28231c18120b0300000000000000000000000000000000000000000000000000000009121b22282d3031323232323232323232322f2e2b2720191007000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736660666a6f7173737271706d66626058524c443b33291f160c01000000000000000f1a26313c46535e69727f8b939ea6afbabebebab8b5afacabacaeb5b7b9bdbfbab0a79f948d80746b60544a3f3428180e04000000000000000000000814202d3a4753606d7a86929facb9beb3a9998c7f7266544b4034281c10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b10151b1f2123282c2d2e30303131302f2d2c2924201f1c18120c070100000000000000000000000000000000000000000000000000000000000910171d2124252626262626262626262622221f1b150e0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73676d72787b7e7f807f7e7c79756f6a615e564d453b31281e1308000000000000000a15202a36424d57626d75818e949ea5aeb4babec4c0bbb9b8b9bbbfc4bfbab4aea69e959082796d60594f42382e23170600000000000000000000000613202c3945515d677683909ca9b6c2b5a99c8f8276665c5145382c1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f1215181c1f2022232424242322201f1d181312100c07000000000000000000000000000000000000000000000000000000000000000000060c11151718191919191919191919191615130f0a040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736f797f84888b8c8d8c8b8985827c756d685e574d433a2f24190d04000000000000030e1a25313b45515b606d79828e939fa2aaadb3b7b9bdbdbdbcbdb9b7b4aeaaa29f948f837a6d675c51473d30261c1106000000000000000000000004101d2935404b5566737f8c99aab4beb8ac9f9286796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306070c101213151617171716151413100c0706040000000000000000000000000000000000000000000000000000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c0908060300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f737d848c9196979999999898928f89817a6e695e564c41352921160b0000000000000009141f29333f45515c676d79818b92989fa2a9abadb2b0b0b0b2acababa39f98928c82796d685d554b40352b1e140a000000000000000000000000010d18242f3c4956636f7c8998a2aebabaaea298897c706356493d2f24180d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040607080a0a0b0a0a08070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7d8791969ea1a8a6a6a5aaa29f9b938e837b6e685d52453d32271b1002000000000000030d17212934404b555c676d757e858d92979b9ea1a8a3a4a3a8a19e9b99928e867f776d675d564c43392e23190c02000000000000000000000000000713202d3a4653606d7985929fabb8bfb4aa998c807366554b4035291d110400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b5a89c8f82869299a1a8acb2b2b3b2b4aeaca59e9591847a6d60594f44382c1e130800000000000000050f18232f39434b555c606d717a80858a8e9196959697969596918e8b86817b726c655d554c443a30271d1108000000000000000000000000000006121f2c3844505c6675828f9ca8b5c2b6a99c908376675d5145392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7aa9e948f9299a3abb2b3b5b8babebfbab8afa7a0968e81746b6054483a3025190d010000000000000007121d273139434b515a62686d73797d818487898a8a89888784817e7a746e69605b534c433a32281e150b00000000000000000000000000000003101c28343f4a5465727f8b98a9b3beb9ac9f92867a6d6053473a2d20140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bbb0a69e9c9fa3aba9a7a7a8abadb3bbc0c1b9b1a89d93897d7063564c41362a1d110500000000000000010b151f273139404550565e61676d7174787a7c7d7d7d7c7a7875716d68615e575049413a312820160c03000000000000000000000000000000000c17232e3c4855626f7b8897a1adb9bbaea3998a7d7063574a3d3025190d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c1b8b0aaa8aca49f9d9a9a9b9fa2a9afb6bec3baafa59b8e8175685e5246392d2013070000000000000000030d151f272f343f444c52555c606468686d6f7071706f6d686865615e56534d443f382f281f160e0400000000000000000000000000000000000615212e3a47535f6a7885919eabb8bfb5ab9a8d807367564c4135291d1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0cac1bab1a7a09a93908e8d8f92979fa4acb6c0c1b9ac9f92867a6d6154473a2e211407000000000000000000030d151d2329323a41464b515357565d616263646362615e565854524c46423b332d261d160d0400000000000000000000000000000000000006121f2b37434e586875818e9ba8b4c1b6aa9d908377685e5246392d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c8bdb2a8a095908783818082858c939aa4afbbc3baaea3998a7e7164574b3e3124180b00000000000000000000030b121820283036394045464a4c5254565757565554524c4b4746413a363127221b140b0400000000000000000000000000000000000000030f1b26313e4b5865717e8b98a8b2bdb9ac9f93867a6d6154473a2e211409000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c5b9aca09690837c76747475797f88939fa7b1bcbfb4ab9a8d8073675a4d4034271a07000000000000000000000001070e161e252a2e34383a3e414647494a4a4a494746413e3a3935302a251f17110a020000000000000000000000000000000000000000000a15212e3b4854616e7b8796a0acb8bbafa4998a7d7164574a3e30251a0e020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bdb2a89e91847a6f6a6767676d737f8c95a0acb8c3b6a99c908376695d50432e23180c00000000000000000000000000050c13191d23282c2d3035393a3c3d3e3d3c3a3936302e2d29251e1a140b0600000000000000000000000000000000000000000000000714212d3a46535e697784919eaab7c0b5ab9a8d817467574d42362a1e11050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b9aca196897d70685f58555c606c7883909daab7c3b8ab9e9185786b544a4034281c10040000000000000000000000000002080d12181c1f2024292d2e2f3031302f2e2d2a2521201d19130e090300000000000000000000000000000000000000000000000005121e2a36424d576774818d9aabb5c0b7aa9d918477695e52463a2d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7ab9e9184786c60564e4b515b66727f8c99a5b2bfb8ac9f928579665c5144382c1f120600000000000000000000000000000000070c101313191d2021232424232221201d191413110d08020000000000000000000000000000000000000000000000000000020e1a25313e4a5764717d8a99a4afbbb8aca096877b6e6154473b2e2114090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b4a89b8e8175655b5044404a54636f7c8996a2afbcbaaea29886796d6053463a2d2013070000000000000000000000000000000000000406080d11131416171717161413110d0807050100000000000000000000000000000000000000000000000000000000000914212d3a4754606d7a86939facb9bdb2a8978b7e7164584b3e31261a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736653493f3a4754616d7a8794a0b5c0bfb4aa94877a6d6154473a2e21140700000000000000000000000000000000000000000001050707090a0b0a09070705010000000000000000000000000000000000000000000000000000000000000000000713202c3945525d687783909daab6c1b4a79b8e817468574d42372b1e120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f3a4653606d798699a3afbbbaada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c566673808d99aab4bfb7ab9e918478695f53463a2d21140600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3844505c667986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000020507080b0d0f1111121211100f0c0a070604000000000000000000000000000000000000000000000000000000000000010d1924303d4a5663707d8998a3aebab9ada196887b6e6155483b2d22170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f343f4a5f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000104090e111414181a1c1d1e1f1e1e1d1b19161413100c0704000000000000000000000000000000000000000000000000000000000814202d3a4753606d7986929facb8bdb2a8988b7e716553493f33271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f2e46535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000001080d11141a1e20212427292a2b2b2b2b2a282623201f1c1812100c07000000000000000000000000000000000000000000000000000006131f2c3845515c6776838f9ca9b6c1b5a89b8e8275655b5044372b1f1205000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000060c13191d20252a2d2e3134353738383837363533302d2c29231f1c18120b0600000000000000000000000000000000000000000000000004101c2934404b5566727f8c99a9b3beb8ab9e9285786c605346392d201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000030a11171e24292c30363a3b3e4042444445454443423f3d3a38342f2c28231c17110a0200000000000000000000000000000000000000000000000c18232f3c4956626f7c8997a2adbab9ada197887c6f6255483c2e23170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000050c151c23282f35393b4246474b4d4f5051525151504e4c494745403a38342e28221c140b05000000000000000000000000000000000000000000000713202d3a4653606d7985929fabb8beb3a9988b7f7265544a3f34281c10030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000060f171e262e343a4145474d5254575a5c5d5e5e5e5e5d5b595653514b46444039332d261d170e0600000000000000000000000000000000000000000006121f2b3844505c6675828f9ba8b5c2b5a89c8f8275665c5044382b1f12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000061018212930383f444c5254575e616467686a6b6b6b6a69686663605c5553514a443f382f2920180f06000000000000000000000000000000000000000003101c28343f4a5465727e8b98a8b2bdb8ab9f9285796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000060f18222a333b424a50565d6065696e7173757777787877767572706d6764605c54504a423b332a21180f0500000000000000000000000000000000000000000b17232e3b4855626e7b8896a1adb9baaea298897c6f6256493c2e23180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000030c18212a343c454d545c60686d72777b7e8082838485848483817f7c7975716d66605b544d453c332a21170d03000000000000000000000000000000000000000614212e3a47535f6a7884919eabb8beb3aa998c7f7266554b4034281c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000b151e29333c464e575e666d727a7f83878a8d8f9091919191908e8c8986827d79716c665e574e463c33291f150b0100000000000000000000000000000000000006121e2b37424e576874818e9ba7b4c1b6a99c8f8276675c5145382c1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000007121c27303b454e585f696e787f858b9095979a9b9d9e9e9e9d9c9b9998928f8a847e786e695f584e453b31271d1207000000000000000000000000000000000000020e1a26313e4b5864717e8b97a7b1bcb8ac9f9286796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000c18232e39424d575f6a6f7b838c92979da0a7a6a8aaaaababaaa9a8aaa29f9c96918b827b6e6a5f574d43392f23180c030000000000000000000000000000000000000914212e3b4754616e7a8795a0acb8baaea398897c706356493d2f24180d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000004101c2834404a545f696f7c8590959fa2a9acb1b3b5b6b7b8b7b7b6b4b4aeaca8a19e948f847c6e695e554b4034291f14090000000000000000000000000000000000000714202d3946525e687784919daab7bfb4aa998c807366554b4135291d1104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000006121f2c3844515c666e7b8591979fa7adb3b8bcc0bebab8b7b7b8babebfbab8b2ada69f9691857b6e675c51453b31261a0e00000000000000000000000000000000000005111e2a36414d566774808d9aabb5c0b6a99d908376675d5145392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000004111d2935414c56606d78839097a1a9b1babebfbbb9b3adabaaaaabadb3b9bbbfbdb9b0a8a1979083796d60574d42362a1c11060000000000000000000000000000000000020e1925303d4a5764707d8a99a3afbbb9ac9f92867a6d6054473a2d211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000613202c3945525d68727f8c959fa9b3bbc3bdb5aeaca9a29f9d9e9fa2a9acaeb5bdc2bab2a9a0958d8073695f5346382e23170c0000000000000000000000000000000000000814212d3a4754606d7a86929facb9bbafa3998a7d7063574a3d3025190d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f35404b556c7986929facb9baada194877a6e6154473b2e21140800000714212d3a4754606d7a85929fa7b1bbc4bcb4aba39f9a9792919192979a9fa3abb4bcc4bbb1a79f92877b6e61544a3f34281c100300000000000000000000000404040404040613202c3945515d677683909da9b6c0b5ab9a8d807367564c41362a1d11050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3945515d677986939facb9baada194877a6e6154473b2e2114080005111e2a36414d5665727f8b98a2aeb9c3bfb4aaa299928d8885848485888d9299a2aab4bfc3bbafa3998d8174665c5044382c1f1206000000000000000004060711111111111111111d2935414c556673808c99aab4bfb7aa9d908377685e5246392d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a5988c7f7265594c3f3a4753606d7a8699a4afbbbaada194877a6e6154473b2e211408000714202d3946525e687783909daab3bec6baaea2989287807c787777787c80879298a2aebac5c0b5ab9e9285796d6053463a2d201307000000000000070c1013131e1e1e1e1e1e1e1e19242f3d495663707c8998a2aebab9ac9f93877a6d6154473a2e2114090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b3a69a8d807367564c413b4854616e7b8794abb5c0bfb4aa94877a6d6154473a2e211407000814212e3b4754616e7b87959fabbcc5bdb2a89f92867d746f6a6a6b6a6f747d86929fa9b3bec7b9ada297887c6f6255493c2f22160900000000030b12181c1f202a2a2a2a2a2a2a2a2a2a2d3a4653606d7985929facb8bbafa49a8a7d7164574a3e30251a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b6a99c8f8276685d5246454d5764707d8a97a3b0bdbaaea398867a6d6053473a2d201407000a1724313d4a5764707e8a97a7b1bcc5b9ada1968b7e726b625f58585f626b727f8b97a1adb9c6beb3a9988b7e7265584b3f3225180c000000030c151d23282c2d37373737373737373737373845515c6676828f9ca9b5c0b6ac9a8d817467574d42362a1e120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b9ac9f92867a6d60595351555e6974818e9aa7b4c1b8ac9f928579675d5145392c1f1306000d1a2633404d596673808c99a6b3bfc4b8ab9e9184786c6059534e4e5359606d7985929eabb8c5c1b4a79b8e8174685b4e4135281b0e0000000b151e272e34383a444444444444444444444444404b5465727f8c98a9b3beb7aa9e918477695e52463a2d20140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0baaea3998c80736b615e5d60676e7b86929facb8c4b7aa9e9184776b554b4035291d1004000e1b2835414e5b6874818e9ba7b4c1c0b3a79a8d8074665b5047434347505c6674818e9aa7b4c1c2b5a99c8f8276695c4f4336291c10000007121d273039404546515151515151515151515151515155626f7c8897a1adb9b8aca096877b6e6154483b2e21150900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bfb4ab9f92867d736e69676d7179829098a2aebac2b5a99c8f8276695c4f432f24180c00000f1c2936424f5c6975828f9ca8b5c2bdb1a4978a7e7164544a3f37373f4a5465727e8b98a5b1bec3b6aa9d9083776a5d5044372a1d1100000c18232e39424b51535d5d5d5d5d5d5d5d5d5d5d5d5d5d5d606c7885929eabb8bdb2a8978b7e7164584b3e31261a0e02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c6baaea3989287807b78787a7d8390949faab4bfbeb3a9998d8073665a4d4033271a070000101d293643505c6976838f9ca9b6c2bbafa295887c6f6255493c2d2e3d495663707c8996a3afbcc4b7aa9e9184776b5e5144382b1e110004101c2834404b545c606a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6575828e9ba8b5c1b4a79b8e817468574d42372b1e1206000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c4bdb4aaa399928d878585868a91959fa6b0bcc5baada297897d7063564a3d3023170a0000101d2a3643505d697683909ca9b6c3baaea194877b6e6154483b2e2f3c4855626f7b8895a2aebbc4b7ab9e9184786b5e5145382b1e120006131f2c3845515c666d7777777777777777777777777777777777777e8b98a5b1beb8ab9e918478695f53473a2e211406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bab2adababa39f9997929192999da0a8b0b8c2bfb4aa9f9285796d6053463a2d2013070000101d2a3643505d697683909ca9b6c3baada094877a6d6154473a2e2e3b4854616e7b8794a1aebac4b7ab9e9184786b5e5145382b1e12000713202d3a4653606d7983848484848484848484848484848484848384919eaab7c4b9ada196887b6e6255483b2d22170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bdb2a8a19e9ea0a8a9a29f9e9fa3abacb1bac2bfbaaea2988d8074665c5145382c1f13060000101c2936434f5c6976828f9ca9b5c2baada093877a6d6054473a2d2e3b4754616e7a8794a1adbac4b7aa9d9184776a5e5144372b1e11000714202d3a4753606d7a8690909090909090909090909090909090909196a0acb9c5bdb2a8988b7e726553493f33271b0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4b9ada196919196a0a9adababacafb5b8bdc3bcb8aea59f92867b6e61544b4034281c100400000f1c2935424f5c6875828f9ba8b5c2baada194877a6e6154473b2e2f3b4855626e7b8895a1aebbc3b6a99d9083766a5d5043372a1d10000714202d3a4753606d7a86939d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9ea0a8b2bdc8c1b5a89b8e8275655b5044372b1f12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b2b2ab9e9184849197a0a7aeb4b8b9bebab8b7b1aba49c938c7f72695e5242392e23180c0000000e1b2734414e5a6774818d9aa7b4c0bbaea194887b6e6155483b2e2f3c4955626f7c8895a2afbbc2b5a89b8f8275685c4f4235291c0f000714202d3a4753606d7a8693a0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacb2bac3cec5b8ab9e9285786c605346392d2013060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa6a6a6a69e91847b8591959fa2aaabadb3aeacaaa7a09d928d81746d62574d4230271d12070000000c1925323f4c5865727f8b98aab3bebcb0a396897d7063564a3d302f3e4a5764717d8a97a4b0bdbfb5ab998d8073665a4d4033271a0d000714202d3a4753606d7a8693a0adb7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b9bdc3cccbc6b9ada197887c6f6255493c2e23170c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9999999999999184777c838d92989b9ea1a9a29f9d9a95908980746f645b51453b301e150b00000000091623303c4956636f7c8998a2aebabeb1a5988b7e7265564c413d3e424d5766727f8c99a5b2bfbbaea3998a7d7064574a3d3124170a000714202d3a4753606d7a8693a0adb9bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbeb3a9988c7f7265544a3f34281c100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818c8c8c8c8c8c8c8c84776e7980858b8f9297949892918d89837d736e645d53493f33291f0c03000000000713202d3a4653606d7985929fabb8c2b5a89b8f8275685d524c4a4a4b535e6976838f9ca9b6c2b9ac9f92867a6d6054473a2d211407000714202d3a4753606d7a8693a0adb2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a89c8f8275665c5044382c1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724303d4a5763707d7f7f7f7f7f7f7f7f7f72676d737a7f82858687868584807d78706b635c534a41372d21170d000000000006121f2c3844515c6675818e9ba6b0bcb8ac9f92867a6d615d555757555d616e7b86929facb9bdb1a79c8f8275675d5145392c201306000714202d3a4753606d798693a0a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a59f9285796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4855616b707373737373737373726d6260686d7275787a7a7a797774706c656059524a41382f251b0f05000000000004101c2834404a54626f7c89949faab4baaea2988e81746d6765646465676d75818e99a3aebbb5ab9f958a7d7063554c4135291d1104000714202d3a4753606d7a869398989898989898989898989898989898989898989898989898989898897c6f6356493c3023160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202c38444f596163666666666666666665625b565d606568676d6e6d676a6763605b534f4740382f261d1309000000000000000c18232e394754606a76828f98a2abb4b4aa9d938d807a74727071727479808d939eabb5b4aea3999083786c6053463a2f24190d01000714202d3a4753606d79868c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c28333e474f555759595959595959595856514c525458555c6061605d555a56535049413d352e261d140b010000000000000007121c2b37434e58616e7b869299a3aab1afa59d928d85817e7d7d7e81858d929da5afb1aaa29f92877c6f655b504437281e130800000713202d3a4653606d787f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7064574a3d3124170a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b16212c353e44484a4c4c4c4c4c4c4c4c4b4a464145474b4b51535453514b4d4a46443f382f2b231c140b020000000000000000000f1b27323d46535f69707e8792989fa7aeaea49d97928e8b8a8a8b8e92979da4aeafa79f98928a7e716a6053493f3327160c01000006121f2b3844505c666d72727272727272727272727272727272727272727272727272727272727272706c6155493c3023160a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005101a232c33383c3d40404040404040403f3d3a35393a3f40454747474540413d3937332d261d19110a01000000000000000000000a16202a36424d57616c717e8690959da4aeaea9a19e9b989797989b9ea1a9aeafa59d9590867e716c62584e41382d22170400000003101c28343f4a545c60656565656565656565656565656565656565656565656565656565656565656461594f44392d2014080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a21282c2f30333333333333333332312e292c2d2f34383a3b3a39352f302d2b27221b140b07000000000000000000000000040e1a26313b45505a616c717c838d929da9b5b3adaba7a5a3a4a5a7abadb3b5a99d928e837c716c625a50463d2f261b1106000000000b17232e38424a50535959595959595959595959595959595959595959595959595959595959595957554f473e33281c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810161c20232426262626262626262524221d202123292c2d2e2d2c292423201f1b17110a02000000000000000000000000000009141f29333e48505a616a6f77808d9aa7b3beb9b8b4b1b0b0b1b4b8b9beb4a79a8e81776f6a615a50483f342b1d140a000000000006111c2630383f44464c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a49443e352c21170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b101416171919191919191919181815111314181c1f202120201d181713120f0b06000000000000000000000000000000000c17232e38424e575f6a6f7a828d929da9b5bbb7b5b1aeadadaeb1b5b7bbb5a99d928e827a6f6a5f574d42382d22170b0000000000000a141e262e34383a3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3d3c39332c231a10050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407090a0d0d0d0d0d0d0d0d0c0b090406070c101314141413100d07060503000000000000000000000000000000000003101c28343f4a545f6a6f7c848f949da4aebab0aba9a4a1a0a0a1a4a9abb0bbafa59d948f847c6f695f544a3f33281c0f030000000000020c141c23282b2d3232323232323232323232323232323232323232323232323232323232323231302d28211a11080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040607080706040100000000000000000000000000000000000000000006121f2c3844505c666e7c8591969ea6aeb4aea69f9c9794939394979c9fa6aeb5afa69f9691857b6e665b5044382b1f160b000000000000020a11171c1f20262626262626262626262626262626262626262626262626262626262626262423201c17100800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27333f4953606d78839097a1a8b0b4aba39f948f8a878686878a8f949fa3abb5b0a8a1979083786c6053463d32271b0f0300000000000000060b10121319191919191919191919191919191919191919191919191919191919191919171614100b05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306070707070707070707070706040000000000000000000000000000000000000000000000000000000000000005121f2b3744505b65727e8b95a0a9b2baaea399928a827e7b7a7a7b7e828a9299a3aebbb2a99f958b7e7164594f44382c2013070000000000000000000306070c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0a0a080400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c1012131414141414141414141413100c0701000000000000000000000000000000000000000000000000000000000613202d394653606c7884919ea7b1bbb2a99f92877e76716e6d6d6e71767e87929fa9b3bbb1a79d9184776b6054483b2f22150700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a11171c1f20202020202020202020201f1d18120b03000000000000000000000000000000000000000000000000000000091623303c4956636f7c8996a0acb9b9ada1968c7f726c6461606061646c727f8c97a1adb9b8aca096897c6f6356493c2f24180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c151c23282c2d2d2d2d2d2d2d2d2d2d2d2c29241d150d0300000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a8b2bdb8ab9e9184786d605a545353545a606d7985929eabb8bdb2a89a8d807467554b4035291d100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a151e262e34383a3a3a3a3a3a3a3a3a3a3a38352f271f150b0100000000000000000000000000000000000000000000000004101d2935404b556975828f9ca8b5c0b3a79a8d8074665c5048474748515c6674818e9aa7b4c1b7aa9d908477675d5145392c1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c2630383f44464747474747474747474745403931271d120700000000000000000000000000000000000000000000000006131f2c3845515d677885929eabb8bdb1a4978a7e7164544a3f3a3a404a5465717e8b98a4b1beb9ac9f92867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c17232e38424a505353535353535353535353514b43392f24180c0300000000000000000000000000000000000000000000000714202d3a4753606d7a8697a1adb9bbaea295887b6f6255483c2e2e3c4956636f7c8996a2afbcbbafa399887b6f6255483c2f22150900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a545c60606060606060606060605d554b4035291f140900000000000000000000000000000000000000000000000814212e3b4754616e7a8794a9b3bebaaea194877b6e6154483b2e2f3b4855626e7b8895a1aebbc0b5ab96897d7063564a3d3023170a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844505c666d6d6d6d6d6d6d6d6d6d6d675d51453b31261a0e02000000000000000000000000000000000000000000000915222f3c4855626f7b8895a2aebbbaada093877a6d6054473a2d2e3b4854616e7b8794a1aebabdb0a3978a7d7064574a3d3124170a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d787a7a7a7a7a7a7a7a7a796d60574d42362a1e1205000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcbaada094877a6d6154473a2e2e3b4854616e7b8794a1aebabdb0a4978a7d7164574a3e3124170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707d8686868686868686868578695f53463a2d211407000000000000000000000000000000000000000000000916232f3c4956626f7c8995a2afbcbaaea194877b6e6154483b2e2f3c4855626f7b8895a2aebbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a869393939393939397887b6e6155483b2e221507000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbbaea295887b6f6255483c2d303c4956636f7c8996a2afbcbdb0a4978a7d7164574a3e3124170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d677784909da0a0a0a0a9978a7e7164574b3e2f23180c000000000000000000000000000000000000000000000815212e3b4854616e7b8794a8b2bdbdb0a4978a7d7164544a3f3b3b3f4a5465717e8b98a4b1bebcb0a396897d7063564a3d3023170a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935404b556774818e9aa7adadada79a8d807467554b4034291c10040000000000000000000000000000000000000000000714202d3a4753606d7a8696a1acb9c0b3a69a8d8073665b5049484849505c6674818d9aa7b4c0bdb2a895887c6f6255493c2f221609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d18242f3e4b5865717e8b98a9b3beb6aa9d908377675c5145382c1f130600000000000000000000000000000000000000000006131f2c3845515d677884919eabb7c4b7ab9e9184786c605a565455565a606d7885919eabb8c4b9aca096877a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000715222f3c4855626f7b8897a2adbab9ac9f9286796d6053473a2d20140700000000000000000000000000000000000000000004101d2935404b556875828e9ba8b5c1b9aca1968b7f726c6562616162656c727f8c97a1adb9c4b7aa9e918477685d5245392c201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7985929fabb8bbaea399897c6f6356493c30231609000000000000000000000000000000000000000000000c18242f3f4c5965727f8c98a6b0bbbdb2a89f92867e76726f6e6e6f72767e86929fa9b3bebdb2a89a8e817467564c4135291d11040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6576828f9ca9b5bfb5ab988c7f7265594c3f30251a0e020000000000000000000000000000000000000000000715222e3b4855616e7b88949fabb7c1baaea398928a837e7c7b7b7c7f838b9298a3aebbc4b9aca1968a7d7063574a3d2f24190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27333f49536673808c99a6b3bfb5a89b8e827568574d42362a1e12050000000000000000000000000000000000000000000714212d3a46535f697683909ca5afbabfb4aaa39f94908b898788898b90959fa3aab4bfbcb1a79e9184786d6053463a2d2013080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d3d4a5763707d8a96a8b2bdb7ab9e918478695e52463a2d20140700000000000000000000000000000000000000000005121e2b37424d5763707d89939ea8b2bbbcb4aea69f9c9895949495989d9fa7aeb4bcbdb4aaa0958b7e72665c5044382b1f12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000614212e3a4754616d7a8796a0acb9b9ada196877b6e6154483b2e211507000000000000000000000000000000000000000000020e1a26313c4855606b75828f96a1a9b2bbbfbab0aba9a5a2a1a1a2a5a9abb1babfbcb4aba2989083786d60544a3f34281c10030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3946525e687784919eaab7bdb2a8978a7d7164574a3e2e23180c0000000000000000000000000000000000000000000009141f2c38444f59616d7a849197a1a9b0b9bdbbb7b6b1afaeaeafb2b6b8bcbebab2aaa29992867c6e665c5042382e23170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d2a36414c566875818e9ba8b4c0b3a69a8d807367544a4034281c100400000000000000000000000000000000000000000003101c27333d46525e686f7c8591969ea6acb2b9babfbebcbabbbcbec0bbb9b4aea8a09892877d706a5f544a3f30261c110600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1925303f4c5865727f8b98aab4bfb6a99c908376665c5144382c1f1206000000000000000000000000000000000000000000000b16212a36414c565f6a6f7c848f949ea0a8acaeb4b3b4b5b5b5b3b5afacaaa29f9691867e706b61574e42382e1e140a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000816232f3c4956626f7c8998a3aebab8ac9f9286796d6053463a2d20130700000000000000000000000000000000000000000000050d1925303a444e58606a6f7a828a91969c9fa3aba7a8a8a8a8a7aba49f9d98928c847c706c61594f453c30261c0c020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7986929facb8baaea398887c6f6255493c2f221608000000000000000000000000000000000000000000000008131e29323c464e5860686e767e848a8f9299989a9b9c9c9b9a989993908b857f796f6a615a50473e332a1e140a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844515c667683909ca9b6bfb4aa988b7f7265584c3f3025190d0100000000000000000000000000000000000000000000020d17202a343c464e565e616c71787d8286898b8d8e8f8f8e8d8c8986837f7a736d675f5850473e352c21180c020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404a546773808d9aa6b3c0b4a89b8e817568564c41362a1d11050000000000000000000000000000000000000000000000050e18222b343c444d525a61666d71767a7d7f8081828282807f7d7a76726d68605d554e463e352c231a0f060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3e4a5764717d8a97a9b2bdb7aa9e918477685e5246392d201307000000000000000000000000000000000000000000000000071019222b323b414650545c6064676d707274757575757472706d6865605d56514b433c342c231a1108000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000715212e3b4854616e7b8796a1adb9b9aca096877a6d6154473a2e21140600000000000000000000000000000000000000000000000000071019202930363e424a5053555d6063656768696968676563615e5654524c454039312a221a110800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535e697885919eabb8bdb2a8968a7d7063574a3d2d22170b0000000000000000000000000000000000000000000000000000070e171f252a30383f44464b515356585a5b5c5c5b5a595654524c4745413a352f271f19100800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d576875828f9ba8b5c0b3a6998d807366544a3f33281c0f030000000000000000000000000000000000000000000000000000050d14191e262e34383a4045474a4c4d4e4f4f4f4d4c4a4746413a39352f29241d150d0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a25313f4c5966727f8c99abb5c0b6a99c8f8376665b5044382b1f120600000000000000000000000000000000000000000000000000000002080c151c23282c2f35393a3d3f4142424242413f3d3a3935302c29241e18120b03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303d495663707c8999a3afbbb8ab9f9285796c605346392d2013060000000000000000000000000000000000000000000000000000000000030a11171c1f24292c2d303234353636353432302e2d2925201d19130c0701000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a86929facb9baaea298887b6f6255483c2f22150800000000000000000000000000000000000000000000000000000000000000060c1012181d1f202325272829292827262321201d1913110d080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3945515d677783909daab6beb4aa988b7e7165584b3e2f24190d01000000000000000000000000000000000000000000000000000000000000000003070c10131417191a1b1c1c1c1a19171413110d080401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101d2935404b556774818d9aa7b4c0b4a79a8e817467564c4135291d110400000000000000000000000000000000000000000000000000000000000000000000000406070a0c0e0f0f0f0f0e0c0a070705010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18242f3e4b5864717e8b97a9b3beb7aa9d918477685d5245392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000715222f3b4855626e7b8897a2adbab9ac9f93867a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7985929fabb8bbafa49a897d7063564a3d302317090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6576828f9ca9b5c0b6ac998c7f7366594c4031261a0e02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27333f49536673808c99acb6c0b5a89c8f827569574d42372b1e1206000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d3d4a5663707d899aa4afbbb8ab9e928578695f53473a2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000614212d3a4754606d7a86939facb9b9ada297887b6e6255483b2f221507000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c3945525d687784919daab7beb3a9978b7e7164584b3e2f24180d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c566874818e9ba7b4c0b4a79a8d817467554b4035291d1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1924303f4b5865727e8b98aab4bfb6aa9d908377675d5145392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000816222f3c4955626f7c8898a2aebab9ac9f92867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7985929facb8bbafa399897c706356493d302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844505c667683909ca9b6c0b5ab998c7f7266594c3f31251a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a546773808d9aa6b3c0b5a89b8f827568574d42362a1e1205000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c17232e3d4a5764707d8a97a8b2bdb8ab9e918578695e53463a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000614212e3b4754616e7a8796a1adb9b9ada197877b6e6154483b2e211507000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a46525e697884919eabb7beb3a9978a7e7164574b3e2e23180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36424d566875828e9ba8b5c0b3a79a8d807467554b4034281c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1925303f4c5965727f8c98abb5bfb6a99d908376675c5145382c1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8999a3aebbb9ac9f9286796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7986929facb9baaea399897c6f6256493c2f2316080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c677783909daab6bfb4ab988b7f7265584c3f3025190e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2934404b556774818d9aa7b4c0b5a89b8e817568564d41362a1e1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232f3e4b5764717e8a97a9b3beb7ab9e918478685e5246392d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000715222e3b4855616e7b8897a1adb9b9aca196877a6e6154473b2e211406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535f697885929eabb8bdb2a8978a7d7064574a3d2e23170c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2b37424d576975828f9ca8b5c0b3a6998d807366544a3f34281c1003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a2631404c5966737f8c99acb6c0b6a99c908376665c5044382c1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091723303d4a5663707d899aa4afbbb8ac9f9285796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a86939facb9baaea298887c6f6255493c2f221608000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d677784919daab7bfb4aa988b7e7265584b3f3025190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c556874818e9ba7b4c1b4a79b8e817468564c4135291d1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d19242f3e4b5865717e8b98aab4bfb7aa9e918477685e5246392d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222f3c4855626f7b8898a2aebab8aca096877a6d6154473a2e211406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7985929facb8bdb2a8968a7d7063574a3d2d22170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505b6676838f9ca9b6bfb3a6998c80736653493f33271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c28333f4a546673808d99a6b3c0b5a99c8f8276655b5044372b1f1205000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d3d4a5764707d8a97a8b2bdb8ab9f9285796c605346392d201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000614212e3b4754616e7a8796a1acb9baada297887b6e6255483b2f221507000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3946525e687884919eabb7beb3a9988b7e7165584b3e2f24180d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36414c566875818e9ba8b5bcb4a79a8e817467554b4135291d1104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1925303f4c5865727f8b98aab4afafaa9d908477675d5145392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000816232f3c4956626f7c8998a3a2a2a2a29f93867a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d79869295959595959599897d706356493d3023160a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c6676838989898989898989897f7366594c403326190d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b54616e7b7c7c7c7c7c7c7c7c7c7b6e6155483b2e22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3946535f696e6f6f6f6f6f6f6f6f6f6e695f53463a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d2b37424d575f61626262626262626262615f574d42362a1e12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1a26313c454d535556565656565656565655534d453b31261a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f2a333c4246484949494949494949494846423b33291f140900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030e18212a31373a3b3c3c3c3c3c3c3c3c3c3b3a36312921180d030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f181f262b2d2e2f2f2f2f2f2f2f2f2f2e2d2a261f180f0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e141a1e212223232323232323232322211e1a140d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e1214151616161616161616161514120e090300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002050708090909090909090909080705020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - m_StreamData: - serializedVersion: 2 - offset: 0 - size: 0 - path: ---- !u!21 &-1030930060397404263 +--- !u!21 &-2577534979213189211 Material: serializedVersion: 8 m_ObjectHideFlags: 0 @@ -80,7 +33,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _MainTex: - m_Texture: {fileID: -2284082493848745064} + m_Texture: {fileID: 7970078894227476819} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _OutlineTex: @@ -165,7 +118,7 @@ MonoBehaviour: m_Name: Korolev Condensed W04 Bold SDF m_EditorClassIdentifier: hashCode: -1512501986 - material: {fileID: -1030930060397404263} + material: {fileID: -2577534979213189211} materialHashCode: -1836380674 m_Version: 1.1.0 m_SourceFontFileGUID: 2bce9312e55b8de45a7cc2d163604db6 @@ -210,18 +163,33 @@ MonoBehaviour: m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 - - m_Index: 6 + - m_Index: 4 m_Metrics: - m_Width: 43.5625 - m_Height: 72.265625 - m_HorizontalBearingX: 4.234375 - m_HorizontalBearingY: 68.21875 - m_HorizontalAdvance: 53.734375 + m_Width: 12.234375 + m_Height: 64.609375 + m_HorizontalBearingX: 2.96875 + m_HorizontalBearingY: 63.984375 + m_HorizontalAdvance: 20.0625 m_GlyphRect: - m_X: 214 - m_Y: 235 - m_Width: 44 - m_Height: 74 + m_X: 996 + m_Y: 188 + m_Width: 14 + m_Height: 65 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 5 + m_Metrics: + m_Width: 26.46875 + m_Height: 25.015625 + m_HorizontalBearingX: 3.234375 + m_HorizontalBearingY: 63.453125 + m_HorizontalAdvance: 32.9375 + m_GlyphRect: + m_X: 569 + m_Y: 99 + m_Width: 27 + m_Height: 26 m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 @@ -233,8 +201,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.21875 m_HorizontalAdvance: 83.15625 m_GlyphRect: - m_X: 938 - m_Y: 93 + m_X: 902 + m_Y: 178 m_Width: 75 m_Height: 73 m_Scale: 1 @@ -248,8 +216,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 17.1875 m_GlyphRect: - m_X: 887 - m_Y: 10 + m_X: 10 + m_Y: 348 m_Width: 11 m_Height: 26 m_Scale: 1 @@ -263,8 +231,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.21875 m_HorizontalAdvance: 23.671875 m_GlyphRect: - m_X: 604 - m_Y: 164 + m_X: 368 + m_Y: 10 m_Width: 18 m_Height: 74 m_Scale: 1 @@ -278,8 +246,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.21875 m_HorizontalAdvance: 23.671875 m_GlyphRect: - m_X: 545 - m_Y: 247 + m_X: 100 + m_Y: 177 m_Width: 18 m_Height: 74 m_Scale: 1 @@ -293,8 +261,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.8125 m_HorizontalAdvance: 41.21875 m_GlyphRect: - m_X: 117 - m_Y: 424 + m_X: 461 + m_Y: 254 m_Width: 32 m_Height: 31 m_Scale: 1 @@ -308,8 +276,8 @@ MonoBehaviour: m_HorizontalBearingY: 48.234375 m_HorizontalAdvance: 41.046875 m_GlyphRect: - m_X: 828 - m_Y: 176 + m_X: 512 + m_Y: 266 m_Width: 33 m_Height: 34 m_Scale: 1 @@ -323,28 +291,13 @@ MonoBehaviour: m_HorizontalBearingY: 14.671875 m_HorizontalAdvance: 20.796875 m_GlyphRect: - m_X: 552 - m_Y: 99 + m_X: 94 + m_Y: 323 m_Width: 19 m_Height: 25 m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 - - m_Index: 16 - m_Metrics: - m_Width: 19.984375 - m_Height: 7.90625 - m_HorizontalBearingX: 2.875 - m_HorizontalBearingY: 30.59375 - m_HorizontalAdvance: 25.921875 - m_GlyphRect: - m_X: 114 - m_Y: 295 - m_Width: 21 - m_Height: 9 - m_Scale: 1 - m_AtlasIndex: 0 - m_ClassDefinitionType: 0 - m_Index: 17 m_Metrics: m_Width: 12.140625 @@ -353,8 +306,8 @@ MonoBehaviour: m_HorizontalBearingY: 11.609375 m_HorizontalAdvance: 18.453125 m_GlyphRect: - m_X: 404 - m_Y: 176 + m_X: 236 + m_Y: 165 m_Width: 13 m_Height: 13 m_Scale: 1 @@ -368,8 +321,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.21875 m_HorizontalAdvance: 29.0625 m_GlyphRect: - m_X: 10 - m_Y: 555 + m_X: 332 + m_Y: 318 m_Width: 27 m_Height: 74 m_Scale: 1 @@ -383,8 +336,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.34375 m_HorizontalAdvance: 42.5625 m_GlyphRect: - m_X: 423 - m_Y: 325 + m_X: 844 + m_Y: 181 m_Width: 36 m_Height: 66 m_Scale: 1 @@ -398,8 +351,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 24.84375 m_GlyphRect: - m_X: 386 - m_Y: 291 + m_X: 247 + m_Y: 82 m_Width: 18 m_Height: 64 m_Scale: 1 @@ -413,8 +366,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.34375 m_HorizontalAdvance: 41.21875 m_GlyphRect: - m_X: 330 - m_Y: 329 + m_X: 129 + m_Y: 93 m_Width: 36 m_Height: 65 m_Scale: 1 @@ -428,8 +381,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.34375 m_HorizontalAdvance: 41.671875 m_GlyphRect: - m_X: 204 - m_Y: 411 + m_X: 957 + m_Y: 10 m_Width: 37 m_Height: 66 m_Scale: 1 @@ -443,8 +396,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 42.484375 m_GlyphRect: - m_X: 430 - m_Y: 10 + m_X: 623 + m_Y: 93 m_Width: 38 m_Height: 64 m_Scale: 1 @@ -458,8 +411,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 41.84375 m_GlyphRect: - m_X: 487 - m_Y: 10 + m_X: 680 + m_Y: 93 m_Width: 37 m_Height: 65 m_Scale: 1 @@ -473,8 +426,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 41.21875 m_GlyphRect: - m_X: 260 - m_Y: 411 + m_X: 569 + m_Y: 176 m_Width: 36 m_Height: 65 m_Scale: 1 @@ -488,8 +441,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 36.1875 m_GlyphRect: - m_X: 117 - m_Y: 474 + m_X: 513 + m_Y: 183 m_Width: 33 m_Height: 64 m_Scale: 1 @@ -503,8 +456,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.71875 m_HorizontalAdvance: 42.03125 m_GlyphRect: - m_X: 62 - m_Y: 509 + m_X: 624 + m_Y: 176 m_Width: 36 m_Height: 65 m_Scale: 1 @@ -518,8 +471,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.265625 m_HorizontalAdvance: 41.21875 m_GlyphRect: - m_X: 99 - m_Y: 211 + m_X: 736 + m_Y: 93 m_Width: 36 m_Height: 65 m_Scale: 1 @@ -534,27 +487,12 @@ MonoBehaviour: m_HorizontalAdvance: 18.71875 m_GlyphRect: m_X: 10 - m_Y: 113 + m_Y: 277 m_Width: 13 m_Height: 52 m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 - - m_Index: 30 - m_Metrics: - m_Width: 17.546875 - m_Height: 60.65625 - m_HorizontalBearingX: -0.09375 - m_HorizontalBearingY: 50.9375 - m_HorizontalAdvance: 20.875 - m_GlyphRect: - m_X: 385 - m_Y: 374 - m_Width: 19 - m_Height: 61 - m_Scale: 1 - m_AtlasIndex: 0 - m_ClassDefinitionType: 0 - m_Index: 31 m_Metrics: m_Width: 26.734375 @@ -563,28 +501,13 @@ MonoBehaviour: m_HorizontalBearingY: 45.265625 m_HorizontalAdvance: 34.109375 m_GlyphRect: - m_X: 331 - m_Y: 10 + m_X: 357 + m_Y: 103 m_Width: 28 m_Height: 34 m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 - - m_Index: 32 - m_Metrics: - m_Width: 29.515625 - m_Height: 24.390625 - m_HorizontalBearingX: 3.6875 - m_HorizontalBearingY: 44.375 - m_HorizontalAdvance: 38.15625 - m_GlyphRect: - m_X: 129 - m_Y: 95 - m_Width: 31 - m_Height: 26 - m_Scale: 1 - m_AtlasIndex: 0 - m_ClassDefinitionType: 0 - m_Index: 33 m_Metrics: m_Width: 26.734375 @@ -593,13 +516,28 @@ MonoBehaviour: m_HorizontalBearingY: 45.265625 m_HorizontalAdvance: 34.109375 m_GlyphRect: - m_X: 331 - m_Y: 63 + m_X: 85 + m_Y: 270 m_Width: 28 m_Height: 34 m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 + - m_Index: 34 + m_Metrics: + m_Width: 34.203125 + m_Height: 64.890625 + m_HorizontalBearingX: 1.4375 + m_HorizontalBearingY: 64.34375 + m_HorizontalAdvance: 38.15625 + m_GlyphRect: + m_X: 735 + m_Y: 177 + m_Width: 35 + m_Height: 66 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 - m_Index: 36 m_Metrics: m_Width: 41.671875 @@ -608,8 +546,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 42.484375 m_GlyphRect: - m_X: 490 - m_Y: 99 + m_X: 785 + m_Y: 10 m_Width: 43 m_Height: 64 m_Scale: 1 @@ -623,8 +561,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 42.84375 m_GlyphRect: - m_X: 332 - m_Y: 246 + m_X: 623 + m_Y: 10 m_Width: 35 m_Height: 64 m_Scale: 1 @@ -638,8 +576,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.265625 m_HorizontalAdvance: 42.203125 m_GlyphRect: - m_X: 132 - m_Y: 10 + m_X: 789 + m_Y: 178 m_Width: 36 m_Height: 66 m_Scale: 1 @@ -653,8 +591,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 44.09375 m_GlyphRect: - m_X: 490 - m_Y: 182 + m_X: 94 + m_Y: 371 m_Width: 36 m_Height: 64 m_Scale: 1 @@ -668,8 +606,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 38.0625 m_GlyphRect: - m_X: 649 - m_Y: 95 + m_X: 457 + m_Y: 99 m_Width: 30 m_Height: 64 m_Scale: 1 @@ -683,8 +621,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 35.90625 m_GlyphRect: - m_X: 166 - m_Y: 169 + m_X: 395 + m_Y: 271 m_Width: 29 m_Height: 64 m_Scale: 1 @@ -698,8 +636,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.34375 m_HorizontalAdvance: 42.65625 m_GlyphRect: - m_X: 62 - m_Y: 424 + m_X: 516 + m_Y: 10 m_Width: 36 m_Height: 66 m_Scale: 1 @@ -713,8 +651,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 45 m_GlyphRect: - m_X: 114 - m_Y: 341 + m_X: 677 + m_Y: 10 m_Width: 35 m_Height: 64 m_Scale: 1 @@ -728,8 +666,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 21.328125 m_GlyphRect: - m_X: 404 - m_Y: 208 + m_X: 64 + m_Y: 412 m_Width: 11 m_Height: 64 m_Scale: 1 @@ -743,8 +681,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 41.578125 m_GlyphRect: - m_X: 884 - m_Y: 93 + m_X: 10 + m_Y: 412 m_Width: 35 m_Height: 65 m_Scale: 1 @@ -758,8 +696,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 43.109375 m_GlyphRect: - m_X: 828 - m_Y: 93 + m_X: 679 + m_Y: 177 m_Width: 37 m_Height: 64 m_Scale: 1 @@ -773,8 +711,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 34.46875 m_GlyphRect: - m_X: 719 - m_Y: 93 + m_X: 847 + m_Y: 10 m_Width: 28 m_Height: 64 m_Scale: 1 @@ -788,8 +726,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 54.265625 m_GlyphRect: - m_X: 51 - m_Y: 295 + m_X: 894 + m_Y: 10 m_Width: 44 m_Height: 64 m_Scale: 1 @@ -803,8 +741,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 45.8125 m_GlyphRect: - m_X: 206 - m_Y: 328 + m_X: 192 + m_Y: 10 m_Width: 36 m_Height: 64 m_Scale: 1 @@ -818,8 +756,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.265625 m_HorizontalAdvance: 43.296875 m_GlyphRect: - m_X: 773 - m_Y: 10 + m_X: 902 + m_Y: 93 m_Width: 36 m_Height: 66 m_Scale: 1 @@ -833,8 +771,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 43.296875 m_GlyphRect: - m_X: 719 - m_Y: 10 + m_X: 341 + m_Y: 235 m_Width: 35 m_Height: 64 m_Scale: 1 @@ -848,8 +786,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.34375 m_HorizontalAdvance: 43.296875 m_GlyphRect: - m_X: 880 - m_Y: 177 + m_X: 173 + m_Y: 236 m_Width: 36 m_Height: 76 m_Scale: 1 @@ -863,8 +801,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 43.296875 m_GlyphRect: - m_X: 595 - m_Y: 81 + m_X: 731 + m_Y: 10 m_Width: 35 m_Height: 64 m_Scale: 1 @@ -878,8 +816,8 @@ MonoBehaviour: m_HorizontalBearingY: 64.34375 m_HorizontalAdvance: 39.953125 m_GlyphRect: - m_X: 664 - m_Y: 10 + m_X: 791 + m_Y: 93 m_Width: 36 m_Height: 66 m_Scale: 1 @@ -893,28 +831,13 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 34.828125 m_GlyphRect: - m_X: 552 - m_Y: 164 + m_X: 228 + m_Y: 291 m_Width: 33 m_Height: 64 m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 - - m_Index: 56 - m_Metrics: - m_Width: 35.1875 - m_Height: 64.265625 - m_HorizontalBearingX: 4.40625 - m_HorizontalBearingY: 63.453125 - m_HorizontalAdvance: 44.09375 - m_GlyphRect: - m_X: 277 - m_Y: 239 - m_Width: 36 - m_Height: 65 - m_Scale: 1 - m_AtlasIndex: 0 - m_ClassDefinitionType: 0 - m_Index: 57 m_Metrics: m_Width: 38.96875 @@ -923,7 +846,7 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 39.953125 m_GlyphRect: - m_X: 828 + m_X: 405 m_Y: 10 m_Width: 40 m_Height: 64 @@ -938,8 +861,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 61.109375 m_GlyphRect: - m_X: 217 - m_Y: 82 + m_X: 565 + m_Y: 260 m_Width: 61 m_Height: 64 m_Scale: 1 @@ -953,8 +876,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 41.3125 m_GlyphRect: - m_X: 378 - m_Y: 93 + m_X: 132 + m_Y: 10 m_Width: 41 m_Height: 64 m_Scale: 1 @@ -968,8 +891,8 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 41.21875 m_GlyphRect: - m_X: 887 - m_Y: 10 + m_X: 10 + m_Y: 42 m_Width: 41 m_Height: 64 m_Scale: 1 @@ -983,28 +906,13 @@ MonoBehaviour: m_HorizontalBearingY: 63.453125 m_HorizontalAdvance: 35.453125 m_GlyphRect: - m_X: 947 - m_Y: 10 + m_X: 77 + m_Y: 38 m_Width: 33 m_Height: 64 m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 - - m_Index: 63 - m_Metrics: - m_Width: 26.015625 - m_Height: 72.265625 - m_HorizontalBearingX: 0.625 - m_HorizontalBearingY: 68.21875 - m_HorizontalAdvance: 29.0625 - m_GlyphRect: - m_X: 10 - m_Y: 184 - m_Width: 27 - m_Height: 74 - m_Scale: 1 - m_AtlasIndex: 0 - m_ClassDefinitionType: 0 - m_Index: 66 m_Metrics: m_Width: 34.203125 @@ -1028,8 +936,8 @@ MonoBehaviour: m_HorizontalBearingY: 51.03125 m_HorizontalAdvance: 39.515625 m_GlyphRect: - m_X: 438 - m_Y: 94 + m_X: 247 + m_Y: 10 m_Width: 33 m_Height: 53 m_Scale: 1 @@ -1043,8 +951,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.046875 m_HorizontalAdvance: 39.515625 m_GlyphRect: - m_X: 438 - m_Y: 166 + m_X: 571 + m_Y: 10 m_Width: 33 m_Height: 70 m_Scale: 1 @@ -1058,8 +966,8 @@ MonoBehaviour: m_HorizontalBearingY: 51.03125 m_HorizontalAdvance: 37.984375 m_GlyphRect: - m_X: 378 - m_Y: 10 + m_X: 280 + m_Y: 291 m_Width: 33 m_Height: 53 m_Scale: 1 @@ -1073,8 +981,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.046875 m_HorizontalAdvance: 39.515625 m_GlyphRect: - m_X: 62 - m_Y: 110 + m_X: 464 + m_Y: 10 m_Width: 33 m_Height: 70 m_Scale: 1 @@ -1088,8 +996,8 @@ MonoBehaviour: m_HorizontalBearingY: 51.125 m_HorizontalAdvance: 38.34375 m_GlyphRect: - m_X: 279 - m_Y: 10 + m_X: 10 + m_Y: 125 m_Width: 33 m_Height: 53 m_Scale: 1 @@ -1103,8 +1011,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.40625 m_HorizontalAdvance: 26.453125 m_GlyphRect: - m_X: 10 - m_Y: 277 + m_X: 132 + m_Y: 283 m_Width: 22 m_Height: 69 m_Scale: 1 @@ -1118,8 +1026,8 @@ MonoBehaviour: m_HorizontalBearingY: 50.9375 m_HorizontalAdvance: 39.515625 m_GlyphRect: - m_X: 543 - m_Y: 10 + m_X: 409 + m_Y: 182 m_Width: 33 m_Height: 70 m_Scale: 1 @@ -1133,8 +1041,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.046875 m_HorizontalAdvance: 39.78125 m_GlyphRect: - m_X: 10 - m_Y: 378 + m_X: 173 + m_Y: 331 m_Width: 33 m_Height: 69 m_Scale: 1 @@ -1148,8 +1056,8 @@ MonoBehaviour: m_HorizontalBearingY: 67.6875 m_HorizontalAdvance: 19.171875 m_GlyphRect: - m_X: 297 - m_Y: 82 + m_X: 53 + m_Y: 209 m_Width: 13 m_Height: 68 m_Scale: 1 @@ -1163,8 +1071,8 @@ MonoBehaviour: m_HorizontalBearingY: 67.6875 m_HorizontalAdvance: 19.4375 m_GlyphRect: - m_X: 168 - m_Y: 341 + m_X: 137 + m_Y: 177 m_Width: 17 m_Height: 87 m_Scale: 1 @@ -1178,8 +1086,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.046875 m_HorizontalAdvance: 37.984375 m_GlyphRect: - m_X: 277 - m_Y: 323 + m_X: 516 + m_Y: 95 m_Width: 34 m_Height: 69 m_Scale: 1 @@ -1193,8 +1101,8 @@ MonoBehaviour: m_HorizontalBearingY: 68.046875 m_HorizontalAdvance: 19.4375 m_GlyphRect: - m_X: 187 - m_Y: 81 + m_X: 70 + m_Y: 121 m_Width: 11 m_Height: 69 m_Scale: 1 @@ -1208,7 +1116,7 @@ MonoBehaviour: m_HorizontalBearingY: 51.03125 m_HorizontalAdvance: 57.515625 m_GlyphRect: - m_X: 595 + m_X: 299 m_Y: 10 m_Width: 50 m_Height: 52 @@ -1223,8 +1131,8 @@ MonoBehaviour: m_HorizontalBearingY: 51.03125 m_HorizontalAdvance: 39.78125 m_GlyphRect: - m_X: 114 - m_Y: 140 + m_X: 357 + m_Y: 164 m_Width: 33 m_Height: 52 m_Scale: 1 @@ -1238,8 +1146,8 @@ MonoBehaviour: m_HorizontalBearingY: 51.03125 m_HorizontalAdvance: 38.515625 m_GlyphRect: - m_X: 77 - m_Y: 38 + m_X: 461 + m_Y: 182 m_Width: 33 m_Height: 53 m_Scale: 1 @@ -1253,23 +1161,8 @@ MonoBehaviour: m_HorizontalBearingY: 51.125 m_HorizontalAdvance: 39.78125 m_GlyphRect: - m_X: 10 - m_Y: 466 - m_Width: 33 - m_Height: 70 - m_Scale: 1 - m_AtlasIndex: 0 - m_ClassDefinitionType: 0 - - m_Index: 84 - m_Metrics: - m_Width: 31.6875 - m_Height: 68.5 - m_HorizontalBearingX: 3.6875 - m_HorizontalBearingY: 51.125 - m_HorizontalAdvance: 39.78125 - m_GlyphRect: - m_X: 154 - m_Y: 252 + m_X: 42 + m_Y: 323 m_Width: 33 m_Height: 70 m_Scale: 1 @@ -1283,8 +1176,8 @@ MonoBehaviour: m_HorizontalBearingY: 51.03125 m_HorizontalAdvance: 26.90625 m_GlyphRect: - m_X: 187 - m_Y: 10 + m_X: 184 + m_Y: 93 m_Width: 21 m_Height: 52 m_Scale: 1 @@ -1298,8 +1191,8 @@ MonoBehaviour: m_HorizontalBearingY: 51.203125 m_HorizontalAdvance: 36.546875 m_GlyphRect: - m_X: 227 - m_Y: 10 + m_X: 184 + m_Y: 164 m_Width: 33 m_Height: 53 m_Scale: 1 @@ -1313,8 +1206,8 @@ MonoBehaviour: m_HorizontalBearingY: 59.40625 m_HorizontalAdvance: 26.734375 m_GlyphRect: - m_X: 56 - m_Y: 199 + m_X: 10 + m_Y: 197 m_Width: 24 m_Height: 61 m_Scale: 1 @@ -1328,8 +1221,8 @@ MonoBehaviour: m_HorizontalBearingY: 50.484375 m_HorizontalAdvance: 39.15625 m_GlyphRect: - m_X: 10 - m_Y: 42 + m_X: 405 + m_Y: 93 m_Width: 33 m_Height: 52 m_Scale: 1 @@ -1343,8 +1236,8 @@ MonoBehaviour: m_HorizontalBearingY: 50.484375 m_HorizontalAdvance: 37.078125 m_GlyphRect: - m_X: 348 - m_Y: 176 + m_X: 285 + m_Y: 221 m_Width: 37 m_Height: 51 m_Scale: 1 @@ -1358,8 +1251,8 @@ MonoBehaviour: m_HorizontalBearingY: 50.484375 m_HorizontalAdvance: 54.71875 m_GlyphRect: - m_X: 217 - m_Y: 165 + m_X: 284 + m_Y: 151 m_Width: 54 m_Height: 51 m_Scale: 1 @@ -1373,8 +1266,8 @@ MonoBehaviour: m_HorizontalBearingY: 50.484375 m_HorizontalAdvance: 39.59375 m_GlyphRect: - m_X: 290 - m_Y: 169 + m_X: 299 + m_Y: 81 m_Width: 39 m_Height: 51 m_Scale: 1 @@ -1388,8 +1281,8 @@ MonoBehaviour: m_HorizontalBearingY: 50.484375 m_HorizontalAdvance: 37.171875 m_GlyphRect: - m_X: 483 - m_Y: 265 + m_X: 846 + m_Y: 93 m_Width: 37 m_Height: 69 m_Scale: 1 @@ -1403,13 +1296,28 @@ MonoBehaviour: m_HorizontalBearingY: 50.484375 m_HorizontalAdvance: 32.578125 m_GlyphRect: - m_X: 434 - m_Y: 255 + m_X: 236 + m_Y: 221 m_Width: 30 m_Height: 51 m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 + - m_Index: 95 + m_Metrics: + m_Width: 10.078125 + m_Height: 72.265625 + m_HorizontalBearingX: 4.6875 + m_HorizontalBearingY: 68.21875 + m_HorizontalAdvance: 19.4375 + m_GlyphRect: + m_X: 996 + m_Y: 95 + m_Width: 11 + m_Height: 74 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 - m_Index: 350 m_Metrics: m_Width: 47.78125 @@ -1425,14 +1333,48 @@ MonoBehaviour: m_Scale: 1 m_AtlasIndex: 0 m_ClassDefinitionType: 0 + - m_Index: 16 + m_Metrics: + m_Width: 19.984375 + m_Height: 7.90625 + m_HorizontalBearingX: 2.875 + m_HorizontalBearingY: 30.59375 + m_HorizontalAdvance: 25.921875 + m_GlyphRect: + m_X: 569 + m_Y: 144 + m_Width: 21 + m_Height: 9 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 56 + m_Metrics: + m_Width: 35.1875 + m_Height: 64.265625 + m_HorizontalBearingX: 4.40625 + m_HorizontalBearingY: 63.453125 + m_HorizontalAdvance: 44.09375 + m_GlyphRect: + m_X: 443 + m_Y: 304 + m_Width: 36 + m_Height: 65 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 m_CharacterTable: - m_ElementType: 1 m_Unicode: 32 m_GlyphIndex: 3 m_Scale: 1 - m_ElementType: 1 - m_Unicode: 35 - m_GlyphIndex: 6 + m_Unicode: 33 + m_GlyphIndex: 4 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 34 + m_GlyphIndex: 5 m_Scale: 1 - m_ElementType: 1 m_Unicode: 37 @@ -1462,10 +1404,6 @@ MonoBehaviour: m_Unicode: 44 m_GlyphIndex: 15 m_Scale: 1 - - m_ElementType: 1 - m_Unicode: 45 - m_GlyphIndex: 16 - m_Scale: 1 - m_ElementType: 1 m_Unicode: 46 m_GlyphIndex: 17 @@ -1518,22 +1456,18 @@ MonoBehaviour: m_Unicode: 58 m_GlyphIndex: 29 m_Scale: 1 - - m_ElementType: 1 - m_Unicode: 59 - m_GlyphIndex: 30 - m_Scale: 1 - m_ElementType: 1 m_Unicode: 60 m_GlyphIndex: 31 m_Scale: 1 - - m_ElementType: 1 - m_Unicode: 61 - m_GlyphIndex: 32 - m_Scale: 1 - m_ElementType: 1 m_Unicode: 62 m_GlyphIndex: 33 m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 63 + m_GlyphIndex: 34 + m_Scale: 1 - m_ElementType: 1 m_Unicode: 65 m_GlyphIndex: 36 @@ -1614,10 +1548,6 @@ MonoBehaviour: m_Unicode: 84 m_GlyphIndex: 55 m_Scale: 1 - - m_ElementType: 1 - m_Unicode: 85 - m_GlyphIndex: 56 - m_Scale: 1 - m_ElementType: 1 m_Unicode: 86 m_GlyphIndex: 57 @@ -1638,10 +1568,6 @@ MonoBehaviour: m_Unicode: 90 m_GlyphIndex: 61 m_Scale: 1 - - m_ElementType: 1 - m_Unicode: 92 - m_GlyphIndex: 63 - m_Scale: 1 - m_ElementType: 1 m_Unicode: 95 m_GlyphIndex: 66 @@ -1710,10 +1636,6 @@ MonoBehaviour: m_Unicode: 112 m_GlyphIndex: 83 m_Scale: 1 - - m_ElementType: 1 - m_Unicode: 113 - m_GlyphIndex: 84 - m_Scale: 1 - m_ElementType: 1 m_Unicode: 114 m_GlyphIndex: 85 @@ -1750,16 +1672,24 @@ MonoBehaviour: m_Unicode: 122 m_GlyphIndex: 93 m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 124 + m_GlyphIndex: 95 + m_Scale: 1 - m_ElementType: 1 m_Unicode: 8230 m_GlyphIndex: 350 m_Scale: 1 - m_ElementType: 1 - m_Unicode: 51 - m_GlyphIndex: 22 + m_Unicode: 45 + m_GlyphIndex: 16 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 85 + m_GlyphIndex: 56 m_Scale: 1 m_AtlasTextures: - - {fileID: -2284082493848745064} + - {fileID: 7970078894227476819} m_AtlasTextureIndex: 0 m_IsMultiAtlasTexturesEnabled: 0 m_ClearDynamicDataOnBuild: 0 @@ -1774,577 +1704,581 @@ MonoBehaviour: m_Height: 28 - m_X: 122 m_Y: 0 - m_Width: 55 - m_Height: 85 + m_Width: 60 + m_Height: 83 + - m_X: 0 + m_Y: 32 + m_Width: 60 + m_Height: 83 - m_X: 67 m_Y: 28 m_Width: 52 - m_Height: 72 - - m_X: 0 - m_Y: 32 - m_Width: 52 - m_Height: 71 - - m_X: 177 - m_Y: 0 - m_Width: 40 - m_Height: 71 - - m_X: 217 - m_Y: 0 - m_Width: 52 - m_Height: 72 - - m_X: 269 - m_Y: 0 - m_Width: 52 - m_Height: 72 - - m_X: 321 - m_Y: 0 - m_Width: 47 - m_Height: 53 - - m_X: 368 - m_Y: 0 - m_Width: 52 - m_Height: 72 - - m_X: 177 - m_Y: 71 - m_Width: 30 - m_Height: 88 - - m_X: 119 - m_Y: 85 - m_Width: 50 - m_Height: 45 - - m_X: 52 - m_Y: 100 - m_Width: 52 - m_Height: 89 - - m_X: 321 - m_Y: 53 - m_Width: 47 - m_Height: 53 - - m_X: 0 - m_Y: 103 - m_Width: 32 - m_Height: 71 - - m_X: 0 - m_Y: 174 - m_Width: 46 - m_Height: 93 - - m_X: 207 - m_Y: 72 - m_Width: 80 m_Height: 83 - - m_X: 287 - m_Y: 72 - m_Width: 32 - m_Height: 87 - - m_X: 104 - m_Y: 130 - m_Width: 52 - m_Height: 71 - - m_X: 207 - m_Y: 155 - m_Width: 73 - m_Height: 70 - - m_X: 156 - m_Y: 159 - m_Width: 48 - m_Height: 83 - - m_X: 46 - m_Y: 189 - m_Width: 43 - m_Height: 80 - - m_X: 0 - m_Y: 267 - m_Width: 41 - m_Height: 88 - - m_X: 89 - m_Y: 201 + - m_X: 182 + m_Y: 0 m_Width: 55 - m_Height: 84 - - m_X: 420 - m_Y: 0 - m_Width: 57 m_Height: 83 - - m_X: 477 + - m_X: 237 m_Y: 0 - m_Width: 56 - m_Height: 84 - - m_X: 368 - m_Y: 83 - m_Width: 60 - m_Height: 83 - - m_X: 280 - m_Y: 159 - m_Width: 58 - m_Height: 70 - - m_X: 204 - m_Y: 225 - m_Width: 63 - m_Height: 93 - - m_X: 144 - m_Y: 242 - m_Width: 52 - m_Height: 89 - - m_X: 41 - m_Y: 285 - m_Width: 63 - m_Height: 83 - - m_X: 533 - m_Y: 0 - m_Width: 52 - m_Height: 89 - - m_X: 428 - m_Y: 84 m_Width: 52 m_Height: 72 - - m_X: 585 + - m_X: 289 m_Y: 0 m_Width: 69 m_Height: 71 - - m_X: 654 + - m_X: 358 m_Y: 0 - m_Width: 55 - m_Height: 85 - - m_X: 585 + m_Width: 37 + m_Height: 93 + - m_X: 289 m_Y: 71 - m_Width: 54 - m_Height: 83 - - m_X: 480 - m_Y: 89 - m_Width: 62 - m_Height: 83 - - m_X: 428 - m_Y: 156 - m_Width: 52 - m_Height: 89 - - m_X: 338 - m_Y: 166 - m_Width: 56 + m_Width: 58 m_Height: 70 - - m_X: 267 - m_Y: 229 + - m_X: 237 + m_Y: 72 + m_Width: 37 + m_Height: 83 + - m_X: 119 + m_Y: 83 m_Width: 55 m_Height: 84 - - m_X: 322 - m_Y: 236 - m_Width: 54 - m_Height: 83 - - m_X: 267 - m_Y: 313 - m_Width: 53 - m_Height: 88 - - m_X: 196 - m_Y: 318 - m_Width: 55 - m_Height: 83 - - m_X: 394 - m_Y: 166 - m_Width: 32 - m_Height: 32 - - m_X: 104 - m_Y: 331 - m_Width: 54 - m_Height: 83 - - m_X: 104 - m_Y: 285 - m_Width: 40 - m_Height: 28 - - m_X: 158 - m_Y: 331 - m_Width: 36 - m_Height: 106 - - m_X: 394 - m_Y: 198 + - m_X: 60 + m_Y: 111 m_Width: 30 - m_Height: 83 - - m_X: 0 - m_Y: 368 - m_Width: 52 m_Height: 88 - - m_X: 52 - m_Y: 414 - m_Width: 55 - m_Height: 85 - - m_X: 709 - m_Y: 0 - m_Width: 54 - m_Height: 83 - m_X: 0 - m_Y: 456 + m_Y: 115 m_Width: 52 - m_Height: 89 - - m_X: 107 - m_Y: 414 - m_Width: 51 - m_Height: 50 - - m_X: 763 - m_Y: 0 - m_Width: 55 - m_Height: 85 - - m_X: 709 + m_Height: 72 + - m_X: 0 + m_Y: 187 + m_Width: 43 + m_Height: 80 + - m_X: 174 m_Y: 83 - m_Width: 47 - m_Height: 83 - - m_X: 639 - m_Y: 85 - m_Width: 49 - m_Height: 83 - - m_X: 542 + m_Width: 40 + m_Height: 71 + - m_X: 174 m_Y: 154 m_Width: 52 - m_Height: 83 - - m_X: 480 - m_Y: 172 - m_Width: 55 - m_Height: 83 - - m_X: 424 - m_Y: 245 - m_Width: 49 - m_Height: 70 - - m_X: 818 + m_Height: 72 + - m_X: 90 + m_Y: 167 + m_Width: 37 + m_Height: 93 + - m_X: 395 m_Y: 0 m_Width: 59 m_Height: 83 - - m_X: 594 - m_Y: 154 - m_Width: 37 - m_Height: 93 - - m_X: 376 - m_Y: 281 - m_Width: 37 - m_Height: 83 - - m_X: 320 - m_Y: 319 - m_Width: 55 - m_Height: 84 - - m_X: 535 - m_Y: 237 - m_Width: 37 - m_Height: 93 - - m_X: 473 - m_Y: 255 - m_Width: 56 - m_Height: 88 - - m_X: 877 + - m_X: 454 m_Y: 0 - m_Width: 30 - m_Height: 45 - - m_X: 542 - m_Y: 89 - m_Width: 38 - m_Height: 44 - - m_X: 413 - m_Y: 315 - m_Width: 55 - m_Height: 85 - - m_X: 194 - m_Y: 401 - m_Width: 56 - m_Height: 85 - - m_X: 250 - m_Y: 401 - m_Width: 55 - m_Height: 84 - - m_X: 107 - m_Y: 464 m_Width: 52 - m_Height: 83 - - m_X: 52 - m_Y: 499 + m_Height: 89 + - m_X: 43 + m_Y: 199 + m_Width: 32 + m_Height: 87 + - m_X: 395 + m_Y: 83 + m_Width: 52 + m_Height: 71 + - m_X: 274 + m_Y: 141 + m_Width: 73 + m_Height: 70 + - m_X: 506 + m_Y: 0 m_Width: 55 - m_Height: 84 - - m_X: 818 - m_Y: 83 - m_Width: 56 - m_Height: 83 - - m_X: 874 - m_Y: 83 - m_Width: 54 - m_Height: 84 - - m_X: 375 - m_Y: 364 - m_Width: 38 - m_Height: 80 + m_Height: 85 + - m_X: 561 + m_Y: 0 + m_Width: 52 + m_Height: 89 + - m_X: 506 + m_Y: 85 + m_Width: 53 + m_Height: 88 - m_X: 0 - m_Y: 545 - m_Width: 46 - m_Height: 93 - - m_X: 818 - m_Y: 166 + m_Y: 267 + m_Width: 32 + m_Height: 71 + - m_X: 447 + m_Y: 89 + m_Width: 49 + m_Height: 83 + - m_X: 347 + m_Y: 154 m_Width: 52 - m_Height: 53 - - m_X: 928 - m_Y: 83 - m_Width: 94 - m_Height: 92 - - m_X: 870 + m_Height: 71 + - m_X: 399 + m_Y: 172 + m_Width: 52 + m_Height: 89 + - m_X: 451 + m_Y: 172 + m_Width: 52 + m_Height: 72 + - m_X: 226 + m_Y: 211 + m_Width: 49 + m_Height: 70 + - m_X: 127 m_Y: 167 + m_Width: 36 + m_Height: 106 + - m_X: 226 + m_Y: 155 + m_Width: 32 + m_Height: 32 + - m_X: 347 + m_Y: 93 + m_Width: 47 + m_Height: 53 + - m_X: 75 + m_Y: 260 + m_Width: 47 + m_Height: 53 + - m_X: 163 + m_Y: 226 m_Width: 55 m_Height: 95 + - m_X: 275 + m_Y: 211 + m_Width: 56 + m_Height: 70 + - m_X: 331 + m_Y: 225 + m_Width: 54 + m_Height: 83 + - m_X: 218 + m_Y: 281 + m_Width: 52 + m_Height: 83 + - m_X: 122 + m_Y: 273 + m_Width: 41 + m_Height: 88 + - m_X: 163 + m_Y: 321 + m_Width: 52 + m_Height: 88 + - m_X: 270 + m_Y: 281 + m_Width: 52 + m_Height: 72 + - m_X: 32 + m_Y: 313 + m_Width: 52 + m_Height: 89 + - m_X: 84 + m_Y: 361 + m_Width: 55 + m_Height: 83 + - m_X: 0 + m_Y: 338 + m_Width: 30 + m_Height: 45 + - m_X: 84 + m_Y: 313 + m_Width: 38 + m_Height: 44 + - m_X: 0 + m_Y: 402 + m_Width: 54 + m_Height: 84 + - m_X: 613 + m_Y: 0 + m_Width: 54 + m_Height: 83 + - m_X: 667 + m_Y: 0 + m_Width: 54 + m_Height: 83 + - m_X: 721 + m_Y: 0 + m_Width: 54 + m_Height: 83 + - m_X: 775 + m_Y: 0 + m_Width: 62 + m_Height: 83 + - m_X: 837 + m_Y: 0 + m_Width: 47 + m_Height: 83 + - m_X: 884 + m_Y: 0 + m_Width: 63 + m_Height: 83 + - m_X: 947 + m_Y: 0 + m_Width: 56 + m_Height: 85 + - m_X: 613 + m_Y: 83 + m_Width: 57 + m_Height: 83 + - m_X: 670 + m_Y: 83 + m_Width: 56 + m_Height: 84 + - m_X: 559 + m_Y: 166 + m_Width: 55 + m_Height: 84 + - m_X: 503 + m_Y: 173 + m_Width: 52 + m_Height: 83 + - m_X: 614 + m_Y: 166 + m_Width: 55 + m_Height: 84 + - m_X: 726 + m_Y: 83 + m_Width: 55 + m_Height: 84 + - m_X: 781 + m_Y: 83 + m_Width: 55 + m_Height: 85 + - m_X: 54 + m_Y: 402 + m_Width: 30 + m_Height: 83 + - m_X: 836 + m_Y: 83 + m_Width: 56 + m_Height: 88 + - m_X: 669 + m_Y: 167 + m_Width: 56 + m_Height: 83 + - m_X: 451 + m_Y: 244 + m_Width: 51 + m_Height: 50 + - m_X: 892 + m_Y: 83 + m_Width: 55 + m_Height: 85 + - m_X: 725 + m_Y: 167 + m_Width: 54 + m_Height: 85 + - m_X: 779 + m_Y: 168 + m_Width: 55 + m_Height: 85 + - m_X: 892 + m_Y: 168 + m_Width: 94 + m_Height: 92 + - m_X: 555 + m_Y: 250 + m_Width: 80 + m_Height: 83 + - m_X: 502 + m_Y: 256 + m_Width: 52 + m_Height: 53 + - m_X: 834 + m_Y: 171 + m_Width: 55 + m_Height: 85 + - m_X: 986 + m_Y: 85 + m_Width: 30 + m_Height: 93 + - m_X: 986 + m_Y: 178 + m_Width: 33 + m_Height: 84 + - m_X: 385 + m_Y: 261 + m_Width: 48 + m_Height: 83 + - m_X: 559 + m_Y: 89 + m_Width: 46 + m_Height: 45 + - m_X: 322 + m_Y: 308 + m_Width: 46 + m_Height: 93 + - m_X: 559 + m_Y: 134 + m_Width: 40 + m_Height: 28 + - m_X: 433 + m_Y: 294 + m_Width: 55 + m_Height: 84 m_FreeGlyphRects: - m_X: 119 m_Y: 28 m_Width: 3 - m_Height: 57 - - m_X: 52 + m_Height: 55 + - m_X: 60 m_Y: 32 - m_Width: 15 - m_Height: 68 - - m_X: 32 - m_Y: 103 - m_Width: 20 - m_Height: 71 - - m_X: 207 - m_Y: 71 - m_Width: 10 - m_Height: 1 - - m_X: 104 - m_Y: 100 - m_Width: 15 - m_Height: 30 - - m_X: 169 - m_Y: 85 - m_Width: 8 - m_Height: 74 - - m_X: 156 - m_Y: 130 - m_Width: 21 - m_Height: 29 - - m_X: 46 - m_Y: 103 - m_Width: 6 - m_Height: 86 - - m_X: 89 - m_Y: 189 - m_Width: 15 - m_Height: 12 - - m_X: 368 - m_Y: 72 - m_Width: 52 - m_Height: 11 - - m_X: 319 - m_Y: 72 - m_Width: 2 - m_Height: 87 - - m_X: 280 - m_Y: 155 m_Width: 7 - m_Height: 4 - - m_X: 204 - m_Y: 159 - m_Width: 3 - m_Height: 66 - - m_X: 144 - m_Y: 201 - m_Width: 12 - m_Height: 41 - - m_X: 41 - m_Y: 267 - m_Width: 5 - m_Height: 18 - - m_X: 41 - m_Y: 269 - m_Width: 48 - m_Height: 16 - - m_X: 428 - m_Y: 83 - m_Width: 49 - m_Height: 1 - - m_X: 480 - m_Y: 84 - m_Width: 53 - m_Height: 5 - - m_X: 267 - m_Y: 225 - m_Width: 13 - m_Height: 4 - - m_X: 322 - m_Y: 229 - m_Width: 16 - m_Height: 7 - - m_X: 196 - m_Y: 242 - m_Width: 8 - m_Height: 76 - - m_X: 104 - m_Y: 313 - m_Width: 40 - m_Height: 18 - - m_X: 0 - m_Y: 355 - m_Width: 41 - m_Height: 13 - - m_X: 756 - m_Y: 83 - m_Width: 7 - m_Height: 940 - - m_X: 639 - m_Y: 71 - m_Width: 15 - m_Height: 14 - - m_X: 688 - m_Y: 85 - m_Width: 21 - m_Height: 938 - - m_X: 426 - m_Y: 166 - m_Width: 2 m_Height: 79 - - m_X: 424 - m_Y: 198 - m_Width: 4 - m_Height: 47 - - m_X: 631 - m_Y: 154 + - m_X: 214 + m_Y: 83 + m_Width: 23 + m_Height: 71 + - m_X: 90 + m_Y: 111 + m_Width: 29 + m_Height: 56 + - m_X: 52 + m_Y: 115 m_Width: 8 - m_Height: 869 - - m_X: 376 - m_Y: 236 - m_Width: 18 - m_Height: 45 - - m_X: 320 - m_Y: 313 - m_Width: 2 - m_Height: 6 - - m_X: 535 - m_Y: 172 - m_Width: 7 - m_Height: 65 - - m_X: 572 - m_Y: 237 - m_Width: 22 - m_Height: 786 - - m_X: 473 - m_Y: 245 - m_Width: 7 - m_Height: 10 - - m_X: 529 - m_Y: 255 - m_Width: 6 - m_Height: 768 - - m_X: 529 - m_Y: 330 - m_Width: 494 - m_Height: 693 - - m_X: 542 - m_Y: 133 - m_Width: 43 - m_Height: 21 - - m_X: 580 - m_Y: 89 - m_Width: 5 - m_Height: 65 - - m_X: 413 - m_Y: 281 - m_Width: 11 - m_Height: 34 - - m_X: 468 - m_Y: 343 - m_Width: 555 - m_Height: 680 - - m_X: 468 - m_Y: 315 - m_Width: 5 - m_Height: 708 - - m_X: 194 - m_Y: 331 - m_Width: 2 - m_Height: 70 - - m_X: 251 - m_Y: 318 - m_Width: 16 - m_Height: 83 - - m_X: 250 - m_Y: 485 - m_Width: 773 - m_Height: 538 - - m_X: 305 - m_Y: 401 + m_Height: 84 + - m_X: 43 + m_Y: 187 + m_Width: 17 + m_Height: 12 + - m_X: 274 + m_Y: 72 m_Width: 15 - m_Height: 622 - - m_X: 159 - m_Y: 486 - m_Width: 864 - m_Height: 537 - - m_X: 158 - m_Y: 437 - m_Width: 36 + m_Height: 69 + - m_X: 447 + m_Y: 83 + m_Width: 7 + m_Height: 6 + - m_X: 399 + m_Y: 154 + m_Width: 48 + m_Height: 18 + - m_X: 496 + m_Y: 89 + m_Width: 10 + m_Height: 83 + - m_X: 226 + m_Y: 83 + m_Width: 11 + m_Height: 72 + - m_X: 226 + m_Y: 187 + m_Width: 48 + m_Height: 24 + - m_X: 258 + m_Y: 155 + m_Width: 16 + m_Height: 56 + - m_X: 347 + m_Y: 71 + m_Width: 11 + m_Height: 22 + - m_X: 347 + m_Y: 146 + m_Width: 48 + m_Height: 8 + - m_X: 394 + m_Y: 93 + m_Width: 1 + m_Height: 61 + - m_X: 75 + m_Y: 199 + m_Width: 15 + m_Height: 61 + - m_X: 163 + m_Y: 167 + m_Width: 11 + m_Height: 59 + - m_X: 331 + m_Y: 211 + m_Width: 16 + m_Height: 14 + - m_X: 218 + m_Y: 226 + m_Width: 8 + m_Height: 55 + - m_X: 122 + m_Y: 260 + m_Width: 5 + m_Height: 13 + - m_X: 215 + m_Y: 321 + m_Width: 3 + m_Height: 702 + - m_X: 32 + m_Y: 267 + m_Width: 11 + m_Height: 46 + - m_X: 32 + m_Y: 286 + m_Width: 43 m_Height: 27 - - m_X: 159 - m_Y: 437 - m_Width: 35 - m_Height: 586 - - m_X: 107 - m_Y: 547 - m_Width: 916 - m_Height: 476 - - m_X: 877 - m_Y: 45 - m_Width: 34 - m_Height: 38 - - m_X: 907 + - m_X: 139 + m_Y: 409 + m_Width: 884 + m_Height: 614 + - m_X: 139 + m_Y: 361 + m_Width: 24 + m_Height: 662 + - m_X: 84 + m_Y: 357 + m_Width: 38 + m_Height: 4 + - m_X: 0 + m_Y: 486 + m_Width: 1023 + m_Height: 537 + - m_X: 0 + m_Y: 383 + m_Width: 32 + m_Height: 19 + - m_X: 30 + m_Y: 338 + m_Width: 2 + m_Height: 64 + - m_X: 503 + m_Y: 89 + m_Width: 3 + m_Height: 84 + - m_X: 54 + m_Y: 485 + m_Width: 969 + m_Height: 538 + - m_X: 84 + m_Y: 444 + m_Width: 939 + m_Height: 579 + - m_X: 669 + m_Y: 166 + m_Width: 1 + m_Height: 1 + - m_X: 779 + m_Y: 167 + m_Width: 2 + m_Height: 1 + - m_X: 555 + m_Y: 173 + m_Width: 4 + m_Height: 77 + - m_X: 635 + m_Y: 250 + m_Width: 90 + m_Height: 773 + - m_X: 635 + m_Y: 252 + m_Width: 144 + m_Height: 771 + - m_X: 502 + m_Y: 244 + m_Width: 1 + m_Height: 12 + - m_X: 554 + m_Y: 256 + m_Width: 1 + m_Height: 767 + - m_X: 834 + m_Y: 168 + m_Width: 2 + m_Height: 3 + - m_X: 889 + m_Y: 171 + m_Width: 3 + m_Height: 852 + - m_X: 635 + m_Y: 256 + m_Width: 257 + m_Height: 767 + - m_X: 635 + m_Y: 253 + m_Width: 199 + m_Height: 770 + - m_X: 1003 + m_Y: 0 + m_Width: 20 + m_Height: 85 + - m_X: 947 + m_Y: 85 + m_Width: 39 + m_Height: 83 + - m_X: 635 + m_Y: 262 + m_Width: 388 + m_Height: 761 + - m_X: 635 + m_Y: 260 + m_Width: 351 + m_Height: 763 + - m_X: 1016 + m_Y: 0 + m_Width: 7 + m_Height: 178 + - m_X: 1019 m_Y: 0 m_Width: 4 - m_Height: 83 - - m_X: 375 - m_Y: 319 - m_Width: 1 - m_Height: 45 - - m_X: 413 - m_Y: 400 - m_Width: 610 - m_Height: 623 - - m_X: 305 - m_Y: 444 - m_Width: 718 - m_Height: 579 - - m_X: 305 - m_Y: 403 - m_Width: 70 - m_Height: 620 - - m_X: 0 - m_Y: 638 - m_Width: 1023 - m_Height: 385 - - m_X: 46 - m_Y: 583 - m_Width: 977 - m_Height: 440 - - m_X: 46 - m_Y: 545 - m_Width: 6 - m_Height: 478 - - m_X: 631 - m_Y: 168 - m_Width: 187 - m_Height: 855 - - m_X: 1022 - m_Y: 83 - m_Width: 1 - m_Height: 940 - - m_X: 572 - m_Y: 262 - m_Width: 451 - m_Height: 761 - - m_X: 572 - m_Y: 247 - m_Width: 298 - m_Height: 776 - - m_X: 631 - m_Y: 219 - m_Width: 239 - m_Height: 804 - - m_X: 870 - m_Y: 166 - m_Width: 4 - m_Height: 1 - - m_X: 925 - m_Y: 175 - m_Width: 98 - m_Height: 848 - - m_X: 925 - m_Y: 167 - m_Width: 3 - m_Height: 856 + m_Height: 1023 + - m_X: 385 + m_Y: 225 + m_Width: 14 + m_Height: 36 + - m_X: 559 + m_Y: 85 + m_Width: 2 + m_Height: 4 + - m_X: 605 + m_Y: 89 + m_Width: 8 + m_Height: 77 + - m_X: 215 + m_Y: 401 + m_Width: 808 + m_Height: 622 + - m_X: 215 + m_Y: 364 + m_Width: 107 + m_Height: 659 + - m_X: 270 + m_Y: 353 + m_Width: 52 + m_Height: 670 + - m_X: 322 + m_Y: 281 + m_Width: 9 + m_Height: 27 + - m_X: 368 + m_Y: 308 + m_Width: 17 + m_Height: 715 + - m_X: 559 + m_Y: 162 + m_Width: 54 + m_Height: 4 + - m_X: 599 + m_Y: 134 + m_Width: 14 + m_Height: 32 + - m_X: 433 + m_Y: 261 + m_Width: 18 + m_Height: 33 + - m_X: 488 + m_Y: 333 + m_Width: 535 + m_Height: 690 + - m_X: 488 + m_Y: 309 + m_Width: 67 + m_Height: 714 + - m_X: 488 + m_Y: 294 + m_Width: 14 + m_Height: 729 + - m_X: 368 + m_Y: 378 + m_Width: 655 + m_Height: 645 + - m_X: 368 + m_Y: 344 + m_Width: 65 + m_Height: 679 m_fontInfo: Name: PointSize: 0 @@ -2424,3 +2358,50 @@ MonoBehaviour: boldSpacing: 7 italicStyle: 35 tabSize: 10 +--- !u!28 &7970078894227476819 +Texture2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Korolev Condensed W04 Bold Atlas + m_ImageContentsHash: + serializedVersion: 2 + Hash: 00000000000000000000000000000000 + m_ForcedFallbackFormat: 4 + m_DownscaleFallback: 0 + m_IsAlphaChannelOptional: 0 + serializedVersion: 2 + m_Width: 1024 + m_Height: 1024 + m_CompleteImageSize: 1048576 + m_MipsStripped: 0 + m_TextureFormat: 1 + m_MipCount: 1 + m_IsReadable: 1 + m_IsPreProcessed: 0 + m_IgnoreMasterTextureLimit: 0 + m_StreamingMipmaps: 0 + m_StreamingMipmapsPriority: 0 + m_VTOnly: 0 + m_AlphaIsTransparency: 0 + m_ImageCount: 1 + m_TextureDimension: 2 + m_TextureSettings: + serializedVersion: 2 + m_FilterMode: 1 + m_Aniso: 1 + m_MipBias: 0 + m_WrapU: 0 + m_WrapV: 0 + m_WrapW: 0 + m_LightmapFormat: 0 + m_ColorSpace: 0 + m_PlatformBlob: + image data: 1048576 + _typelessdata: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010406070b0e0e0c08080602000000000000020507080c0e0e0c08070502000000000000030608090c0e0d0b0706040100000000000000000000000000000000000406070f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f08070502000000000000000000000000000206080813131313131313131313130807050200000000000000000001050707131313131313131313131308070502000000000000000000000000050a0d1010131313131313131313100f0d0a0500000000000002070a0c0d1313131313131313130e0d0b08030000000000000000000000000000000000000000000406070a0d0e0f0f0e0b080806020000000606060606060606060000000000000000000000000000000003080b0d0e1313131313131313130c0b09050103090d10121313131313131313131308070502000005080a0b131313131313131313100f0d0905000000000000000000000000000000000000000000000000000001000004060706060300000000000000000000000000000000000000000000000000000002070a0c0d13131313131313131313100f0d0a0500000000000000000000000000000000000000000000000000000000000000000000010406070a0d0f0f0f0e0c090605030000000606060606060606060000000000000000000000000000000000000000000000000000000000020608080b0e0f1011100f0e0c090806030000000000000000000000000000000000000000000000000000000001010606060606060606050400010406070a0d0e0f0f0e0c08080602000000000000000000000000000000000000000001070b0f111213131313131313131313131313131313131211100e0b080806020000000000000000000000000000000000000000000001070b0f1112131313131313131313100f0d0a050000000002080c1012121313131313131313130e0d0b08030000000000000000000001070b0f1112131313131313131313100f0d0a050000000004080a0a1313131313131313131313090806030000000000000000000000000106090b0c131313131313131313130a09070400000000000000000000000004090d0f0f1313131313131313131307060400000000000000000000000001070b0f111213131313131313131313131313131313131313131313131313131212100c080200000000000000000000050a0d10101313131313131313130f0e0c0804000000000000000000000000000003070b0d0e1313131313131313131312100d0802000000000000000000000000000000000000000000000000040607090c0e0f101110100f0d0b08070502000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d101314181a1b191514120f0903000002090e111414191b1b191414110e09020000030a0f121515191b1a181413100d070100000000000000000000000000070c1012131c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1514120e090300000000000000000003090f12141520202020202020202020201414110e0802000000000002080d11131420202020202020202020201514120e09020000000000000000030a11161a1c1d2020202020202020201d1c1916100a03000000070e1317191a2020202020202020201b1a18140f08010000000000000000000000000000000001070c101314171a1b1c1c1b181514120e09090a131313131313131313080705020000000000000000000001080f14181a1b202020202020202020181815110c0e14191d1f202020202020202020201514120e090c111417182020202020202020201d1c1915100a0300000000000000000000000000000000000000010507070b0d070c10121313120f0b06000000000000000000000000000000000000000000000000080e1317191a202020202020202020201d1c1a16110a0300000000000000000000000000000000000000000000000000000000000001070d111314171a1b1c1c1b191513120f0b060a13131313131313131308070502000000000000000000000000000000000000000000000104090e121415181a1c1d1d1d1c1b191615130f0a05020000000000000000000000000000000000000000000003080b0d0e13131313131313131111080d111314171a1b1c1b1a191514120e09030000000000000000000000000000000000050c12171b1d1e20202020202020202020202020202020201f1e1d1b181514120f0a0502000000000000000000000000000000000000050c12171b1d1e2020202020202020201d1c1916100a0300060d13181c1e1f2020202020202020201b1a18140f080100000000000000050c12171b1d1e2020202020202020201d1c1916100a03050b1014161720202020202020202020201615130f0a04000000000000000000060d1215181920202020202020202020171613100b05000000000000000002091015191b1c202020202020202020201413100c07010000000000000000050c12171b1d1e20202020202020202020202020202020202020202020202020201f1e1c18130d0600000000000000030a11161a1c1d2020202020202020201c1b18140f09020000000000000000000001080e13171a1a2020202020202020201f1f1c19140d06000000000000000000000000000000000000000000070c10131316191b1c1d1d1d1d1c1a181514120e09050200000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c12181d20202427272622211f1a150c07060b141a1e20212527272521201e19140b06070c151a1f21222627272420201d18120c0400000000000000000000030b12181c1f202929292929292929292929292929292929292929292929292929292929292929292921211e1a140d0500000000000000060e151a1f21222d2d2d2d2d2d2d2d2d2d2c21201e19140d05000000050c13191d20212c2d2d2d2d2d2d2d2d2d2c21201e1a140d05000000000000040d151c2226292a2d2d2d2d2d2d2d2d2d292926211c150d04010a12191f2326262d2d2d2d2d2d2d2d2d272724201a130b020000000000000000000000000002090e12181c1f202426282928272522211e1a1516172020202020202020201414110e080200000000000000020b131a202427272d2d2d2d2d2d2d2d2d2524221d18191f25292b2c2d2d2d2d2d2d2d2d2d21201e1a14171d2123242d2d2d2d2d2d2d2d2d292826211b140c040000000000000000000000000000000002080d111314171a1c181c1f20201f1c17110a020000000000000000000000000000000000000000020a12191f2326272d2d2d2d2d2d2d2d2d2d2a2926221c150d0400000000000000000000000000000000000000000000000000000003090e13181d20212426282928272522201f1b1716172020202020202020201414110e080200000000000000000000000000000000000001080d11151a1e21222527292a2a2a29272522211f1b15110e080200000000000000000000000000000000000001080f14181a1b20202020202020201e1d13191d20212427282928272522211e1a15100b060000000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c2c2b29282522211f1a15120e0903000000000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d292926211c150d0710181f24282b2c2d2d2d2d2d2d2d2d2d272724201a130b020000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d292926211c150d10171c2023242d2d2d2d2d2d2d2d2d2d2d22211f1b150e07000000000000010911181e2224252d2d2d2d2d2d2d2d2d2d2322201c160f08000000000000030c141b212528292d2d2d2d2d2d2d2d2d2c201f1c18120b03000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c2b28241f1810070000000000040d151c2226292a2d2d2d2d2d2d2d2d2d282725201a130c030000000000000000020b12191f2326272d2d2d2d2d2d2d2d2d2c2b29251f1810080000000000000000000000000000000000040a0f12181c1f20232627292a2a2a2928272422211e1a14120e090300000000000000000000000000000000000000000000000000000000000000000000000000000000080d161d24292c2d313434332f2e2b2620181211171f252a2d2e323434322e2d2a251f1711121820262b2e2f333434312d2c29241d160d080000000000000000030c151c23282c2d353535353535353535353535353535353535353535353535353535353535353535352e2d2a251f170f050000000000060f1820262b2e2f39393939393939393939392e2d2a251f170e0500050e161e252a2d2e39393939393939393939392e2d2a251f170f0500000000030d161f272d3236373939393939393939393635322d261f160d0a131c242a2f32333939393939393939393433302b251d140b010000000000000000000000050d141a1d23292c2d303334353534322e2d2b261f22232d2d2d2d2d2d2d2d2d21201e19140d050000000000010b141d252b30333439393939393939393932312e2923232a313538393939393939393939392e2d2a251f22282d30313939393939393939393635322d261e160c0300000000000000000000000000050b1013191d202124272923282c2d2d2b28221c140b02000000000000000000000000000000000000000a141c242a2f3233393939393939393939393635322d271f160d0000000000000000000000000000000000000000000000000000060e151a1d24292c2d313335363534322f2d2b272222232d2d2d2d2d2d2d2d2d21201e19140d0500000000000000000000000000000000070c13191d20262b2d2e3234363637363634322f2e2b26201e19140d0701000000000000000000000000000000020b131a202427272d2d2d2d2d2d2d2d2b2a1e24292c2d303335363534322f2e2b261f1c17110a020000000000000000000000050f1820282f333738393939393939393939393939393939393939383634322f2e2b26211e1a140e0802000000000000000000000000050f1820282f3337383939393939393939393635322d261f1610192229303538393939393939393939393433302b251d140b01000000050f1820282f3337383939393939393939393635322d261f161a21282d303139393939393939393939392f2e2b2620181007000000000009131b23292e313239393939393939393939302f2c272119110800000000020c151e262c313536393939393939393939392d2c29231d150d0300000000050f1820282f3337383939393939393939393939393939393939393939393939393939393835302922191006000000030d161f272d3236373939393939393939393534312c251e150c02000000000000010b141d242b303334393939393939393939393835302a221a10060000000000000000000000000000040a0f161b1d23282c2d30323436363737363533312e2d2b26211e1a140d08020000000000000000000000000000000000000000000000000000000000000000000000000008111a1f282f35393a3e41413f3b3a373129241d1b222730363a3b3f41413f3b3a363027221b1d242931373a3c3f41403e3a39352f281f1a1109000000000000000b151e272e34383a424242424242424242424242424242424242424242424242424242424242424242423b3a36312921170d03000000030e18212a31373a3b46464646464646464646463b3936302920170d020c1620283036393a46464646464646464646463b3a36302921170d020000000a151f2831383e424346464646464646464643423e3831281f150c1c262e353b3f4046464646464646464641403c362f261d130800000000000000000001090f171f252a2f34383a3d40414242413e3b3a37312c2f303939393939393939392e2d2a251e170e050000000008131d262f363c40414646464646464646463f3d3a342d2c353c4145464646464646464646463b3a3630292c33393d3e46464646464646464643413e3830281e140a000000000000000000000003090e161c1e252a2d2e3134362e34383a3938332d261d140a00000000000000000000000000000000000008121c262e363b3f404646464646464646464643423e3831281f0c030000000000000000000000000000000000000000000000010a0f1820262b2f35393a3d40424242413f3c3937332d2f303939393939393939392e2d2a251e170e0500000000000000000000000000030b12181e24292c31373a3b3e414243444342413f3c3b37322d2a251f18120c0400000000000000000000000000010b141d252b30333439393939393939393837332f35393a3d40414242413f3b3a37312b28231c140c06000000000000000000010c16202a323a3f43454646464646464646464646464646464646454443413e3b3a37312d2a261f19140d0500000000000000000000010c16202a323a3f434546464646464646464643423e3831281f18222b343b41444546464646464646464641403c362f261d13080000010c16202a323a3f434546464646464646464643423e3831281f232c33393c3d46464646464646464646463c3b37322a22180e0400000006111b252d343a3e3f464646464646464646463d3c38332b23190f0500000009141e2730373d4142464646464646464646463a38342f271f150b010000010c16202a323a3f434546464646464646464646464646464646464646464646464646464544413b342b22180d0200000a151f2831383e424346464646464646464642403d372f271e130900000000000008121d262f363c3f414646464646464646464644413b342c22180d02000000000000000000000000060b151b21272c2e34383a3c3f41424344434342403e3b3a37312d2a251f19140d05000000000000000000000000000000000000000000000000000000000000000000000008121a232c31394045474b4d4e4c4847433c352f27262d333b4246474c4e4e4c4746423b332d26272f353c4347484c4e4d4b47454039312c241b1209000000000007121c2730394044464f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4846423b33291f14090000000915202a333c43474853535353535353535353534746413b32291f1408131e28323a41464753535353535353535353534846423b33291f1409000005111c27313a434a4e50535353535353535353504e49423a31261c151e2e3840474b4d5353535353535353534e4c4841382f251a0f0300000000000000020a131b21293036394045474a4d4e4f4f4e4b4847423c383c3d4646464646464646463b3936302920170d020000030f1a252f3841484c4e5353535353535353534b4a453f37353e474d51535353535353535353534846423b33363e45494b535353535353535353504e49423a30261b1005000000000000000000050d141a21282c3036393a3e40434440444646443f382f261c110600000000000000000000000000000000020e19242e3840474b4d53535353535353535353504e4a433a311e150b00000000000000000000000000000000000000000000020b131c212a31373a4145474a4d4e4f4f4e4c4846443f383c3d4646464646464646463b3936302920170d020000000000000000000000060c151c23282f35393c4247484b4d4f5050504f4e4c4947433c39363029241d160d0700000000000000000000000008131d262f363c4041464646464646464644433f3a4145474a4d4e4f4e4d4c4847423c38342e261e180f07000000000000000007121d28323c444b505153535353535353535353535353535353535251504e4b4847433c3a36312a251e170e0800000000000000000007121d28323c444b5051535353535353535353504e49423a31261f29343d464c51525353535353535353534e4c4841382f251a0f030007121d28323c444b5051535353535353535353504e49423a31262c353e44494a53535353535353535353534947433c342a20150a0000010d18232d373f464a4c535353535353535353534a48443d352b21160b000004101b26303942494d4f535353535353535353534745403931271d1207000007121d28323c444b5051535353535353535353535353535353535353535353535353535352514c463d34291f13080005111c27313a434a4e505353535353535353534f4d4841392f251a0f0400000000030e19242f3840474c4d53535353535353535352514d463e342a1f140800000000000000000000020a111720262b323839404546494c4e4f505050504f4d4b4846423c3a36312a251e170e08000000000000000000000000000000000000000000000000000000000000000000050e1a242c353e434b5153575a5a5955534e454039312f383f444d5254585a5a5854524d443f382f313940454e5355595a5a5753514b433e362d241b0f06000000000c18232e39424a51535c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c54534d453b31251a0e0200020f1a26313c464e5355606060606060606060605f54524d443b3025190e1925303a444c52545f6060606060606060605f54524d453b30251a0e02000a16222d38434d555b5d6060606060606060605c5a544c42382d211c2630404a5257596060606060606060605a58534a41362b201408000000000000010a141c252d333b42464b515357595b5c5b5a5855534d4644484a5353535353535353535346413b32291e140800000814202b36414a53585a606060606060606060585651493f3c4750585e5f6060606060606060605f524d453b3e485055576060606060606060605c5a544c42382d2115090000000000000000070f171f252a33383a4146474a4d4f514a515353504a42382d22170b0000000000000000000000000000000007131f2a36404a52585a606060606060606060605d5a544c4330271c12070000000000000000000000000000000000000000010b141d252e333c42474b515457595b5c5b5a585553504945484a5353535353535353535346413b32291e140800000000000000000000080f181e272e343a4145474d5355585a5c5d5d5d5c5a5855534e4746413b352f281f19100900000000000000000000030f1a252f3841484c4e5353535353535353514f4b474c5254575a5b5c5b5a5855534d46443f38302a21191007000000000000000b17232f3a444e565c5e606060606060606060606060606060605f5f5e5c5b5855534e4846423b363029201a110800000000000000000b17232f3a444e565c5e6060606060606060605c5a544c42382d24303b464f575d5f6060606060606060605a58534a41362b201408000b17232f3a444e565c5e6060606060606060605c5a544c42382d333e474f5557606060606060606060606055534e463c32261b0f030006121e29343f495156586060606060606060606056544f473d33271c1004000915212c37424c545a5c6060606060606060605f53514b43392f23180c00000b17232f3a444e565c5e60606060606060606060606060606060606060606060606060605f5d574f463b3024180c000a16222d38434d555b5d6060606060606060605b59534b41372c2014080000000007131f2b36404a52585a6060606060606060605f5d5850463b3025190d000000000000000000030b141c222832373d43484b515356595a5c5d5d5d5c5b5a5755534d4846423b363029201a110a01000000000000000000000000000000000000000000000000000000000000020d17202c363e474f555d6064676766625f58514b433938414950575e6165676765615e565049413839434b51585f6266676764605d5550483e362d21180e03000004101c2834404a545c6068686868686868686868686868686868686868686868686868686868686868686868615e574d42362a1e12050006121f2b37434e585f626c6c6c6c6c6c6c6c6c6c6c615e564d41362a1c111d2a36414c565e616c6c6c6c6c6c6c6c6c6c6c615e574d42362a1e1205000d1a26323e4a555f666a6c6c6c6c6c6c6c6c6c69665e54493e3226232e3842525c63666c6c6c6c6c6c6c6c6c67645c53483c3024180b0000000000000a131c262e373f454d52555c6063666768686765615f57535154566060606060606060605f524c443b3025190e02000b1824303c48535c64676c6c6c6c6c6c6c6c6c65625b5145414d58626a6c6c6c6c6c6c6c6c6c6c6c5e574d4245505a61646c6c6c6c6c6c6c6c6c69665e54493e3226190d00000000000000071019212930363e44484c5254575a5c5e5f5c60605b544a3f33281c0f030000000000000000000000000000000a17232f3b47525c63666c6c6c6c6c6c6c6c6c6c69665e5442392e23180c000000000000000000000000000000000000000009131d262f373f454e53555d606466686968676562605b535154566060606060606060605f524c443b3025190e02000000000000000008111a212a303940444c5254575f61656769696a69696765625f5854524d454039312b221b12090000000000000000000814202b36414a53585a60606060606060605e5c5653565d6063666869686765625f5753504a423c332b22190f050000000000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6b696765625f5855534d46413b322c231a1108000000000000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c69665e54493e322835414c5761696c6c6c6c6c6c6c6c6c6c67645c53483c3024180b000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c69665e54493e3239444f5961646c6c6c6c6c6c6c6c6c6c6c625f584e43372b1f1306000915222e3a46515b62656c6c6c6c6c6c6c6c6c6c6360594f44382c201307000d1925313d49545e65696c6c6c6c6c6c6c6c6c6c6a5c554b4034291c1004000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6961574c4135281c10000d1a26323e4a555f666a6c6c6c6c6c6c6c6c6c68655d53483d3125180c000000000b1723303c47525c64676c6c6c6c6c6c6c6c6c6c6962584d4135291c100000000000000000030c151d262d333c43474f54545c6063656769696a6a69686664615f5754534d46413b322c231c130a01000000000000000000000000000000000000000000000000000000000008141e29323e48505961676d717474726e6a605d554b423f49535b60696e727474726e69605b53493f424b555d606a6f727473716d67615a50483e332a1f1409000006121f2c3844515c666d757575757575757575757575757575757575757575757575757575757575757575756e695e53463a2d211407000814212e3a47535f6a6e79797979797979797979796e685e5246382e2317202d3946525e686d79797979797979797979796e695e52463a2d20140700101c2936424e5b6671767979797979797979797670665a4e42352928343f4a54636e73797979797979797979746e64584c4033271a0d0000000000060f1c252e38404951575e61676d707374757574716e6964605c60636c6c6c6c6c6c6c6c6c6c5e564c41362a1e1105000d1a2733404c58646e74797979797979797979726d62564a45515e6a747979797979797979797976695e52464955616c717979797979797979797670665a4e4135281c0f000000000000060f19222b333b42464f55565e616467696a6c666d6c665b5044382b1f12060000000000000000000000000000000c1926323f4b58636e7379797979797979797979767066544a4034281c1004000000000000000000000000000000000000060f1b252f38414951575f62676d707375757574726f6c65605d60636c6c6c6c6c6c6c6c6c6c5e564c41362a1e11050000000000000008111a232b333c424a51565d6066696e7174757677767574726f6a66615e56514b433d342d241b120900000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6b67605f62686d707374757574726e6965605c544e463d342b21170b020000000000111d2a3743505c687278797979797979797979797979797979797978777674716e6a67615f57524c443e352c231a1007000000000000111d2a3743505c6872787979797979797979797670665a4e42352b3844515d697378797979797979797979746e64584c4033271a0d00111d2a3743505c6872787979797979797979797670665a4e42353c4955616c707979797979797979797979766a5f53473b2e211508000b1824313e4a56626d7279797979797979797979706b6054483c2f221606000f1b2835414d5a6570757979797979797979797975675c5145382c1f130600111d2a3743505c68727879797979797979797979797979797979797979797979797979797873695d5144382b1e1200101c2936424e5b667176797979797979797979756f65594d4034271b0e000000000d1a26333f4c58646e747979797979797979797974695d5144382b1f1200000000000000020c151e272f383f444e53596063666d6f727475767776767573716e6966615e57524c443e362e251c130a00000000000000000000000000000000000000000000000000000000020e1925303b44505a616b70797e80817f7b746d675d544a44505b656c737b7f81817f7b736c655b50444a545d676d747c7f81807e79706c625a50453c31261a0e02000713202d3a4653606d78818282828282828282828282828282828282828282828282828282828282828282827b6e6154483b2e211508000815222f3b4855626e7b88868686868686868686877a6e61544a3f34281c27333f4953616d7a86868686868686868686877b6e6154483b2e21150800101d2a3743505d6a76838686868686868686868276695c504336292c3844505c6673808686868686868686868174675a4e4134271b0e00000000030e18212d37404a525b62696e74797d80818282817e7b77716d666b7079797979797979797976685e5246392d201407000e1b2734414e5a6774818686868686868686867f7265584b46535f6c79868686868686868686867b6e6154484b5764717e8686868686868686868276695c504336291d100000000000020b18212b343d454d52596163686d71737677787979786c605346392d201306000000000000000000000000000003101c28343f4a54667380868686868686868686868276665c5144382c1f12060000000000000000000000000000000000030e18212d37414a525b636a6e747a7d80818282817f7c78726d676b7079797979797979797976685e5246392d201407000000000000060f1a232b353d454e545c60686d72777b7e808283838382817f7c78736e68605d554e463f362d241b1107000000000000000d1a2733404c58646e7479797979797979797772606a6f747a7d80818281807f7b77716d665f584e463d33291d140a0000000000121e2b3845515e6b78848686868686868686868686868686868686858483817e7b77736e69615e564f473e362c22190c030000000000121e2b3845515e6b78848686868686868686868276695c5043362c3945525f6c78858686868686868686868174675a4e4134271b0e00121e2b3845515e6b78848686868686868686868276695c504337434e5864707e86868686868686868686867c6f6255493c2f221609000c1925323f4c5865727f868686868686868686867d7063564a3d2d22170b05121e2b37424d5769758286868686868686868687796d6053473a2d20140700121e2b3845515e6b7884868686868686868686868686868686868686868686868686868685786c5f5245392c1f1200101d2a3743505d6a76838686868686868686868175685b4f4235281c0f0c0c0c0c0e1a2734414d5a67748086868686868686868686796c5f5246392c1f13000000000000000a141e273039424a50585f626b6f75797c7f81828383838382807e7b77736e69615e5650483f372e251c110800000000000000000000000000000000000000000000000000000005111e2a36414c56616c717d858a8d8d8c8781796d665c51505a606c777f868b8d8d8b867f776c605a50515c666d7981878c8d8d8a857e716c62574d42372b1e1205000714202d3a4753606d79868f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f887b6f6255483c2f221509000814212e3a47535f6a76828f93939393939393998c7f73665c5044382b1f2b3744505b65727f8c98939393939393938e8175695e52463a2d20140700101d2a3743505d6a768390939393939393938f8376695c504336292d3a4653606d798491939393939393938d8174675a4e4134271b0e000000000915202a333f49525c646d727b81868a8c8e8f8e8d8b88837e786e707d8686868686868686867a6e6154473b2e211408000e1b2734414e5a6774818d939393939393938b7e7265584b46535f6c79869293939393939393877b6e6154484b5764717e8a939393939393938f8276695c504336291d1000000000000a141d2a333d464e575e616b70767a7d8082848586867d706356493d3023160a000000000000000000000000000006121f2b3844505c6676839093939393939393939286796d6053463a2d20130700000000000000000000000000000000000915202a333f49525c646d727b81868a8c8e8f8e8d8b88847f796f707d8686868686868686867a6e6154473b2e2114080000000000030c18212b353d474f575f666d727a7f84888b8d8f9090908f8d8b8884807b736d67605850483f362d23190d030000000000000e1b2734414e5a677480868686868686868684776d737c81868a8d8e8f8e8d8b88847e786e6a60584e453b2f261b110600000000121e2b3845515e6b7884919393939393939393939393939393999292918f8e8b8884807b756e68615950483e342a1e150b0000000000121e2b3845515e6b788491939393939393938f8376695c5043362c3945525f6c788592939393939393938d8174675a4e4134271b0e00121e2b3845515e6b788491939393939393938f8376695c50433a47535f6a76828f93939393939393938f82766a5f53473b2e211508000916222f3c4955626f7c8897939393939393938c7f736653493f33271b0f0714212d3a46535f6978859293939393939393908376675c5145382c1f130600121e2b3845515e6b7884919393939393939393939393939393939393939393939393939285786c5f5245392c1f1200101d2a3743505d6a768390939393939393938e8275685b4f4235281c1919191919191a2734414d5a6774808d939393939393939286796c5f5246392c1f1300000000000006111c263039424b545b606a6f767c8185898c8d8f9090908f8e8d8a8884807b746e68615a51493f372d231a0d0400000000000000000000000000000000000000000000000000000714202d3946525e68717e8791979a9a9a938e82786d605455616c74808c92989a9a98928c80746c615554606d78828e939a9a9a9791887e71695f53463a2d211407000714202d3a4753606d7a86939b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b95887b6f6255483c2f2215090006121f2b37434e5863707d8a95a09f9f9f9f9f9e9184786d6053463b31262d394653606c7884919e9f9f9f9f9f9f95897c6f62574d42362a1e120500101d2a3743505d6a7683909d9f9f9f9f9f9c8f8376695c5043362a36424d5764717d8a97a19f9f9f9f9f9a8d8174675a4e4134271b0e000000020e1a26313c45515b646e737f868e9298999a9b9b9a9895908b837b707d8993939393939393877a6e6154473b2e211408000e1b2734414e5a6774818d9a9f9f9f9f9f988b7e7265584b46535f6c7986929f9f9f9f9f9f94877b6e6154484b5764717e8a979f9f9f9f9f9c8f8376695c504336291d100000000006111c262f3b454e5860696e767d82868a8d8f919292897c706356493d3023160a00000000000000000000000000000713202d3a4653606d7985929f9f9f9f9f9f9fa398887c6f6255493c2f22160800000000000000000000000000000000020f1a26313c46515b646e747f868e9299999b9c9b9a9896918c847c717d8993939393939393877a6e6154473b2e21140800000000000b151e2a333d474f59606a6e787f858c9195989a9c9c9d9c9c9a9896918d8680796f6a625a50483f352b1f150b0100000000000e1b2734414e5a6774818d939393939393918477787f878e9298999b9c9b9a9896918b837c6f6a60574d41382d22170b00000000121e2b3845515e6b7884919e9f9f9f9f9f9f9f9f9f9f9f9f9fa39f9f9e9c9a9896918d87817a706b615a50463c30271d120700000000121e2b3845515e6b7884919e9f9f9f9f9f9c8f8376695c5043362c3945525f6c7885929f9f9f9f9f9f9a8d8174675a4e4134271b0e00121e2b3845515e6b7884919e9f9f9f9f9f9c8f8376695c5043414c55626e7b88949f9f9f9f9f9fa095897d7063584e43372b1f1306000613202d394653606c7985929f9f9f9f9f9f9c8f8276655b5044372b1f120815222e3b4855616e7b8897a19f9f9f9f9f998d807366554b4034291c100400121e2b3845515e6b7884919e9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9285786c5f5245392c1f1200101d2a3743505d6a7683909d9f9f9f9f9f9b8e8275685b4f42352823262626262626242734414d5a6774808d9a9f9f9f9f9f9f9285796c5f5246392c1f130000000000030c17232e38424b545c666c737c83898e9297989a9c9c9d9d9c9b999796918c86817a706c635b51493f352c1f160c01000000000000000000000000000000000000000000000000000814212e3b4754616e7a869299a1a9aca49f948c7f73665c5564717e8a929fa3aaaaa39f928a7d7064555c6673808c949fa4aca9a19a92867b6e6155483b2e221508000714202d3a4753606d7a8693a0a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a295887b6f6255483c2f22150900020f1a26313c4653606c7884919da9b3acacada1968a7d7063574d42362a36424d5763707d8996a0acacacb2a89d9083766a6054453b30251a0e0200101d2a3743505d6a7683909da9acacaca99c8f8376695c5043362d3a46535f6976828f9ca9b2acacaca79a8d8174675a4e4134271b0e00000006121e2b37424e57636d73808c92989fa2aaa7a8a8a7a7a09d9590857c7d89969f9f9f9f9f94877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7acacaca5988b7e7265584b46535f6c7986929facacacaca194877b6e6154484b5764717e8a97a4acacaca99c8f8376695c504336291d10000000000b17222d38424d57606a6f7b828a8f92999a9c9d9f96897c706356493d3023160a00000000000000000000000000000916222f3c4955626f7c8898a2aeacacacacb4aa988b7f7265584c3f3025190d0100000000000000000000000000000006121f2b37434e58626d74808c92999fa3aba8a8a8a7a8a09e9691877e7d89969f9f9f9f9f94877a6e6154473b2e2114080000000007121c27303c464f59606b707c838c92979da0a7a7a8a9aaa9a8a7a9a19e98928d847c716c625a50473d31271d120700000000000e1b2734414e5a6774818d9a9f9f9f9f9e918479818c92999fa3aaa7a8a8a7a8a09e9590857c6f695e53493f33271b0f03000000121e2b3845515e6b7884919eabacacacacacacacacacacacb4aeacabaaa9a7a8a09e99928e857d706c61584e43392e23180c00000000121e2b3845515e6b7884919eabacacaca99c8f8376695c5043362c3945525f6c7885929fabacacaca79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabacacaca99c8f8376695c504345515d6774818d9aa6b0acacb2a89d9083776b6054463c32261b0f030006121f2b3844505b6675828f9ca8acacacab9f9285796c605346392d20130e1824313e4b5764717e8a97a9b3acacafa4998a7d7063574a3d2f23180c0000121e2b3845515e6b7884919eabacacacacacacacacacacacacacacacacacacacacab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9acacaca89b8e8275685b4f42352f30323232323232302f34414d5a6774808d9aa7acacacac9f9285796c5f5246392c1f1300000000000a151e28343f4a545c666d787f8790949b9fa2a9a7a8a9aaa9a9a8a6a8a09e99928e857e726d635b51473e31281e1308000000000000000000000000000000000000000000000000000d1a2633404d596673808c98a2abb3b6afa69f9285796d605d677683909da5aeb4b4aea49d908376675d606d7985929fa6afb6b3aca3998d8074675a4e4134271b0e000714202d3a4753606d7a8693a0adafafafafafafafafafafafafafafafafafafafafafafafafafafaea295887b6f6255483c2f221509000009151f2b3744505b65727e8b97a2adbabdb2a89c8f8275695f5346392e3a46525e6975828f9ba8b2bdb9ada1968a7e7164584e4333291f14090000101d2a3743505d6a7683909da9b6b9b6a99c8f8376695c50433634404b54616e7b87939facb9b9b9b4a79a8d8174675a4e4134271b0e0000000814212e3a47535f6a727f8c929fa2aaaeb4b4b5b5b4b1aca79f9792857e8b98a5acacaca194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b46535f6c7986929facb9b9aea194877b6e6154484b5764717e8a97a4b1b9b6a99c8f8376695c504336291d10000000030f1c28333f4a545f696f7c858f949c9fa3aba9aaa396897c706356493d3023160a00000000000000000000000000000c1825323f4b5865727e8b98aab4bfb9b9b9b4a89b8e817568564c41362a1d11050000000000000000000000000000000814212e3a47535f6a727f8c929fa3abaeb4b4b5b5b4b2aca8a0999287808c99a6acacaca194877a6e6154473b2e211408000000000c18232e39424e58606b707d8690959fa2a9acb1b3b5b6b6b6b5b4b2adaaa39f9691877e716d62594f43392f24180c02000000000e1b2734414e5a6774818d9aa7acacaa9e9184818e939fa3abaeb4b4b5b4b3b2aca7a09792867b6e655b5044372b1f1409000000121e2b3845515e6b7884919eabb7b9b9b9b9b9b9b9b9b9b9bfbab9b8b7b6b4b2acaba39f9792877e706a5f554b4034281c1106000000121e2b3845515e6b7884919eabb7b9b6a99c8f8376695c5043362c3945525f6c7885929fabb8b9b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7b9b6a99c8f8376695c503f4953606d7a85929facb8b9b9aca1968a7e7164594f44342a20150a0000030f1c28333f4a5466727f8c99aab4bfbaada297887b6f6255483c2f221b1b1c2934404b556774808d9aa7b3b9b9ac9f93867a6d6054473a2d2114070000121e2b3845515e6b7884919eabb7b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6b9b5a89b8e8275685b4f42383c3d3f3f3f3f3f3f3d3c38414d5a6774808d9aa7b3b9b8ac9f9285796c5f5246392c1f130000000006111c26303844505c666d78818c92999fa6abadb3b4b5b6b6b6b6b5b3b2acaba39f9792887f726d63594f433a2f24190d01000000000000000000000000000000000000000000000000101d2a3643505d697682909caab4bdc0baada297887c6f62606d7a86939facb9bfbfb9ac9f93867a6d60626f7c8997a2adbbc0beb4ab9d9184776a5e5144372b1e11000714202d3a4753606d7a8693a0a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a295887b6f6255483c2f2215090000030f1b27333f4953606d7985929fabb5c0b9ac9f93877b6e61544b40343f4a54616e7b86929facb9bfb4aa9e9184796d6053463d3220170d020000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043363845515c6673808d9aa4afbbc8c0b4a79a8d8174675a4e4134271b0e000005121e2a36424d57626e7b86929fa4aeb4babfbfbab8b4b2b1b1a9a2979285929fabb8b9ada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000006121f2b3844505b666e7b8592979fa6acafb5b5afa396897c706356493d3023160a0000000000000000000000000005111d2935414c566874818e9ba7b4c1d0c6c4b7aa9e918477685e5246392d201307000000000000000000000000000006121f2b37434e58626e7c87929fa4aeb4babfbebab8b3b1b0b2aba3999286929facb9b9ada194877a6e6154473b2e21140800000004101c2834404a545f6a707d879298a0a7adb3b8bcc0c1bfbebfc1c0bdb9b4aea8a099928b7f716b60554b4035291f1409000000000e1b2734414e5a6774818d9aa7b4b9ac9f92868e939da5afb5b0b2b5b7bbc0bdb9b1a9a1988f82776c6053463b31251a0e020000121e2b3845515e6b7884919eabb7c4c6ccc6c3c2babababababababcbec2c1bdb9b5afa9a19992877c6f675c5145382e23170b000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5044505b65727f8b98a2aebabeb3a99e9184786d6053463d3320180e040000000b17222d3c4956626f7c8998a2aebabeb3a9988b7e7165584b3e30242727272c3845515c677783909daab6c3b7aa9d908477685d5245392c2013070000121e2b3845515e6b7884919eabb7c4c6cdc8c4c3bbbbbbbbbbbbbbbbbbbbbbbbb8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4f4244484a4c4c4c4c4c4c4a4844414d5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000c17232e38424f59606d78818e939fa3abb0b8babec0c2c1c0c1c2c1c0bdb9b5afa9a19a938c7f726b61564c4135291e1308000000000000000000000000000000000000000000000000111e2a3744515d6a7783909daab7c3c9beb3a996897d7063616e7a8799a3afbbc7c7bbafa399877a6e6163707d8996a9b3bec9c5b8ab9e9285786b5f5245382c1f12000714202d3a4753606d7a869396969696969696969696969696969696969696969696969696969696969695887b6f6255483c2f2215090000000b17222d3845515d6773808d99a3afbbbbafa4998d8073665c51453844505c6673808c99a3afbbbaaea2988c7f72665c5044382c1f1205000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043363a4653606d7985929eacb6c0ccc0b4a79a8d8174675a4e4134271b0e00000714212d3a46535e6976828f98a3aebabfc2bcb4aeaca8a5a4a6a9a9a2979297a2adbabaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d100000000613202d394653606c78839097a1a9b0b9bbb9b8afa396897c706356493d3023160a000000000000000000000000000713202d3946525e687784919eaab7c4d1d2c5b9aca096877a6d6154473a2e21140600000000000000000000000000000814212e3a47535f6a76828f99a3aebabfc2bbb3adaba7a4a3a4a8aba3999299a3aebabaada194877a6e6154473b2e21140800000006121f2c3844515c666e7c869299a2aab1babebeb9b8b4b2b1b2b4b8babebfbab2aba39f92877d6f675d51453b30251a0e010000000e1b2734414e5a6774818d9aa7b4baaea39992999da5aba6a4a3a5a9abb0babfc3bbb3aa9f948a7d7164574d42362a1e12050000121e2b3845515e6b7884919eabb7c4c9c1bbb6b5adadadadadadaeafb1b5b9bbc0c0bbb3aba3999083796d60544a3f34281c10030000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504653606c7884919daab4bfb9ada1978b7f72665c5044382b1f1207000000000613202d3a4653606d7985929facb8c1b4a79b8e817468564c413534343434343a4753606d7986929facb9c0b4a79a8d817467564c4135291d11040000121e2b3845515e6b7884919eabb7c4cbc3bcb8b6aeaeaeaeaeaeaeaeaeaeaeaeaeab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4f474f545659595959595957554f474d5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000003101c28343f4a54606b73808d939ea5afb5bdc2c0bbb9b6b4b3b4b5b8babec5c0bbb3aca49f93887d70685d52453a2f24190d010000000000000000000000000000000000000000000000101c2936434f5c6976828f9ca9b3bdc0b9ada197887b6f62606d7986929facb9bfbfb9ac9f9286796d60626f7c8897a1adb9c0bdb4aa9d9083776a5d5144372a1e11000714202d3a4753606d79868989898989898989898989898989898989898989898989898989898989898989887c6f6255483c2f22150900000006111b2935404b55616e7b87929facb9c0b5ab9e9285796d6053463c4653606d7884919eabb5c0b8ac9f92867a6d61544a3f34281c1003000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504337424d5764717e8a97a1adbec7d2c0b4a79a8d8174675a4e4134271b0e00000815212e3b4854616e7b87939faab4bfc2b8b0aaa29f9b9898999c9fa6a29fa2a9b3bebaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000006131f2b38434e5865717e8b959fa9b3bbbab2adaba5ab96897c706356493d3023160a000000000000000000000000000714212e3a4754616d7a8796a0acb8c5d2d5c9bdb2a8968a7d7063574a3d2d22170b00000000000000000000000000000815222f3b4855626e7b88949fabb5bfc2b8b0a9a29f9a9796989b9fa3a39fa3abb4bfbaada194877a6e6154473b2e211408000004111d2935414c55606d78839098a2abb4bcc0bbb3adaba7a5a4a5a7abadb3babfbdb5afa3999184796d60574d42362a1d13070000000e1b2734414e5a6774818d9aa7b4bfb4aba39fa3a8a19e999797989c9fa6aeb4bcc5bcb0a69c8f8276695e53463a2d2114070000121e2b3845515e6b7884919eabb7c4c1b7afaaa8a0a0a0a0a0a0a1a2a4a8acafb6bec5bdb4aba0958b7e72665c5044382b1f12060000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504d5763707d8996a0acbcbfb4aa9e9285796d60544a3f34281c10030000000006121f2c3844515c6676838f9ca9b6c2b7aa9d918477685d5246414141414141414956636f7c8999a3aebbbdb2a8978a7e7164574b3e2f24190d010000121e2b3845515e6b7884919eabb7c4c3b9b1abaaa2a2a2a2a2a2a2a2a2a2a2a2a2a29f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4f4f5960636565656565656361594f4d5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000006121f2c3844505c66707d88939fa6afbbc0c0bbb5afaca9a7a7a7a9abadb3b9bdc4beb6afa49a92857a6d60554c4135291d110400000000000000000000000000000000000000000000000c1926333f4c5966727f8c97a2abb2b5afa69e9185786c605c6776828f9ca4aeb4b4aea49c8f8276665c606c7885919ea6afb5b2aba2988d8073675a4d4034271a0d000613202d394653606c777d7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c796d6053473a2d201407000000000d18242f3946525e6975828e9ba7b1bcb9ada1978a7e7164584e434d5764707d8a96a1adbdbbb0a69a8e8174685e5242382e23170c00000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433a47535f6976838f9ca9b3bed0cdc0b4a79a8d8174675a4e4134271b0e00030f1c28333f4a5466737f8c99a4afbcc4bab0a69f98928e8c8b8c8f949ea1a9adb3bcc5baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000815222e3b4754606a7784919da7b1bbb9b1a8a19e999599897c706356493d3023160a000000000000000000000000000a1724303d4a5763707d8a96a8b2bdc8d4d9cec0b3a6998d807366544a3f33281c0f0300000000000000000000000004111d2935414b556773808d9aa6b0bdc4bab0a69f97928d8a8a8b8e9299a1a8aeb4bdc6baada194877a6e6154473b2e21140800000613202c3945515d67727f8c95a0aab3bdbeb6afa9a19e9b9897999b9fa2a9aeb4bcc0b5aba0968d8074695e52463a2f24180d0100000e1b2734414e5a6774818d9aa7b4c0bdb4aeaca59e96918d8a8a8b8f949fa2aab4bfc2b9ac9f93877b6e6154483b2e2115080000121e2b3845515e6b7884919eabb7c4bbafa59e9b9494949494949495979b9fa4acb4bcc6bdb1a79e9184786d6053463a2d2013060000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50535f6975828f9ca8b2bdbaaea2988c8073675d5142382e23170b000000000004101c2834404a546673808c99abb5bfb9ac9f93867a6d61544e4e4e4e4e4e4e4e4e5965727f8c98abb5bfb9aca196877b6e6154483b2e211508000000121e2b3845515e6b7884919eabb7c4bcb1a79f9d9595959595959595959595959595959285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4f54606b70727272727272706b61554d5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000000713202d3a4653606d7884919aa4afb8c1beb6afaba39f9d9b9a9a9c9fa2a9acb2bac3c0b6aca1978d8073675d5145392c20130600000000000000000000000000000000000000000000000714212d3a4754606d7a859299a1a8aba39f948b7f72665b5563707d89929fa2aaaaa29f92897d7063545b66727f8c949fa4aba8a19992867b6e6154473b2e2114080005121f2b3744505b656c6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6d675d5145392c1f13060000000007121d2a36424d57636f7c89959fabb8beb3a99c8f83766a5f5347535f6976828f9ca8b2bdb7ab9f94887c6f62564c4130261c110600000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043404b55626e7b88949fabbbc5cfcdc0b4a79a8d8174675a4e4134271b0e0006121f2b3844505b667683909dabb5c0bdb2a89f949086817f7e7f82899297a1acb6c0ccbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000916232f3c4956626f7c8995a0acb9bcb1a7a096918c8886877d6f6356493c30231609000000000000000000000000030f1c28333f4a546673808c99a6b3bfced9dccfc2b6a99c8f8376665b5044382b1f12060000000000000000000000000613202c3945515d677783909daab6c2bdb2a89f949085807e7d7e81879196a1abb5c0cbbaada194877a6e6154473b2e21140800000714212d3a4754606d7a85929fa7b1bcc0b6aca49f97928e8c8b8c8e92979fa2aab4bcbdb2a89f92867b6e61554b4035291d110400000e1b2734414e5a6774818d9aa7b4c0c6bbb0a69e938e84807d7d7f828a9298a2aebac2bbafa49a8b7e7165584b3e3225180b0000121e2b3845515e6b7884919eabb7c4b6aa9e938f87878787878787898b8f939aa2aab4bfc3b9aca096897c706356493d2d22170b0000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c4b55616e7b87939facb9c0b5ab9f92867a6d61554b4030261c11060000000000000c18232e3d495663707c8999a3aebbbbafa49a8a7d70635a5a5a5a5a5a5a5a5a5a566875828e9ba8b5c1b7ab9e918478695e52463a2d201407000000121e2b3845515e6b7884919eabb7c4b8ab9f95908888888888888888888888888888888885786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b4d5763707d7f7f7f7f7f7f7d7063584e5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000006121f2b37434e5864717e8b96a0acb6c0beb6aca49f9992908e8d8e8f92979ea1a8b1b9c3beb3a99f92857a6d6054473a2d22170b00000000000000000000000000000000000000000000000713202c3945525d68707d8791969a9a99928d82786c605454606b73808c92989a9a98928b80736b605454606c78828d93999a999691877e70695e52463a2d20140700030f1b27333f49535b6063636363636363636363636363636363636363636363636363636363636363636363605d554b4035291d100400000000010e1a25303b4854606b7683909da9b2bdb7ab9f94887b6e62554b55616e7b87939facb9bdb2a89c8f82766a5f53443a301e150a0000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504345515c6773808d9aa6b0bbcdd6cdc0b4a79a8d8174675a4e4134271b0e000613202d394653606c7985929facb8c5b9aca09690827b75727173767d85929aa4afbbc8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d1000000d192633404c5966737f8c99a7b1bcb8aca09591847f7c7a796f6b6054483b2f22150900000000000000000000000006121f2b3844505b6676828f9ca9b5c2cfdcdfd2c5b8ac9f9285796c605346392d2013060000000000000000000000000714212d3a4754606d7a86939facb9c6b9aca19690827a74717071757c849199a3afbbc7baada194877a6e6154473b2e2114080005121e2a36424d5765727f8b97a2adb9c3bbafa49a938d85817f7e7f81858b9298a2aab4bfbbaea3998d8073675d5145392c20130600000e1b2734414e5a6774818d9aa7b4c0c4b7ab9f948e817973717072767d86929fa6b0bcc0b6ac9a8d8174675a4e4134271b070000121e2b3845515e6b7884919eabb7c2b5a89b8f817a7a7a7a7a7a7b7c7e82889298a2aebac4bdb2a89a8d807467544a3f33281c0f0300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c515d6773808d99a4afbbbbafa3998d8174685e5243392f1e140a000000000000000714202d3a4753606d7a86929facb9c0b6ac998d8073676767676767676767676767687884919eabb7c1b4a79b8e817468574d42362a1e1205000000121e2b3845515e6b7884919eabb7c3b6aa9d90837c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7c6e6255483b2f22150800101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b535e6977838c8c8c8c8c8c84786a5f545a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000814212e3a47535f6a7783909da8b2bec0b6aca49a938d868381808182858a9196a0a7b1bcc5baaea2988b7e7165544a3f33281c0f030000000000000000000000000000000000000000000004111d2935414c56606b707d848a8d8d8c8780786d665b504f59636e737f868b8d8d8b867f736e63594f505b666d7880878c8d8d8a847d706c61564d42362a1e110500000b17222d38414950535656565656565656565656565656565656565656565656565656565656565656565653514b43392f24180c00000000000009141f2c38434f5964717e8a96a1adb9bbb0a69a8d8074675d515c6773808d9aa4afbbb8aca0968a7d7063584e4332281e0c030000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50434753606d7985929eabb8c2cddacdc0b4a79a8d8174675a4e4134271b0e000815222f3b4855626e7b8898a2aebabfb4aa9e9184796e696565666b6f7c88939facb9c6baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d100004101c2934404b556976828f9ca9b5bfb4aa9d91837a726f6d676360594f44382c1f13070000000000000000000000000613202d394653606c7985929fabb8c5d2dedfd3c6baaea298887b6f6255483c2f2215080000000000000000000000000916222f3c4955626f7c8899a4afbbbfb4ab9e9184796d686463656a6f7c87929facb9c5baada194877a6e6154473b2e211408000714212d3a46535f697783909da9b3bebaafa59f9388807a7472717274797f869298a2aebabfb5ab9f92857a6d6053473a2d20140700000e1b2734414e5a6774818d9aa7b4c0bdb2a89c8f82786d676464656b707e8a949fabb7c3b6a99d9083766a5d50432e23180c0000121e2b3845515e6b7884919eabb7c1b5a89b8e82756d6d6d6d6d6e6f71757d86929fa8b2bdc3b6aa9d908377665b5044382b1f120600121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c53606d7985929fabb5c0b9ac9f92877b6e61564c4131271d0c020000000000000006131f2c3845515d677683909da9b6c2b6a99c8f8276747474747474747474747474747b8796a1acb9beb3a9988b7e7165584b3e30251a0e02000000121e2b3845515e6b7884919eabb7c2b6a99c8f83766f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e6a5f53473a2e21140800101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b54616e7b87959898989896887c6f62555a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000815222f3b4855626e7b8895a0acbac3bbafa49a9388807a7674747476797e849095a0aab4bfbeb4aa9c8f8275665b5044382b1f120600000000000000000000000000000000000000000000010d19242f3a444f59606b70797d80807f7b746d665c544a47525c636d727a7e80807e7a726d635c52474a545c666d747b7f81807d79706b615a50443b3025190e02000006111b262f383f4446494949494949494949494949494949494949494949494949494949494949494949494745403931271d1207000000000000030f1b27323d4653606d7984919eaab4bfb8ab9f9285796d6053606d7985929eacb6beb3a99d9184786c6053463c3120160c000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50434e5864717e8b97a2adb9c6d4dacdc0b4a79a8d8174675a4e4134271b0e000a1724303d4a5763707d8a96aab4bfbaaea3988b7e71675e565859606b75828e9ba8b5c1baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d100006131f2c3845515c677885919eabb8baaea2988a7d706862605d55544f473d32271b0f030000000000000000000000000915222f3c4855626f7b8898a2aebac6d3dfdfd6cabfb4aa988b7e7165584b3e2f24190d0100000000000000000000000a1724313d4a5764707d8a97abb5c0baaea3998b7e71675e5657585f6a75818e9ba8b4c1baada194877a6e6154473b2e211408000815222e3b4855616e7b8895a0acbbc5b6aa9e938b7e736d67656466676d727c86929fabb4bfbaaea2988a7d7164574a3e3124170800000e1b2734414e5a6774818d9aa7b4c0b8aca096887c6f665d555759616c7683909ca9b6c3b8ab9e9185786b544b4034281c100400121e2b3845515e6b7884919eabb7c1b5a89b8e827568616161616162646b717e8b96a0acb9c5b8ac9f9285786c605346392d20130600121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5965727e8b97a2adbdbbb0a69b8e8175695f53443a301f150b000000000000000004101d2935404b556673808d99abb5c0b8ac9f92868081818181818181818181818181818f9ba8b2bdb9ada197887b6e6255483b2f22150900000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696262626262626262626262626262625f584e43372b1f120600101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b5665727f8b98a7a5a5a8998c807366575a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000c1926333f4c5966727f8c99a7b1bcbfb4aa9f93887e746e68686767666d717a839098a3aebac5b8ac9f9285796c605346392d201306000000000000000000000000000000000000000000000008131e28323d474f5960676d717374726e69605c544a42404a525b62686d717474716d68625b524a40424a545c60696e727473716d67605950483e32291f1409000000000a141d262d3337393c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3a39352f271f150b01000000000000000a161f2c3844515c66737f8c98a3aebabaada2978b7e71655864717e8a97a1adbebaada2978b7f72655b5044372b1f1204000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5047535f6a7683909ca9b3becad6dacdc0b4a79a8d8174675a4e4134271b0e000b1824313e4b5764717e8a97a4b1bdb9ac9f92867a6d60554d4b4f5964707d8a97aab4bfbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000714202d3a4753606d7a86939facb9b8ac9f9285796d605653514b48443d352b21160a000000000000000000000000000b1825323e4b5865717e8b98aab3becad6d3d2d3d0c1b4a79b8e817468564c4135291d110400000000000000000000000c1825323f4b5865727e8b98a5b1beb9ac9f92867a6d60554c4a4e5864707d8a97aab4bfbaada194877a6e6154473b2e211408000b1825323e4b5865717e8b98a7b1bcbdb2a89b8e81756c605d5558555d606a727f8c99a3aebabfb4aa9a8e8174675b4e413024190d01000e1b2734414e5a6774818d9aa7b4c0b7aa9d9184776a5f544b4a505a65727e8b98a5b1beb8ac9f928579665c5145382c1f130600121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b545454545659606c7884919eaab7c4baaea298877b6e6154483b2e21150800121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c606b7783909da9b3beb7ab9f94887c6f62574d4232291e0d030000000000000000000c18242f3d4a5763707d8a99a4afbbbaaea298928d8d8d8d8d8d8d8d8d8d8d8d8d8d8f939eaabac4b8ab9e9285796c605346392d20130600000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5555555555555555555555555555534e463c31261a0f0200101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b5d6876838f9ca9b2b2aa9d908377695e5a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f130004101c2834404a546875828f9ba8b5c0baaea3988d80746c615e565a545c60686e7b86929facb9c5baaea298887b6e6255483b2f2215080000000000000000000000000000000000000000000000010c16202c353d474f555c6064676765615f57514a423938404951565e6165676765615e565149403839424a51575f6165676664605c554f473e362c20170d0200000000020b141b22272b2d303030303030303030303030303030303030303030303030303030303030303030302d2c29241d150d03000000000000000004101c2834404a54616d7a86929facb8beb3a99d9083776a606a7683909ca9b3beb5ab9f9285796d6053493f33271b0f03000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504b55626f7b88949fabbbc5cfdbdacdc0b4a79a8d8174675a4e4134271b0e000c1825323f4b5865727e8b98a5b1beb6aa9d908377675d51433e4854616e7b8798a3aebabaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000815222e3b4855616e7b889aa4afbbb6a99d908376665c504745403a38322b23190f0400000000000000000000000004111d2935414c556774818e9aa7b4c1d0cbc7c5c7cbc4b7aa9d918477685d5245392c20130700000000000000000000000c1926323f4c5965727f8c98a5b2bfb6aa9d908377675d51433d4754616e7b8798a3aebabaada194877a6e6154473b2e211408000e1b2834414e5b6774818e9aa7b4c1b9aca196887b6f625a514b4b4b5158606d7a86929facb9c3b7aa9d9084776a564c4135291d1105000e1b2734414e5a6774818d9aa7b4c0b4a79b8e817468584e423e4955626f7c8895a2afbbbaaea39886796d6053463a2d20130700121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f47474849505b6574818d9aa7b4c0bfb4aa95887c6f6255483c2f22150900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376696363707d8995a0acbbbcb1a79c8f82766a6054453b3120170c000000000000000000000714212d3a4754606d7a86939facb9bfb4aaa29f9a9a9a9a9a9a9a9a9a9a9a9a9a9a9b9ea5afbbc2b5a89b8f8275655b5044372b1f120500000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504848484848484848484848484847433c332a2015090000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685b616d7a86929facb9b8aca095877b6e615a6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f130006121f2c3844515c667884919eabb3b3b3ac9f92867a6d615a524c4d4a50565f6974818e9ba7b4c1bfb4aa978a7d7064574a3d3124170a000000000000000000000000000000000000000000000000040d1a232c353d434b5153575a5a5955534d444039302e373f444c5254585a5a5854524c443f372e303940444d5355595a5a5753514b433d352c241a0e05000000000000020a11171b1f2023232323232323232323232323232323232323232323232323232323232323232323201f1d18120b03000000000000000000000c18232e3946525e6874818e9aa6b0bbb8ab9f95887c6f626f7c88949fabbbbbafa3998d8073675d5141382d22170b00000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50515d6774808d9aa6b0bccdd7e1dacdc0b4a79a8d8174675a4e4134271b0e000c1926333f4c5966727f8c99a5b2bfb5a89b8e827568554b403a46525e697986929facb9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000916232f3c4956626f7c8995acb6c0b5a89c8f827569544a3f39352f2c2721191107000000000000000000000000000613202c3945515d677784919daab7c4c7c0bbb9bbc0c6b9ac9f93867a6d6054473a2d21140600000000000000000000000c1926333f4c5966727f8c99a5b2bfb5a89b8e827568554b403a46525e697986929facb9baada194877a6e6154473b2e21140800101d293643505c6976838f9ca9b6c2b7ab9e9184786a5f5345403e4045515d6776838f9ca9b6c2b8ac9f928579685d5246392d201307000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403a4754606d7a8793a0b5c0bfb4aa94877a6d6154473a2e21140700121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423a3b3f495365727f8b98a5b2bebcafa295897c6f6256493c2f23160900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f837670707075828f9ba7b1bcb8aca095897d7063584e43332a1f0e05000000000000000000000613202c3945525d687783909daab7c3bcb4aeaca7a7a7a7a7a7a7a7a7a7a7a7a7a7a8aaafb7c1bfb4aa988c7f726553493f33271b0f0300000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433c3c3c3c3c3c3c3c3c3c3c3b3a37312a21180e030000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685564717e8b99a3afbbbcb1a7988b7f7265566774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000713202d3a4653606d7986939fa6a6a6a6a69c8f8275685e524641413f444d5764717d8a97a4b0bdbeb1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000000008111a232b31394045474a4d4d4c4846423b342e27252d323a4146474b4d4d4b4746413a322d25272e343c4247484c4e4d4a47454039312b231a1108000000000000000000060b0f1213161616161616161616161616161616161616161616161616161616161616161616161413100c0701000000000000000000000007121c2a36414c56626f7c88949fabb7bcb1a79a8e81746874818d9aa6b0bcb9ac9f92877b6e61554b402f261b110600000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5053606d7985929fabb8c2cddee9dacdc0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79b8e8174685b4e4136424d576b7885929eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1623303d495663707c8996a3afbcb5a89b8f8275685c4f422e29241d1b160f0700000000000000000000000000000714212d3a4754606d7a86939facb9c4bdb5afacafb5bdbbafa49a897d7063564a3d2d22170b00000000000000000000000d192633404c5966737f8c99a6b2bfb4a79b8e8174685b4e4136424d576b7885929eabb8baada194877a6e6154473b2e21140800111e2b3844515e6b7784919eaab7c2b5a89b8f827568584e43352f35414b556673808d99a6b3c0baaea298877a6d6154473a2e211407000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f3a4653606d798699a3afbbbaada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352d3e4b5764717e8a97a4b1bdbcafa296897c6f6356493c3023160900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c3b7aa9d90837d7d7d7d7d87929facb9bdb2a89d9083776b6155463c3221180c030000000000000000000004111d2935414c566774808d9aa7b3c0c6bfbab8b4b4b4b4b4b4b4b4b4b4b4b4b4b4b5b6bbc1c6baaea298897c6f6256493c2d22170b0000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362f2f2f2f2f2f2f2f2f2f2f2e2b2620180f06000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275685c6775828f9babb5c0c2b6a99c8f8276685d6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000815212e3b4854616e7b87999a9a9a9a9a9a998c7f7366564c413630343b4855616e7b8894a1aebbbfb2a5998c7f7266594c3f3326190c00000000000000000000000000000000000000000000000000000811191f272f34383a3e40413f3b3a363128231c1b20293036393a3e41413e3a39363029201b1c232831373a3b3f41403e3a38342f271f1a1108000000000000000000000000030506090909090909090909090909090909090909090909090909090909090909090909090706040000000000000000000000000000000d1925303a47535f6a76828f9ca8b2bdb8ac9f92867a6d7a85929fabb8bcb1a79b8e8275695e5343392f1d140a0000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c4e5865717e8b97a2adbac6d3dfe7dacdc0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413045525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724303d4a5763707d8a96a3b0bdb5a89b8f8275685c4f42352918130f0a040000000000000000000000000000000a1723303d4a5663707d8999a4afbbbbb2aba39fa3abb5c0b6ac998c7f736653493f33271b0f03000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413045525e6b7885919eabb8baada194877a6e6154473b2e21140800121f2c3845525f6b7885929eabb8c1b4a79a8e8174675b4e41383a3a3f4c5865727f8b98a5b2bebfb4aa94877b6e6154483b2e211508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3844505c667986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4b8aca09590898989898a9299a3afbbb9ada1968b7e7164594f413a31281e150b00000000000000000000010d19242f3e4a5764717d8a97a8b2bdc8cac6bfbab8b4b4b4b4b4b4b4b4b4b4b4b6bac1c6ccc5b8ac9f9285796d6053463a2d2013060000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362922222222222222222222211f1a150e0600000000101d2a3743505d6a7683909da9b6c1b5a89b8e827568606d7985929facb8c5c5b9ac9f92867a6d606774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000815222f3b4855626e7c888d8d8d8d8d8d8d8d8b7e7164584b3e30252d3a4754606d7a8793a0adbabfb3a6998c807366594d4033261a0d000000000000000000000000000000000000000000000000000000070d151d23292c2d313434322e2d2a261f18120e171e252a2d2e323434322e2d2a251e170e12181f262b2d2e323433312d2c29231d150d08000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e2b37434e5863707d8a96a0acb9baaea2988b7f727e8b98a2aebab8ab9f95897c6f63574d4231281d0b020000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c535f6a7683909da9b3becad6e2e7dacdc0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c070100000000000000000000000000000000030f1b27333f495366737f8c99abb5beb2a9a1999299a3afbbb5a99c8f8276655b5044372b1f1205000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e3f444647474b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f343f4a5f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4bcb1a7a09d96969696979fa3abb5c0b7ab9e9184796d605b534b433a30271d1207000000000000000000000814212e3b4754616e7a8796a0acb8c5c6bcb4aeaca7a7a7a7a7a7a7a7a7a7a8aaafb7c1cbc2b6a99c8f8376665c5144382c1f12060000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d15151515151515151514120f09030000000000101d2a3743505d6a7683909da9b6c1b5a89b8e82756863707d8a98a2aebac6c7bbafa3998a7e71646774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000814212e3b4754616e7a808080808080808080807c6f6255483c2f222d3a4653606d798693a0acb9bfb3a6998c807366594d4033261a0d00000000000000000000000000000000000000000000000000000000030b12181c1f202427272622211e1a140c07050d13191e20212527272521201e19130d05070c151a1e212226272724201f1c18120b030000000000000000000000000105090b0b13131313131313131313131313131313131313131313131313131313131313090806030000000000000000000000000000000000020f1b26313c4653606c7884919ea9b3beb4aa9d91847783909daab3beb3a99d9083776b6054453b311f160c000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c55626f7c88959fabbcc5d0dbe0e4dacdc0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000005121f2b3744505b6575828f9ca8b5b9ada1979186929facb9b8ab9f9285796c605346392d201306000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4a50535353535864717e8b97a4b1bebbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f2e46535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235303d4a5763707d8a96a3b0bdbcafa295897c6f6256493c2f23160900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4c3b9b1acaaa3a3a3a3a3acafb5bdc3b6aa9d90837b736c655d554b43392e23180e040000000000000000000714202d3946525e687784919daab7c4bfb4aaa29f9a9a9a9a9a9a9a9a9a9a9b9ea5afbac6c0b5ab998c807366544a4034281c10040000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10090909090909090808060200000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275686674818e9aaab4bfc7c5c0b5ab9b8e8275676774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000714202d3a46525e696e737373737373737373736f6a5f53473a2e202d3a4653606d798693a0acb9bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000001070c101314171a1a191514120e0903000002080d111314181a1a181413110d0802000003090e121415191b1a171413100c0701000000000000000000000000060c11151718202020202020202020202020202020202020202020202020202020202020201615130f0a04000000000000000000000000000000000a151f2b3844505b66727f8b97a2adbab8aca0958c7f8c95a0acbcb9ada1978b7e7164594f4333291f0d04000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5d6774818d9aa7b1bccecfd0d3d8dacdc0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000613202d394653606c7985929eabb8b8ab9e918583909da9b6baada297887b6e6255483b2f221507000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4a545c606060606064717e8b97a4b1bebbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235303d4a5763707d8a96a3b0bdc0b6ac95887c6f6255483c2f22150900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4cbc3bcb8b7b0b0b0b0b0b9bbc0c7c4b8ab9f9590867f776d675d554b40342820160c02000000000000000005111e2a36414c566774818e9aa7b4c1baaea298928d8d8d8d8d8d8d8d8d8d8e939eaab6c2bbafa399897d7063564a3d2e23180c000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275686c7985929eabb8c0bbb9bbb8ac9f9285796d6774808d9aa7b3c0b8ac9f9285796c5f5246392c1f130005111e2a36424d575e6167676767676767676767625f584e43372b212d3a4754606d7a8793a0adbabfb2a5988c7f7265594c3f3226190c00000000000000000000000000000000000000000000000000000000000000000406070b0d0e0c08070502000000000000010507070b0e0e0b07070501000000000000020608080c0e0d0b07060400000000000000000000000000000911181d2124252d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d22221f1b150f07000000000000000000000000000000030f1c28333f4a54606d7a85929fabb5bcb1a79f9386939fa7b1bcb4aa9e9185796d6053463d3220170d00000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c606d7a85929fabb8c2c4c3c4c7cdd4cdc0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000815222f3b4855626e7b8897a2adb9b5a89c8f82808d9aa7b4beb3a9978b7e7164584b3e2f24180d010000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a505c666d6d6d6d6d6d717e8b97a4b1bebbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235313e4b5764717e8a97a4b1bdbbafa49a887b6e6155483b2e22150800121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336353945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4d1cec8c5c3bcbcbcbcbdc4c5c6cac8bcb1a79f98928c82796d675c51453e32281e13080000000000000000010d1925303e4b5864717e8b97a8b2bdb8ac9f928681818181818181818181818e9ba8b4c1b9ac9f92867a6d6053473a2d201407000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275686f7c8997a1adb9b5afacafb5aea2988a7d706774808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300020e1a25303b454d52545a5a5a5a5a5a5a5a5a5a55534e463c3126232f3b4855626e7b8895a1aebbbeb1a4988b7e7165584b3e3225180b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b22292e3132393939393939393939393939393939393939393939393939393939393939392f2e2b27201910070000000000000000000000000000000b17222d3845515d6773808d99a4afbbbbafa4999399a4afb9baaea3988c7f73665c5145382c1f130500000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695865727e8b98a2aebabcb7b6b7bcc2cbcdc0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000000000b1825313e4b5864717e8b97a9b3beb3a6998c807e8b97aab4bfb4a79a8e817467554b4035291d11040000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a53606d787a7a7a7a7a7a7f8b98a5b1bebbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423b3b3f4a5465727f8c98a5b2bfb9ac9f9386796d6053473a2d20140700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504342424245525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4cec6bfbab8b7b7b7b7b7b7b8babfc5c3b9b1aaa39f938f82796d605a50443a3024190d0100000000000000000815212e3b4854616e7b8796a1acb9b9ac9f92867a7474747474747474747d8996a3b0bcb6aa9d908377675d5145392c201306000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e82756873808d9aa9b3b2aba39fa3abb4aa9a8d81746574808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000009141f29333b4246474d4d4d4d4d4d4d4d4d4d4847433c3432322e343f4a5464707d8a97a3b0bdbeb3a996897d7063564a3d3023170a00000000000000000000000000000000000000000000000000000000000000000000000000000000000004090d0f0f13131313131313131311100e0b06000000000000000000000000000000000000000000000000000000000006111b242d343a3d3e464646464646464646464646464646464646464646464646464646464646463c3b37322b22190f04000000000000000000000000000006111c2935404b55616e7b87939facb9c0b5aba49fa4abb5c0b9ac9f92867a6d61544b4034281c100400000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f837669606a7783909daab4b9b0aba9abb0b9c2cdc0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000004101d2935404b556774818d9aa7b4beb3a9968a7d7c8898a2aebab7aa9d908477675d5145392c2013060000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8686868686868b919ba7b3bfbbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f47474849505c6675818e9ba8b4c1b7ab9e918478675d5145382c1f130600121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504e4e4e4e4e525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4c6bcb4aeacaaaaaaaaaaabacaeb4b8babebcb4aea69e948e81756c61564c4135291d120700000000000000000714212d3a46535e697884919eabb7bbafa399897c7067676767676767737f8c99a6b2bfb3a69a8d807367554b4035291d1104000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e82756a7784919eaab2a8a0999299a3afab9e9184786c74808d9aa7b3c0b8ac9f9285796c5f5246392c1f130000020d17202930363a3b404040404040404040403c3c3f3f3f3f3f3f4045505b6674808d9aa7b3c0b9ada197877b6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000002091015191b1c2020202020202020201e1d1a17110b040000000000000000000000000000000000000000000000000000010c18222d363f454a4b535353535353535353535353535353535353535353535353535353535353534947433c342b20150a0000000000000000000000000000000d18242f3a46535f6975828f9ba7b1bcbdb5afacafb5bdbbb0a69b8e8174685e5242392e23180c0000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f837669626f7c8995a0acbcb0a69f9c9fa6b0bcc7c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000613202c3945515d677783909daab7b9ada197877b7985929facb8b9ac9f92867a6d6053473a2d2014070000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b9393939393989ba3acb7c3bbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b54545455565a606d7985919eabb8bfb4aa9b8f827568554b4035291d100400121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5b5b5b5b5b5b5b5f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4bfb4aaa29f9d9d9d9d9d9e9fa2aaabaeb4bcbfbab0a69e938a7e71685d5246392f24180c000000000000000005121e2a36424d576875818e9ba8b4c0b5ab988c7f72655a5a5a5a576975828f9ca8b5bdb2a8978a7d7064574a3d2f24180d01000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e82756e7b8896a0acaca0969186929facada197897c6f74808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000050e171f252a2d2e34343434343434343d4348494c4c4c4c4c4c4b5158606c7884919eaab7c4b8ab9e918578695e52463a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000030c141b212528292d2d2d2d2d2d2d2d2d2a2a27221d160e050000000000000000000000000000000000000000000000000005111d29343f485056586060606060606060606060606060606060606060606060606060606060606055544e463c32271b0f03000000000000000000000000000007131d2a36424d5763707c8995a0acb8c4c0bbb9bbc0c7b7ab9f94887c6f62564c4130271d12070000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376696874818e9aa7b1b7ab9f9490949fabb7c4c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000714202d3a4753606d7a86929facb9b8ab9e9185787683909ca9b6bbafa399897c706356493d302316090000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a0a0a0a0a5a7acb5bec9bbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e827568616161616263656c727e8b97a1adb9baaea2988b7e7165584b3e2f24180c0000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696868686868686868686c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4baaea298929090909090919298999fa2aab1b9c1b8afa59e92857a6d61554b4035291d100400000000000000020e1a25313f4b5865727e8b98a9b3beb5a89b8e827568564c4e525e697885919eabb8b8aca096877a6d6154473a2e21140700000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8275727f8c99a8b2aa9e9184828f9bacb2a9998d807374808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000050d141a1e2021272727272727323d474f5456595959595959545c606a717e8b96a0acb9bcb1a79a8e817467574d42362a1e11050000000000000000000000000000000000000000000000000000000000000000000000000000020c151e262c3135363939393939393939393736332e2720170e040000000000000000000000000000000000000000000000000915212e3a45505a62656c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6260584e43372b1f13060000000000000000000000000000010e1a26313b4854606b7783909da9b3bec9c7c6c7c9bdb2a89c8f82766a5f53443a301e150b000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376696d7a86929facb8b3a99c9083909ca9b6c3c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000a1623303d495663707c8999a3afbbb5a89c8f827574808d9aa7b3c0b5ab998c7f7266594c3f31261a0e0200000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a5adadadb1b3b7bec7c8bbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c1b5a89b8e82756e6e6e6e6e6e7072777e86929fa9b3bbb2a89f92867a6d6154473a2e2114070000121e2b3845515e6b7884919eabb7c2b6a99c8f837675757575757575757575757885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4b8ac9f928683848484848485888d92989fa7b1b9c1b9ada2978c7f73675d5145382c1f130600000000000000000915222f3b4855626e7b8897a1adb9b7ab9e918478685e524854616e7b8797a1adb9b7aa9d918477685e5246392d20130700000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e82757683909da9b4aa9a8d807e8b9aa4afaa9d91847774808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000002090e1114141a1a1a1a1f2c38434f59606365656565656566666d727c85929fa8b2bdb8aba095897d7063564a3d30251a0e02000000000000000000000000000000000000000000000000000000000000000000000000000009141e2730373d414246464646464646464644433f39322920160b0000000000000000000000000000000000000000000000000b1724313d4a56626c7179797979797979797979797979797979797979797979797979797979797979766a6054473b2e22150800000000000000000000000000000009141f2c38444f5964717e8b97a1adb9c6d1d2d2c5b9aca0968a7d7064584e4332291e0c03000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f837669727f8b98a2aeb9ada1978b7e8b97a4b1bec0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000000000c1926333f4c5966727f8c99abb5c0b3a6998c8073717e8b97aab4bfb5a89c8f827569574d42362a1e120500000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a5b1b9b9bcbcbcbcbcbcbbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c2b5a89b8f827a7a7a7a7a7a7b7c7f838a9298a3aebab1a9a0968d8073685d5246392d2013070000121e2b3845515e6b7884919eabb7c4b8ab9e92858181818181818181818181818187929facb9c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f82777777777778797c808690959fa7b1bcbeb3a99e9285796d6053473a2d20140700000000000000000814212e3a47535f6a7885929eabb8b9aca196877a6e61544a5764717d8a97a9b3beb4a79a8e817467564c41362a1d110500000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e82757b87939facaea298897d7b87939facaca095887b74808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000000000020507080d0d0d15222f3b4854606b6f7272727272727375797f869297a2adbab8aea49d9083776b6054483c2f1f1409000000000000000000000000000000000000000000000000000000000000000000000000000004101b26303942494d4f535353535353535353514f4a443b32271d110600000000000000000000000000000000000000000000000b1825323e4b5865717e868686868686868686868686868686868686868686868686868686868686867c6f6255493c2f22160900000000000000000000000000000003101b27323d4653606d7985919eabb4bfcbd6cabeb4aa9e9184786c6053463c3120170c00000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f83766b7783909daab4b8ab9e92857a8793a0adbac0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000005121e2a36424d576875828f9ba8b5beb3a9978a7d706e7b8898a2aebab8ab9e928578695f53463a2d21140700000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a5afafafafafafafafafafaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4b6aa9e938f87878787878788898c90959fa3aab4aea8a0979184796d60564c4135291d11050000121e2b3845515e6b7884919eabb7c4b9ada197928e8e8e8e8e8e8e8e8e8e8e8e8e9299a3aebbc0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f83766a6a6a6a666c6f737a839095a0acb8c2b9ada1978a7d7064574a3d2f24180d010000000000000006121f2b37434e586875828f9ba8b5bdb2a8968a7d70635749536673808d99a6b3beb2a9978b7e7164584b3e3025190d0100000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e82757e8b9aa4afac9f9285797783909daab1a7988c7f74808d9aa7b3c0b8ac9f9285796c5f5246392c1f1300000000000000000000000101091623303c4956636f7d7f7f7f7f7f7f8082858b9298a2a9b3b7aea59d92897d7063594f44382c200d0200000000000000000000000000000000000000000000000000000000000000000000000000000915212c37424c545a5c6060606060606060605d5b554d44392e22170b00000000000000000000000000000000000000000000000714212d3a4754606d7a869293939393939393939393939393939393939393939393939393939393887c6f6255493c2f221609000000000000000000000000000000000b161f2c3845515c6773808c99a3aebac7d3c6baaea2988b7f72665b5044382b1f120500000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f83766f7c8995a0acbcb0a69a8d80798693a0adb9c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000714212d3a46535f697885919eabb8b9ada197877b6e6c7985929facb8b9ada197887b6e6155483b2e22150700000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b98a2a2a2a2a2a2a2a2a2a2a2a2a195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4bbafa59e9b9494949494949596989da0a7aeb4aaa29f9591857c6f675d51443a3024190d010000121e2b3845515e6b7884919eabb7c4beb3a9a19e9b9b9b9b9b9b9b9b9b9b9b9b9b9fa3abb5bfc0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695d5d545b6062686d7983919da7b1bcbeb3a99a8e817467554b4035291d100400000000000000020f1a26313f4c5865727f8b98aab3beb3a6998c80736653505b6576838f9ca9b6b9ada197887b6e6155483b2e2215080000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e8276828f9cacb6ac9b8f827573808c99a9b3a99c908376808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000000000000000000000d1a2633404d596673808c8c8c8c8c8c8c8e92979fa2aab3b0aba49d938d80746b6054473d33271c100000000000000000000000000000000000000000000000000000000000000000000000000000000d1925313d49545e65696c6c6c6c6c6c6c6c6c6a675f554a3f33271a0e02000000000000000000000000000000000000000000000713202c3945525d6875828f9c9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f95887c6f6255493c2f2216090000000000000000000000000000000004101c2834404b55616e7a86929facb9c5d2c5b8ab9f92857a6d60544a3f33281c0f0300000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f837674818e9ba7b1b7ab9f94887b798693a0adb9c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000815222e3b4855616e7b8897a1adb9b8ab9e91857869667683909ca9b6beb3a9978a7e7164574b3e2f23180c00000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e8b969696969696969696969696969695887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4c1b8afaaa8a1a1a1a1a1a1a1a3a5aaacb1baaea298928c837c6f6a5f554b4032281e1308000000121e2b3845515e6b7884919eabb7c4c5bbb3adaba8a8a8a8a8a8a8a8a8a8a8a8a8acaeb5bdc6c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c514a5053565e676f7c89959fabb8c4b7ab9e918478675d5145392c20130600000000000000000916222f3c4955626f7c8898a2aebab5a99c8f8276655b53606c7985929fabb8b8ab9e918578695f53463a2d2114070000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e827986929facafa49a8b7e716f7c8997a1adac9f93867a808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000000000000000000000d1a2633404d596673808c9898989898999b9fa2a9aeb4b0a69f9c928d81786d60594f44352b21160b0000000000000000000000000000000000000000000000000000000000000000000000000000020f1b2835414d5a6570757979797979797979797771675b4f43362a1d10040000000000000000000000000000000000000000000004111d2935414c5664717e8a98a2aeacacacacacacacacacacacacacacacacacacacacacacaca295887c6f6255493c2f22160900000000000000000000000000000000000c18232e3946525e6874818e9ba7b4c1cdc0b3a79a8d8074675d5142382d22170b0000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f83767a86929facb8b3a99c9083767a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000b1824313e4b5764717e8a97a9b3beb5a89c8f8275696774808d9aa7b3c0b3a79a8d807467554b4034291c1004000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a5865727e89898989898989898989898989898989887c6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4cac1bbb6b5adadadadadadaeafb2b6b8bcb8ac9f928680796f6a5f584e43392f20160c02000000121e2b3845515e6b7884919eabb7c4cdc5beb9b8b4b4b4b4b4b4b4b4b4b4b4b4b4b9bbbfc6cfc0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c503f44464c55606a7683909da9b6c3b9ac9f9386796d6053473a2d20140700000000000000000613202d394653606c7985929fabb8b8ab9f9285796c6055626e7b8897a2adbab5a89b8e827568574d42362a1e12050000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e817e8a99a3aeac9f93877b6e6c7885919eabafa4998b7e808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000000000000000000000d1a2633404d596673808c99a5a5a5a5a6a8abadb3bab2a89f94908981786d665c51473d33231a0f050000000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c69758286868686868686868683776a5d5144372a1e110400000000000000000000000000000000000000000000010d1924303a4753606d7a86929facb8b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9afa295887c6f6255493c2f221609000000000000000000000000000000000007121d2a36414c5663707d8996a3b0bcc8bbafa295887c6f62554c4134281c11060000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f83767f8c98a3aebaada2978b7e717a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000004101c2934404b556774808d9aa7b3bfb3a6998c80736664717e8a97aab3beb6aa9d908377675c5145382c1f1306000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a54616e7a7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c796d6053473a2d201407000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4cac2bbb7b5afafafafafafafb1b3b8b9beb6aa9d90837d746d665c53493f33271f140900000000121e2b3845515e6b7884919eabb7c4cdc4beb9b8b4b4b4b4b4b4b4b4b4b4b4b4b4b9bbbfc6cfc0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043383a434e5865727f8c98a5b2bfbbafa49a887c6f6255493c2f221609000000000000000006121f2b3844505b6676828f9ca9b5baada297887b6e625864717e8b97a9b3beb3a9988b7f7265584c3f31261a0e020000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c1b5a89b8e81818e9babb4aa9d908377696574818e9babb4ab9b8f82808d9aa7b3c0b8ac9f9285796c5f5246392c1f13000000000000000000000000000d1a2633404d596673808c99a6b2b2b2b3b5b8babeb8aca09690827d746d665c544b40352b211108000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f939393939393939084776a5d5144372a1e110400000000000000000000000000000000000000000000000813202c3945515d6775828e9baab3becac6c6c9c3bfbebbbbbbbbbbbbbbbbbbbbbbbbbbafa295887c6f6255493c2f22160900000000000000000000000000000000000613202c3945515d6774808d9aa7b3c0ccbfb2a6998c7f73665c5145382c1f160b0000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f837784919daab4b8ab9f9285796d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000006131f2c3845515c677683909da9b6beb3a9978a7d7064626e7b8898a2aebab9ac9f9286796d6053473a2d201407000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a525e686e6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6d675d5145382c1f1306000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4c2b8b0aaa9a2a2a2a2a2a2a2a4a7abadb3b8aca095908980786d655b50443b3025190e02000000121e2b3845515e6b7884919eabb7c4c4bbb3adaba7a7a7a7a7a7a7a7a7a7a7a7a7acaeb5bdc6c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336313d495663707c8996a3afbcc0b6ac968a7d7063574a3d3024170a0000000000000000030f1c28333f4a5466727f8c99aab4beb3a9978a7e7164546774808d9aa7b3baada297887c6f6255493c2f221609000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b5a89b8f8185929fabb3a9998c80736664717d8a99a3aeac9f9286818e9aa7b4c1b8ac9f9285796c5f5246392c1f13000000000000000000000000000d1a2633404d596673808c99a6b3b4b5b6b9babfc4b7aa9d91847d756e685f584e453b2f261b1106000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9c9f9f9f9f9f9d9084776a5d5144372a1e1104000000000000000000000000000000000000000000000004111d2935404b5564707d8a98a2aebac6d3c7beb7b3b1aeaeaeaeaeaeaeaeaeaeaeaeaeaea295887c6f6255493c2f22160900000000000000000000000000000000030f1c28333f4a54606d7a85929fabb8c5d1c4b8ab9e9185796d6053463d32271b0f0300000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f837d8995a0acbcb1a79a8d80746d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b46535f6c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000714202d3a4753606d7986929facb9b9ada197877b6e61606c7985929fabb8bbaea399897c6f6356493c30231609000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4c565e616363636363636363636363636363636363605d554b4035291d1004000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f35404b556c7986929facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4bbb0a69f9c95959595959596979a9ea1a9afb1a7a09d928d81776c60564d42362a1e1105000000121e2b3845515e6b7884919eabb7c4beb3a9a19e9b9b9b9b9b9b9b9b9b9b9b9b9b9fa3abb5bfc0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362e3b4854616e7b8794a1aebabdb1a4978a7e7164574b3e3124180b0000000000000000000b17222d3c4956636f7c8998a2aebab3a79a8d8074675c667683909da9b6b8ab9f9285796c605346392d201306000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3b8ab9e92859297a2adada197897c6f62606d7a86929facaea2989184919eaab7c4b8ac9f9285796c5f5246392c1f13000000000000000000000000000d1a2633404d596673808c99a6a7a7a8a9acaeb4b9b8aca0969189827a6e6a5f574d41382d22170b000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8acacacaa9d9084776a5d5144372a1e11040000000000000000000000000000000000000000000000010d18242f3a4753606d7985929fabb8c5c9beb5aca7a4a2a2a2a2a2a2a2a2a2a2a2a2a2a2a295887c6f6255493c2f2216090000000000000000000000000000000006121f2b3844505b66727f8b98a2aebac6d2c6b9ada1978b7e7164594f44382c1f140900000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f82818e9ba8b1b8ab9f95887c6f6d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a79a8e8174675b4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b404b556c7986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb6a99c8f8376695c504336291d10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000091623303c4956636f7c8999a3aebbb8ab9e928578695e5b6576838f9ca9b6bfb5ab988c7f7265594c3f30251a0e020000000000000d192633404c5966737f8c99a6b2bfb4a79a8e8174675b4e4134404b556b7885919eabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4c5254565656565656565656565656565656565653514b43392f24180c00000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3945515d677986939facb9baada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c4b7aa9f948f888888888888898a8d92979ea5afb1aca49d938c7f72695e52463a2d201509000000121e2b3845515e6b7884919eabb7c4b9ada197918e8e8e8e8e8e8e8e8e8e8e8e8e9299a3aebbc0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4754606d7a8793a0adbabeb1a5988b7e7265584b3f3225180c0000000000000000000613202d3a4653606d7985929facb8b6a99d90837666606d7986929facb8b5a89c8f8275665b5044382b1f1206000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3b9ada1979297a1a9b3ab9e9185786c605d6776828f9ca9b4aaa0969196a0acb9c5b8ac9f9285796c5f5246392c1f13000000000000000000000000000d1a2633404d596673808c999b9b9b9b9c9fa3aaadb2b2a8a09d948f857c6e695e53493f33271b0f030000000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5b9b7aa9d9084776a5d5144372a1e110400000000000000000000000000000000000000000000000007131f2c3845515c6774818e9ba9b3bec3b7aca39b9895959595959595959595959595959595887c6f6255493c2f221609000000000000000000000000000000000613202d394653606c7884919eaab3becad5c9beb3a99d9083776b6054483b31261a0e01000000000000000000000000101d2a3743505d6a7683909da9b6c3b7aa9d908386929facb9b4aa9d9083766a6d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000d192633404c5966737f8c99a6b2bfb4a89b8e8175685b4e4236424d576b7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b45515d677986929facb9baaea194877b6e6154484b5764717e8a97a4b1bdb5a99c8f8276695c4f4336291c10000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000000000c1926323f4c5965727f8c98abb5bfb5a89c8f82756957536773808d9aa6b3c0b5a89b8e827568574d42362a1e12050000000000000d192633404c5966737f8c99a6b2bfb4a89b8e817568544a3f3845515c677885929fabb8baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41464749494949494949494949494949494949494745403931271d120700000e1b2734414e5a6774818d9aa7b4bfb2a5988c7f7265594c3f3a4753606d7a8699a4afbbbaada194877a6e6154473b2e21140800121e2b3845515e6b7884919eabb7c2b5a99c8f827c7c7c7c7c7c7c7e80858e939ea6b0b8aea59f92867b6e6154473c31261a0e020000121e2b3845515e6b7884919eabb7c4b8ab9e91858181818181818181818181818187929facb9c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00000000000000000006131f2c3845515c6676838f9ca9b6b9ac9f9286796d626f7c8898a3aebab4aa998c7f7266544a3f33281c0f03000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3beb3a9a19ea1a9b3b4ab9b8e8174655b5565727f8c98a8b2b2a8a09ea0a8b2bdc5b8ac9f9285796c5f5246392c1f13000000000000000000000000000d1a2633404d596673808c8e8e8e8e8e9092989ea1a8b0b2aca69e9791857b6e655b5044372b1f14090000000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e110400000000000000000000000000000000000000000000000004101c2934404b5563707d8a97a1adb9bfb3a79b908b88888888888888888888888888888888887c6f6255493c2f22160900000000000000000000000000000006121f2b37434e5864707d8a96a0acbcc5d0dacfc4b8aca095897c6f63574d42362a1d1307000000000000000000000000101d2a3743505d6a7683909da9b6c3b8aca095909299a3aebaaea2988b7e71656d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000c1926323f4c5965727f8c98a5b2bfb6a99c8f837669584e433946535f697985929facb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4bfb2a5998c7f7266554c4753606d7a8699a3aebbbbaea295887b6f6255484b5565727e8b98a5b1beb5a89b8e8275685b4f4235281c0f000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000005111e2a36424d576875828e9ba8b5bfb3a6998c807366595764717e8a97a9b3beb8ab9e918478695e52463a2d2014070000000000000c1926323f4c5965727f8c98a5b2bfb6a99c8f8376665b50443a4753606d7a86939facb9baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41393b3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3a38352f271f150b0100000e1b2734414e5a6774818d9aa7b4c0b3a69a8d807367564c413b4855616e7b8894abb5c0bbafa499877a6d6054473a2d21140700121e2b3845515e6b7884919eabb7c1b5a89b8e82756f6f6f6f6f6f717479818e949fabb7baaea2988c807366574e42372b1e12060000121e2b3845515e6b7884919eabb7c2b6a99c8f837674747474747474747474747885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00000000000000000004101c2834404b546673808c99abb5baaea398897c6f65727e8b98aab4baaea398897c6f6356493c2d22170b00000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3c5bbb3adabadb3baaea3998a7d71645355616e7b8896a0acb8b2acaaacb2bac4c5b8ac9f9285796c5f5246392c1f13000000000000000000000000010a1724313d4a5764707e81818181818283868b91969fa6b0b8b0a9a1978f82776c6053463b31261a0e0200000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e1104000000000000000000000000000000000000000000000000000c18232f3a4653606d7985929eabb8beb1a4988b7e7c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7c796d6053473a2d2014070000000000000000000000000000000b15212e3b47535f6a76828f9ca8b2bdcecfcecfc8bcb1a79b8f8275695f53463a2f24180d000000000000000000000000101d2a3743505d6a7683909da9b6c3bcb1a7a09d9fa3abb4b8ab9f9285796d606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000b1825323e4b5865717e8b98a4b1beb8ab9e9285786a605447464b55616e7b8898a3aebabaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0b4a79b8e8174675d545359626f7c8995abb5bfbdb1a4978a7e71645b53535c6774818d9aa7b4c0b4a79a8e8174675b4e4134281b0e000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000714202d3a46525e697884919eabb8beb3a9978a7d70645755616e7b8897a2adbab9ada196877b6e6154483b2e2115070000000000000b1825323e4b5865717e8b98a4b1beb8ab9f9285796c605347464c56626f7c899aa4afbbbaada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342e30303030303030303030303030303030302d2c29241d150d030000000e1b2734414e5a6774818d9aa7b4c0b6a99c8f8376685e5247464d5764717d8a97a4b0bdb9ac9f9386796c605346392d20130600121e2b3845515e6b7884919eabb7c1b5a89b8e827568626262626364676d7882909cabb5bfb4aa9e9184786a5f53473a2e2114080000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696868686868686868686c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c000000000000000000000c18232e3d4a5663707d8999a3afbbb4aa988b7e726774818e9aa7b4b9ac9f9286796d6053473a2d20140600000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3cdc5beb9b8b9beb9ac9f92867a6d6054535f697784919daab7bdb9b7b9bdc4ccc5b8ac9f9285796c5f5246392c1f130000000000000002060a0c0c0e0e1623303c4955616c7074747474747576797e8490949fa8b2bbb3a99f948a7d7064574d42362a1e120500000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e11040000000000000000000000000000000000000000000000000007121f2c3844505c6674818d9aa8b2bdb4a79a8d81746f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6d675c5145382c1f1306000000000000000000000000000007121d2a36414c56626f7c88949fabbac4c6c3c1c3c6c3b9ac9f93877b6e61554b4135291c11060000000000000000000000101d2a3743505d6a7683909da9b6c3c3b9b1acaaacaeb4bdb1a79a8d817467606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000b1724313e4a5764717d8a97acb6c0b9ada197897c6f625b5353555d67727f8b98aab4bfbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0b8ab9f92857a6d666060616b74818d9aa7b4c0c2b5a99c8f82766d626060656d7985919eabb8c0b3a69a8d8073675a4d4034271a0d000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000814212e3b4754616e7b8796a1adb9b9ada197877b6e615453606c7985929fabb8bdb2a8978a7d7164574a3e2e23180c0000000000000b1724313e4a5764717d8a97acb6c0baada297897d70635c5353555d6873808c99acb6c0baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272323232323232323232323232323232323201f1d18120b03000000000e1b2734414e5a6774818d9aa7b4c0b9ac9f92867a6d615a5353565f6975818e9ba8b4c1b8ab9f928578655b5044372b1f120500121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b55555556555d66707d8a99a3afbbb9ada196887b6e6255483b2f2215080000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5b5b5b5b5b5b5b5f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c000000000000000000000714202d3a4753606d7a86929facb9b4a79b8e8174677784909daab7b6a99c908376675c5145382c1f130600000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0cfc9c6c5c6c2b5a99c8f8276675d514d576773808d9aaab3bec5c4c5c9ced2c5b8ac9f9285796c5f5246392c1f13000000000000070d121618191a1a1a202d3944505a6164686868686868676d717a829096a1adb9bbb0a69d908376695f53463a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e11040000000000000000000000000000000000000000000000000003101c28343f4a5463707c8996a1adb9b8ab9e9285796d626262626262626262626262626262605c554b4034291c100400000000000000000000000000000c18232e3946525e6874818e9ba6b0bbc1bab6b5b6bac1bbafa4998d8073675d5145382d22170b0000000000000000000000101d2a3743505d6a7683909da9b6c3cbc3bcb8b7b9babfb8aca095887c6f62606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00091623303c4956636f7c899aa4afbbbeb3a99b8e81756d63606061676d7984919eabb7c4baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0baada2978e8178706d6c6e737d87929facb9c5c3b7aa9e948b7f756f6d6d6f77808d97a1adb9c0b5ab988b7e7265584b3f3225180c000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000000000b1724313e4a5764717d8a97a8b2bdb8ab9e928578695e52505b6576838f9ca9b6c0b3a69a8d807367544a4034281c10040000000000091623303c4956636f7c899aa4afbbbeb3a99c9082766e63606061676d7a85929eabb8c5baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b16161b1f22232727272727272727272721201d19130c04000000000e1b2734414e5a6774818d9aa7b4c0bbaea3998d80736c62606061686e7b86929facb9c4b7aa9e9184776b5e493f33271b0f0300121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4949494b54606d7a86929facb9bdb2a8978b7e7164584b3e3125180b0000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504e4e4e4e4e525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c000000000000000000000613202c3945515d677683909da9b6b7aa9d9184776d7a86929facb9b5ab998d807366554b4034291c100400000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dad5d2d1c8bdb2a8988b7f7265554b495663707d8998a2aebac6d1d2d5d9d2c5b8ac9f9285796c5f5246392c1f1300000000010a12181e2225262727272728333e485055575b5b5b5b5b555d60686d7a84919eabb5c0b8ab9f95887b6e6155483b2e22150800000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e110400000000000000000000000000000000000000000000000000000c17232e394653606c7884919eabb8b9ada197897d7063555555555555555555555555555553514b43392f23180c000000000000000000000000000004101c2834404b54616d7a86929facb9c1b7afaaa8aaafb7c0b5ab9f92857a6d60544a3f33281c0f0300000000000000000000101d2a3743505d6a7683909da9b6c3d0cec8c5c3c5c7bfb4aa9d9083776a60606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000714212d3a4754606d7a86939facb9c5b6aa9e938b7f756f6d6c6e7179828f96a1acb9c5baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0beb3a99e938e837d7a797b80879299a3afbbc6bfbbb0a69b918b817c79797c828d929da9b3bebbafa499897c6f6256493c2f231609000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000004101c2834404a546773808d9aa6b3c0b5a99c8f827669574d49536773808d9aa6b3c0b6a99c908376665c5144382c1f120600000000000714212d3a4754606d7a86939facb9c5b7ab9f948d8076706d6c6e7179828f97a1adb9c6baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b1920272b2e2f343434343434343434342e2d29251e160e040000000e1b2734414e5a6774818d9aa7b4c0bfb5ab9f93877e746f6d6d6e727a839098a3aebac1b5a89b8e8275685b4f422d22170b0000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423c3c45515d677784919daab7bfb3a6998c807366594d4033261a0d0000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504341414145525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c0000000000000000000004101d2935404b556773808d9aacb6b9ac9f93867a6f7c8999a3afbbafa4998a7d7063574a3d2f23180c0000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dce2ded1c5b8aca096887b6e6155484653606d7985929fabb8c5d2dde1dfd2c5b8ac9f9285796c5f5246392c1f13000000000a131c232a2f3233343434343434363e44494a4e4e4e4e4e4b51565e68727f8b99a3afbbbcb1a7988b7f7265584c3f3225190c00000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e1104000000000000000000000000000000000000000000000000000006121f2b3844505b6674808d9aa8b2bdb3a99b8e8174675c514848484848484848484848484745403931271d1207000000000000000000000000000006131f2c3845515c66737f8c98a3aebabbafa59e9b9ea5afbbbaaea2988b7f72665b5044382b1f150a00000000000000000000101d2a3743505d6a7683909da9b6c3d0d9d4d1d0d2c6baaea2988b7e726558606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000613202c3945515d677784919daab7c3baafa59b918b817c7a797a7e848f949ea8b2bdc9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0c5bcafa59e9490898686888d9299a3abb5c0bdb5aeaca9a39b938e888686898f949da4aebbc4b9ac9f9386796d6053473a2d201407000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000006121f2c3844515c667683909ca9b6bfb3a6998c807366594d4a5764717e8a97a9b3beb8ac9f9286796d6053463a2d20130700000000000613202c3945525d687784919eaab7c4bbb0a69c928d827d7a797a7e848f949fa9b3bec9baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342719222b32383b3c414141414141414141413a3935302820160c0200000e1b2734414e5a6774818d9aa7b4c0c6bbafa4999388817c7a797b7f859095a0aab4bfbdb2a8998c7f7266594c3f332619060000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423535404b556a7683909da9b6c1b4a79b8e8174685b4e4135281b0e0200121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336353945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00000000000000000000010d18242f3d4a5763707d8a9aa4afbbafa49a897d727f8c98abb5b9ac9f93867a6d6054473a2d2114070000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dce9ddd0c4b7aa9d918477695f534644515c6675828e9babb5c0ccd7e3dfd2c5b8ac9f9285796c5f5246392c1f1300000007121c252e353a3e3f4141414141414141413e3d414141414140454c56606d7a86929facb9c1b4a79b8e8174685b4e4135281b0e02000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e11040000000000000000000000000000000000000000000000000000030f1c28333f4a54626f7c8996a0acb9b8ab9f9285796d6053463c3c3c3c3c3c3c3c3c3c3c3a38342f271f150b0100000000000000000000000000000713202d3a4653606d7985919eaab4beb3a99e938e939ea9b2beb3aa9e9184786c6053463c31261b0f02000000000000000000101d2a3743505d6a7683909da9b6c3d0dce0deddd2c5b8ac9f92867a6d6054606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e0004111d2935414c556874818e9ba8b2bdc1b7aca39b938e898686878b91969ea6b0bac1cabaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4c0bbb3adaba69f9c96999399999fa3abb5bdbfb5aba39f9c9fa59e9b999399969c9ea6aeb6c0bdb2a89c8f8276675d5145392c201306000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000713202d3a4653606d7986929facb8beb3a9978a7d7064574a4855616e7b8897a2adbabaaea398897c6f6256493c2f231608000000000004111d2935414c566874818e9ba8b2bdc2b8aea49c948f898686878a91969fa6b0bbc5d0baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427202b343d4347494d4d4d4d4d4d4d4d4d4d4746413a32281e130800000e1b2734414e5a6774818d9aa7b4c0ccc0b5aba49a938e898686878b9197a0a7b1bcc6b9aca196897c706356493d3023160a0000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352f43505c6976838f9ca9b6c1b5a89b8e8275685b4f4235281c0f0200121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798693a0acb9beb2a5988b7f7265584c3f3225190c00000000000000000000000714212d3a4754606d7a86939facb9b6ac998c7f75818e9ba8b4b7aa9d908477685d5245392c2013070000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dce2d6cabeb3a99a8d807367574d42404a5464717e8b99a4afbbc7d4e0dfd2c5b8ac9f9285796c5f5246392c1f130000020d18232e373f464b4c4d4d4d4d4d4d4d4d4d4a49453e36352f353a45515d677783909daab6c3b6a99d9083766a5d5043372a1d1004000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e11040000000000000000000000000000000000000000000000000000000b17222d384754606a7784919eaab7baada2978a7d7064554b40352f2f2f2f2f2f2f2f2f2d2c29231d150d0300000000000000000000000000000713202c38444f5964717e8b97a1adbcb9ada1978e828e97a1adb9b9aca0968a7d7064584e43372b1e1308000000000000000000101d2a3743505d6a7683909da9b6c3d0dce9e0d4c8bcb1a79b8e8174675d53606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00010d19242f3d495663707c8996a0acb8c1beb5aca59e9b96999399979ea0a8a8aab0b8c1baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb3a9a19e9fa2a9aba49fa4abacaeb5bdc1bbaea3999290949fa9aba49fa4aba9aab0b8c0c0b9ada1968a7e7164554b4035291d1104000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000916232f3c4956626f7c8998a3aebab9ada197877b6e61544846535f697885929fabb8bfb4aa988b7f7265584c3f3025190d0100000000010d19242f3d4a5663707d8996a0acb9c1c0b6aea69f9c96999399979da0a8acafb6bec7baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342727323d464e54565a5a5a5a5a5a5a5a5a5a54524c443a3025190d01000e1b2734414e5a6774818d9aa7b4c0c5bcb3aeaca49f9b95999399989ea1a9b1b9c3beb3a99e9184786c605346392d2013060000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42353643505c6976838f9ca9b6c2b5a89c8f8275695c4f4236291c0f0300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4753606d7a8693a0adb9beb1a5988b7e7265584b3f3225180c00000000000000000000000713202c3945525d687784909daab7b5a89b8f827784919eaab7b4a79a8d817467564c4135291d11040000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dcdfd3c6baada297897c706356493d3a4754616d7a86939facb9c6d2dfdfd2c5b8ac9f9285796c5f5246392c1f13000006121e2a353f495157595a5a5a5a5a5a5a5a5a575550483e33282935404b556875818e9ba8b4c1b7ab9e9184786b5e5145382b1e1205000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e110400000000000000000000000000000000000000000000000000000006111c2b37434e586673808d99a7b1bcb3a99b8e8175675d5145392c2222222222222222201f1c18120b030000000000000000000000000000010c16222f3b4854606b7783909da9b3beb6ac9e92857a84919eabb5bdb2a89c8f82766a5f53473a3025190d000000000000000000101d2a3743505d6a7683909da9b6c3d0dce9ded1c5b8aca095897c6f625553606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000816222f3b4854606b7784919ea5afb9c2beb7afaaa8aba49fa4abaaa69e9c9ea6b0bbbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4b9ada197929297a2adafacafb5b9bbbfbeb9b0a69f9287839097a1a9afacafb5b5b7bbc2bdb9afa59e9184796d6053473a2f24180d01000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000c1925323f4c5865727f8b98aab4bfb8ab9e928578695e5346424d576976828f9ca9b6c1b4a89b8e817568564c41362a1e110500000000000813202d394653606c7884919ea6b0b9c2c0b8b0aba9aba49fa4abaaa29f9fa4acb6c0baada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272b38434e58606267676767676767676767615e564c4135291d1105000e1b2734414e5a6774818d9aa7b4c0beb3aaa29fa2aaa7aba49fa4ababadb3bbc3bfb9ada1978c7f73665b5044382b1f12060000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42353643505c6976838f9ca9b6c2b5a89c8f8275695c4f4236291c0f0300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362e3b4754616e7a8794a1adbabeb1a4978b7e7164584b3e3125180b000000000000000000000004111d2935414c566774818d9aa7b4b8ab9e91847a8796a0acb9b2a8978a7e7164574b3e2f24190d010000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dcded2c5b8ab9f9285796d6053463a3946525e687683909da9b6c3cfdadfd2c5b8ac9f9285796c5f5246392c1f1300000a16222f3a46515b636667676767676767676764615a5045392d242f414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1206000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e1104000000000000000000000000000000000000000000000000000000000f1b27323d4855626f7c8895a0acb8b8ac9f92867a6d6053473a3024191515151515151413100c070100000000000000000000000000000007131d2a36424d5763707c8995a0acbbbbafa49a8d8073808c99a4afbbb7ab9f94887c6f62564c41362a1d12070000000000000000101d2a3743505d6a7683909da9b6c3d0dce3d6cbbfb4aa9d9083776a605453606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000713202c38444f5964717e8a939ea7b0b9bdc1bab6b4b5afacafafa59d948f949eaab7baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b2b2ab9e928585929fa4abb1b7b9bab8b7b3ada69e948d807a859197a0a8aeb4b7b9b9b8b7b2ada59d938a7d70675d5145392c1d130700000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000005111e2a36414c566875818e9ba8b4c1b5a99c8f827669574d42404d5a6673808d99a6b3c0b7aa9e918477685e5246392d201407000000000005121f2b3744505b65717e8b949ea7b0b9bec2bbb7b5b5afacafaca29892939aa4afbbbaada194877a6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272e3b4754606a6f747474747474747474746d685e5246392d201307000e1b2734414e5a6774818d9aa7b4c0baaea2989298a0a7b0afacafb5b8b9bec2bcb8ada49e92857a6d61544a3f33281c0f030000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423534404b546a7683909da9b6c2b5a89c8f8275695c4f4236291c0f0300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362f3c4855626f7c8895a2aebbbdb0a4978a7e7164574a3e3124170b0000000000000000000000010d1924303e4a5764717e8a97a8b2b9ada1978b7e8b98a8b2b9aca196877b6e6154473b2e211408000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dcd7ccc0b5ab9b8e8275665c51443836414c5666737f8c99a8b2bdc9d5dfd2c5b8ac9f9285796c5f5246392c1f1300000c1825323e4b57636d72747474747474747474716c6155493d302734404d5a6773808d9aa6b3c0b9ac9f9286796c5f5346392c201306000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e1104000000000000000000000000000000000000000000000000000000000a16212e3a47535f6a7784909daab7baaea2988a7e7164564c4135291d1109090909090706040000000000000000000000000000000000010d18242f3a46535f6975828f9ba7b1bcb9ac9f93877b6e7b87939facb9bbb0a69b8e8174685e5246392e23180c0000000000000000101d2a3743505d6a7683909da9b6c3d0dce0d3c7baaea3988b7f7265584e53606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000004101b27323d4955616c75818e959fa6adb2b7b8b9b9b8b6b0aba39f938e828f9ca8b2b2ada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa6a6a6a69e91847e8a9399a0a7aaacaeacaaa9a19e948f82786f7c8591969fa2aaabacadabaaa8a19e938e81746c61554b4035291d0c0100000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000713202d3946525e687784919eaab7c0b3a6998d8073665a4d403e4a5764717d8a97a9b3beb9aca096877a6e6154473b2e2114060000000000030f1b27333f4953626c75828f959fa6adb3b7b8b9b9b8b6afaaa29a928588939facb9baada194877a6e6154473b2e21140800121f2c3845525f6b7885929eabb8c1b4a79b8e8174685b4e4130252f3c4956626f7c808080808080808080807a6d6154473a2e211407000e1b2734414e5a6774818d9aa7b4c0b8ab9f928590959fa6aeb4b8babebab8b7b1aba39c928a7e71685e5242382d22170b000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42333845515c667784919daab7c2b5a89b8f8275685c4f4235291c0f0200121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433639414d5765717e8b98a4b1bebeb3a995897c6f6256493c2f2316090000000000000000000000000814212e3b4754616e7a8796a0acb9b2a99d9083909daab6b7ab9e918478695e52463a2d201407000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dcd4c7bbafa4998b7e7164544a4034303c4955626f7c8896a1adb9c5d2dfd2c5b8ac9f9285796c5f5246392c1f1300000c1926333f4c5966727f8080808080808080807e7164574a3e2f2434404d5a6773808d9aa6b3c0b9ac9f9286796c5f5346392c201306000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e11040000000000000000000000000000000000000000000000000000000006121f2b37434e5866737f8c99a7b1bcb4aa9c8f8275685d5245392c20140800000000000000000000000000000000000000000000000004111d2935414b55616e7b87939facb9beb3a99c8f82766975828f9ca8b2bdb9ac9f92867a6d61544b4034281c100400000000000000101d2a3743505d6a7683909da9b6c3d0dcdfd2c5b8ac9f92867a6d60544753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e0000000b16212d3945505a616d7a838f949ea1a8aaabacacaba9a69e99928c817d8996a3a6a6a6a194877a6e6154473b2e211408000e1b2734414e5a6774818d9999999999999184777f8790959b9d9fa39f9d9b97918b82796d6a6f7c848d92989b9e9fa29e9d9b96918a81776c605a5043392f24180c0000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000714212e3a4754616d7a8796a0acb9beb3a9978a7d7064574a3d3b4855616e7b8897a1adb9bdb2a8978a7d7064574a3d2e23170b0000000000000b17222d3841505a616e7a8390949ea1a9aaabacacaba9a59e9892887e87929facb9baada194877a6e6154473b2e21140800111e2b3744515e6a7784919daab7c2b5a89c8f827569574d42362b2f3f4c5965727f8c8d8d8d8d8d8d8d8d877a6d6154473a2e211407000e1b2734414e5a6774818d9aa7b4bfb2a5988c7f8390949fa2aaabaeb3aeacaaa79f9d918c80746c61564c412f261c1106000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f433f444653606d7986929facb9c1b4a89b8e8175685b4e4235281b0f0200121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504341464b535e6975828e9ba8b5c1b9ada197877b6e6154473b2e2114080000000000000000000000000714202d3946525e687784919eaab7b8aba0959095a0abb8b4a79b8e817468574d42362a1e1105000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dcd2c6b9ac9f93867a6d6154473a2e2e3b47545f6a7884919eabb8c4d1dcd2c5b8ac9f9285796c5f5246392c1f130004111d2a3744505d6a77838d8d8d8d8d8d8d8d8d817568554b40352e343f4a546874818e9ba7b4c1b8ac9f9285796c5f5246392c1f1306000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e110400000000000000000000000000000000000000000000000000000000030f1b26313c4855616e7b88959fabb8b9ac9f92867a6d6054473b3025190e0200000000000000000000000000000000000000000000000613202c3945515d6774808d99a4afbbb9ada1978a7d7164707d8a96a1adb9baaea3988c7f73665c5145382c1f160a00000000000000101d2a3743505d6a7683909da9b6c3d0dcd4c8bdb2a89b8e8175685d524753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000004111d28333e46525d686d79828b91969a9d9e9f9f9f9d99948f877f787d8996999999999994877a6e6154473b2e211408000e1b2734414e5a6774818c8c8c8c8c8c8c8c8477727d838a8e91929892918e8a857e776d675f6a6e7980868b8f91929792918e8a847e746c655b50483e31271d12070000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f02000000000000000000000a1724313d4a5764707d8a97a8b2bdb9ada197877b6e6154483b3a46535f697885929eabb8c0b3a6998d807366544a3f34281c1003000000000006111b262f3e46525e686e7a828b91979a9d9e9f9f9e9c99938e867e7986929facb9baada194877a6e6154473b2e21140800101d2a3643505d697683909ca9b6c3b7aa9e918477695e52463b3839424d576773808d9a9a9a9a9a9a9a9386786d6053463a2d201307000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7a828c92989c9fa2aaa29f9d9a9590897f746e645a50443a301d140a00000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4f4a50535a63707d8999a3afbbc0b4a79a8d8174675a4e4134271b0e0100121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504f4c52555c656e7b86929facb9c5b8ab9e928578695e52463a2d20140700000000000000000000000005111e2a36414d566774818e9aa7b4bcb1a7a09da0a7b1bcb3a9988b7e7165584b3e30251a0e02000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0dcd0c3b6a99d908376685e5246392d2b37434e586774818e9aaab4bfcbd7d2c5b8ac9f9285796c5f5246392c1f130003101d2a3643505d697683909a9a9a9a9a9a9a908376675d51453c3b3b44505c6676828f9ca9b5c2b8ab9e9285786b5f5245382c1f1205000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e110400000000000000000000000000000000000000000000000000000000000a15212d3a46535f697783909dacb6baaea3998b7e7165564c41362a1e110500000000000000000000000000000000000000000000030f1c28333f4a54606d7a85929fabb5c0b5ab9e9185796d606c7884919eabb5bfb4aa9e9185796d6053463d32271b0f03000000000000101d2a3743505d6a7683909da9b6c3d0dcd1c5b8aca096897c7063564c4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000000000c17222935414c565d676d777e848a8d9091929392908d88827c73707d898c8c8c8c8c8c8c877a6e6154473b2e211408000a1724303d4a5763707d7f7f7f7f7f7f7f7f7f726b6f787d818486868584817e79716c655d585f676d737a7e828486868584817d79716c605b53493f362c1f150b010000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000003101c28343f4a546673808d99a6b3c0b8ab9e928578695e53463a36424d576976828f9ca9b5c2b6a99c8f8376665c5044382b1f12060000000000000a141d2a36414c565e686d787e858a8e90919292918f8c88817b717986929facb9baada194877a6e6154473b2e211408000e1b2835414e5b6874818e9ba7b4c1b9aca096877b6e61564d4644464b545f697683909da7a7a7a7a79e918478665c5144382c1f1206000e1b2734414e5a6774818d9aa7b4beb1a5988b7e72787f868c8f9298949892908d89837d736d645c52483e32291e0b0200000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685c5c5c545b60626c75828f9babb5c0bfb2a5998c7f7266594c3f3326190c0000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5c5c565e61676d77828f99a3aebbc0b6ac9c8f827669574d42362a1e1105000000000000000000000000020e1925303e4b5864717e8b97a8b2bdb9b1abaaabb1b9b9ada197887b6e6255483b2f22150900000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0d5c9bdb2a8998c7f7366564c41362a26323d4a5764707d8a98a3aebac7d3d2c5b8ac9f9285796c5f5246392c1f1300020f1b2835424e5b6875818e9ba7a7a7a7a79f9286796d60564d4848484c55606d7985929fabb8c4b7aa9e9184776b5e5144382b1e1105000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d5144372a1e0800000000000000000000000000000000000000000000000000000000000005121e2b37424d5765727f8c9aa4afbbb4ab9c8f8276685e5246392d2014090000000000000000000000000000000000000000000006121f2b3844505b66727f8b98a2aebdbbafa4998d8073665c66737f8c99a3afbbb9ada1978b7e7164594f44382c1f1409000000000000101d2a3743505d6a7683909da9b6c3d0d7cbbfb4ab9d9184776b6054444753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000060d1924303a444c555d656c71797d81838586868583807c766f6a6e7b7f7f7f7f7f7f7f7f7f796d6053473a2d201407000916232f3c4855616b707373737373737373726d62656c7074777979797775716d67605b534e555d60686d7275787979787774716d67615a504941382d231a0d03000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000006121f2b3844505c6676838f9ca9b6c2b5a99c8f827669574d423631404d5a6673808d99a6b3c0b8ac9f9285796d6053463a2d201307000000000000020b1925303b444c565d666d72797d818485868685837f7b756e697986929facb9baada194877a6e6154473b2e211408000c1825323f4b5865727e8b98a9b3bebdb2a8998c7f72685e56535053555c666e7b87939facb3b3b3a89c8f827569544a4034281c1004000e1b2734414e5a6774818d9aa7b4beb1a5988b7e726d727a7f83858787868584807d786f6b635b524a40362c20170d0000000000121e2b3845515e6b7884919eabb7c1b5a89b8e82756969696969666c6f747e8a939eaabdc7bcb1a7978a7d7064574a3d3124170a0000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376696969696a686e7179818e949fabb5bfbbafa49a8b7f7265584c3f30251a0e02000000000000000000000000000815222e3b4855616e7b8896a1adb9c3bcb8b6b8bcc3b8ab9e9285796c605346392d20130600000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0d2c5b9ada196887c6f6255493c3025202d3a4753606d7a86929facb9c5d2d2c5b8ac9f9285796c5f5246392c1f1300000d1a2633404d596673808c99abb5b3b3aea3988b7e71685e57555455565e67707d8a97a2adbac2b6a99c8f8376695c504336291d1003000000000000000000000000000000000000000000000000000000000000000000000000030f1c2936424f5c6975828f9ca8b5c2b7aa9d9084776a5d51443025190d010000000000000000000000000000000000000000000000000000000000020e1a26313c4854616e7b87939facb9b9ac9f92867a6e6154473b31251a0e020000000000000000000000000000000000000000000613202d394653606c7884919eaab3beb9ac9f93877b6e6154616e7b86929facb9beb3a99d9083776b6054483b31251a0e010000000000101d2a3743505d6a7683909da9b6c3d0d3c7baaea3998c7f7265594f444753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000000000008131e28323a434b535b60676d7074777879797876736f6a625f696e7373737373737373736d675d5145392c201306000714202c38444f596163666666666666666665625b5b6063686a666d666a6864605c555049434b51565e6165686b666d666a6864605d5550443f382f261b110800000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000713202d3a4653606d7985929facb8c0b3a6998d8073665a4d4031313d4a5764707d8a97a9b3bebaaea298887c6f6255483c2f2215080000000000000008141e29323b444c545c60676d7074777879797876736e6a616c7986929facb9baada194877a6e6154473b2e211408000916222f3c4955626f7c8897a1adb9c4b8ab9f92857a6e6862605b5f61676d78828f9aa4afbbbcb1a7998c7f7266594c3f2e23180c00000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265686d7276787a7a7a797773706c656059514940382f241a0e050000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8176767676767677797c8187929fa6b0bbc5b8aca095877b6e6154483b2e2115080000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f83767676767676787a7e848e939ea6b0bdc6b9ac9f93877b6e6155483b2e22150900000000000000000000000000000714212d3a46535f697884919eabb8c4c8c4c3c4c8c2b5a89b8f8275655b5044372b1f120500000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0d1c4b7ab9e9184786a5f53473b2e1e202c3945515d6776828f9ca9b5c2ced2c5b8ac9f9285796c5f5246392c1f1300000a1724313d4a5764707d8a99a3afbbbfb4aa9e91847a6e696462616263686d7984919da9b3bec0b5ab9a8d8074675a4d4134271a0e0100000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a546975828f9ca8b5c2b7aa9d9084776a564c41362a1d11050000000000000000000000000000000000000000000000000000000000000914202d3a46525e697683909cabb5bbafa3998b7f7265574d42362a1e1205000000000000000000000000000000000000000006121f2b37434e5864707d8a96a0acbcbdb2a89c8f8275695e535e6975828f9ba8b2bdb8aba095897c6f63574d42362a1d13070000000000101d2a3743505d6a7683909da9b6c3d0d2c5b9ac9f92867a6d6154473d4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e0000000000020c162028313a414950555c6063676a656c6c666a66625f58575e61666666666666666666605d554b4035291d10040004101c28333e474f555759595959595959595856515053575b545c605c545b5753514b443f3940454c5254585c545c605c545b5753514b433e332d261d140a0000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000916222f3c4955626f7c8898a2aebabeb3a9978a7d7164574a3e312e3b4854616e7b8797a1adb9bfb4aa988b7e7265584b3f3024190d01000000000000020d172029323a424a50555d6064676a656c6c656966625f586c7986929facb9baada194877a6e6154473b2e211408000713202d3a4653606d7985929eacb6c0baada29790837a736f6c66696e7279818e949eacb6c0b8aca095887c6f6255483c2f22150700000e1b2734414e5a6774818d9aa7b4beb1a5988b7e72655d616569686d6e6d676a6763605b534f4740372f261d1208000000000000121e2b3845515e6b7884919eabb7c4b8ab9e91858282828282838485888e9299a3afb8c1bfb4aa9d908377695e52463a2d2014070000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4b8ab9f928582828282828384878b91969ea5afb8c2bcb0a69c8f8276695f53463a2d211407000000000000000000000000000005121e2a36424d576875818e9ba8b4c1cfd1d0d1cabfb4aa988c7f726553493f33271b0f0300000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0cbbfb4aa9a8d817467584e43372b1f1d2935404b5565727f8b98a7b1bcc8d2c5b8ac9f9285796c5f5246392c1f1300000714212e3a4754616d7a86929facb9c4b9ada19690837b74706f6e6e70747a829096a0acbbc5bbafa3998a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844505c6675828f9ca8b5c2b7aa9d908477685e5246392d20150900000000000000000000000000000000000000000000000000000000000005121e2a36424d5765727f8b99a3afbbb5ab9d908376695e53463a2d21150900000000000000000000000000000000000000000b15212e3a47535f6a76828f9ca8b2bdb9ada1968a7d7064574d5663707d8996a0acb9bcb1a79b8f8275695e53463a2f24180d0000000000101d2a3743505d6a7683909da9b6c3d0c9bdb2a89b8e8275685e52463a4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000000000000040e161f282f383f444b5153575a535b60605b545a55534e4d535459595959595959595953514b43392f24180d0100000b16212c353e44484a4c4c4c4c4c4c4c4c4b4a4644464a4e4a5053504a4e4b46454039332f353a4146474b4f4a5053504a4e4a474540393127221b140b020000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0f020000000000000000000c1825323f4b5865727e8b98aab4bfb9ada297877b6e6154483b2e2d3a46535e697885929eabb8c1b4a79b8e817468564c4135291d110500000000000000050e17202830383f444b5153575b535b60605b535955535f6c7986929facb9baada194877a6e6154473b2e2114080006121f2b3844505c6674818d9aa4afbbbeb3a9a09590857f7b7978797b7e848e939da6b0bebcb1a79d9083776a5f53473a2e21150800000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265585459565d6061605d555a56535049413d352e251d140b00000000000000121e2b3845515e6b7884919eabb7c4b9ada197918f8f8f8f8f909092989a9fa3abb5c0c4baaea2988c7f7266574d42362a1e12050000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4baada297928f8f8f8f8f909196989ea0a8afb7c1beb4aa9f94897d7063574d42362a1e12050000000000000000000000000000020e1a26313f4b5865727e8b98a9b3becad6ddd3c6baaea298897c6f6256493c2d22170b0000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0c7baaea3988a7d7063574a3d32261b18242f3b4854616e7b8795a0acb8c5d2c5b8ac9f9285796c5f5246392c1f1300000713202d3946525e687683909ca9b2bebdb2a9a0959086817d7b7b7b7d808690949fa8b2bdc5b9ac9f92867a6d6154473a2e211407000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7985929eabb8c5b9ac9f92867a6d6154473c31261a0f000000000000000000000000000000000000000000000000000000000000020e1a25303b4754616d7a86929facb9b9ac9f93877b6e6154483c31261a0e0200000000000000000000000000000000000007121d2a36414c56626f7c88949fabbac0b5ab9e9184786d60534653606c7884919eabb4bfb9ac9f92877b6e61554b4035291c110600000000101d2a3743505d6a7683909da9b6c3d0c5b9aca096897d7063564c413a4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e00000000000000040d161d262d33394045474a4e49505353504a4d4847434246484c4c4c4c4c4c4c4c4c4745403931281d120700000005101a232c33383c3d40404040404040403f3d3a37393d413f4446443f423e3a38342e2724293035393a3f423f4446443f413e3a38352f271f17110a02000000000000000a1724313d4a5764707d8a97a3b0bdb5a89b8f8275685c4f4235291c0600000000000000000005111d2935414c566874818e9ba7b4c1b8ab9e928578695e53463a2d2a36424d576976828f9ca9b5c2b7aa9d918477685d5246392d2013070000000000000000050e161e262e34394045474a4e4950535350494c48535f6c7986929facb9baada194877a6e6154473b2e2114080003101c28343f4a54626e7b87939faab4bfbcb1a7a097928c88868586888b91969da5afb8c1b8aca0958b7e7164584e43372b1f120600000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b4c4c52545453514b4d4946443f382f2b231c130b0200000000000000121e2b3845515e6b7884919eabb7c4beb3a9a19e9c9c9c9c9c9c9d9fa2aaacafb5bdc3bab1a79f92867a6d6054473b30251a0e020000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4beb3a9a29f9c9c9c9c9c9d9ea1a8aaacb2bac1bfb6aca2988f82766b6054453b31261a0e020000000000000000000000000000000915222f3c4855626f7b8897a1adb9c6d2dfd2c5b8ac9f9285796d6053463a2d2013060000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3d0c5b8ac9f92867a6d6053473a2d201414212d3a46535e697784919daab7c4cfc5b8ac9f9285796c5f5246392c1f13000005111d2935414c5664717e8b97a1adb9c2bbb1a7a098928d8a8887888a8d92989fa6b0bac3bdb0a69c8f8276685d5246392d20130700000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c5563707d8a97a1adb9c6bbaea3998b7f7265584e43372b1c11060000000000000000000000000000000000000000000000000000000000000914202d3946525e6876828f9caab4bbafa49a8c7f7266574e42372b1e12060000000000000000000000000000000000000c18232e3946525e6874818e9ba6b0bbbbafa3998c7f73665c5044505b65727f8c99a3aebabbafa3998d8073675d5145382d22170b00000000101d2a3743505d6a7683909da9b6c3cbc0b5ab9e9184786c6053463a3a4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e0000000000000000040b141b22272f34383a3d413f444646443f403c3a37363a3b4040404040404040403a39352f281f160c010000000008111a21282c2f30333333333333333332312e2b2d302e34383a38342e312d2c28231d181e25292d2e322e34383a38342e312d2c29241d150d060000000000000000000a1724303d4a5763707d8a96a3b0bdb5a89b8f8275685c4f42352917110f0a040000000000000713202d3946525d687784919daab7c2b5a99c8f827669574d42362a2531404d596673808c99a6b3bfb9ac9f93867a6d6154473a2e211406000000000000000000040c141c23282f35393a3d413f444646443f4046535f6c7986929facb9baada194877a6e6154473b2e21140800000b17232e3847535f6a75818e98a2aebac1b9b1a9a29f999993929299989ea0a8afb7c1b8aea49d9183786d6053463c31261b0f0300000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f41454747474540403d3937332d261d19110a010000000000000000121e2b3845515e6b7884919eabb7c4c4bbb3adaba9a9a9a9a9a9aaabaeb4b9bbc0c1b9b1a89f958c7f72685d524539291f1409000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4c5bbb3adaba9a9a9a9a9a9abacb2b7b9bdc4bdb5aea49a92867b6e61594f4433291f1409000000000000000000000000000000000613202d394653606c7985929eabb8c5d1d8cfc2b6a99c8f8376665c5044382c1f12060000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3cfc2b5a89c8f8275675d5145392c1f13121e2a36424d576773808d9aa9b3becac5b8ac9f9285796c5f5246392c1f130000010d1925303a4753606d7984919ea6b0bbc3b9b1aaa39f9a97959495969a9fa2aab0b8c2bfb4ab9f948a7d7063564c4135291d11050000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d6775818e9ba9b3bec9bfb5ab9d9083776a5f5347382d22170b00000000000000000000000000000000000000000000000000000000000005111e2a36414c5665717e8b98a3aebab6ac9d9083776a5f53473a2e21150a000000000000000000000000000000000004101c2834404b54616d7a86929facb9c2b9ac9f92877b6e61544a3f4953616d7a86929facb9c0b5ab9f92857a6d60544a3f33281c0f03000000101d2a3743505d6a7683909da9b6c3c7bbafa3998c7f72655b5044373a4753606d7a8693a0adb9c0b4a79a8d8174675a4e4134271b0e000000000000000000020a11171d23292c2d302d3337393938332d2f2e2b2a2d2e3333333333333333332d2c29241d160d040000000000000810161c20232426262626262626262524221f202423282c2d2c282324201f1c18120c13191d20212523282b2d2b282324201f1d18120b03000000000000000000000a1623303d495663707c8996a3afbcb5a89b8f8275685c4f422d28231c1b160f0700000000000714212e3a4754616d7a86939facb9c0b3a6998d8073665a4d40312524313d4a5764707d8a97a9b3bebbafa49a8a7d7063574a3d2d22170b00000000000000000000020a11171d24292c2d312d3337393937332d46535f6c7986929facb9baada194877a6e6154473b2e211408000006111c2b37434e58616e7b86929fa5afb8c1bbb3adababa49f9e9fa3abaaacb2bac1b9b0a69d92897d70665c5044382a20150a0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f35393a3b3a39352f302d2b27221b140b0700000000000000000000121e2b3845515e6b7884919eabb7c4cdc4beb9b8b5b5b5b5b5b6b7b8babec5c2bbb7afa7a0969083786d60564c413529170d02000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7c4cdc5bebab8b5b5b5b5b5b6b7b9bdc4c5beb9b2aba39f93887e71695f53473d3321170d030000000000000000000000000000000005121f2b3744505b6575828f9ba8b5c2d0cbcbc0b5ab998c807366544a3f34281c10030000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6c3c8bcb1a7988b7e7265554b4035291d100e1a25313c4956636f7c8997a2adbac6c5b8ac9f9285796c5f5246392c1f1300000008131f2c3845515c67717e8b949fa9b3bbc3bcb4aeaca7a3a2a1a1a3a7acaeb4bcc2c0baaea3999083766b6155443a3024190d010000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a86929facb8c5cfc6b8ab9f95887b6e62544a3f33281c0f030000000000000000000000000000000000000000000000000000000000010d1925303a4754606d7a86929facb9b8aca095887b6e6255483c32261b0f000000000000000000000000000000000006131f2c3845515c66737f8c98a3aebabdb2a89b8f8275695e52423846525e6875818e9ba8b2bdbaada2978b7f72665b5044382b1f150a000000101d2a3743505d6a7683909da9b6bfbfb9ac9f92867b6e6153493f333a4753606d7a8693a0adb9bdb4a79a8d8174675a4e4134271b0e0000000000000000000000060b12181c1f202422272b2d2d2b282222211f1e212126262626262626262620201d18120c040000000000000000050b101416171919191919191919181815121317171c1f201f1c17181313100c0702080d11131418171c1f201f1c17171413100c070100000000000000000000000916232f3c4956626f7c8995a2afbcb5a89c8f82756953493f38342e2b2720191007000000000a1724303d4a5763707d8a9aa4afbbbeb3a9978a7d7164574a3e3124212e3b4854616e7b8797a1adb9c0b6ac998c80736653493f33271b0f030000000000000000000000060b12181d1f202422272b2d2d2b273946535f6c7986929facb9baada194877a6e6154473b2e2114080000000f1a26313c46535e69727f8b939ea6afbabebebab8b5afacabacaeb5b7b9bdbfbab0a79f948d80746b60544a3f3428180e040000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f322c2d2e2d2c292423201f1b17110a020000000000000000000000121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbebebdbfbab9b6b0aba59e9591847a6e665c50443a3024190500000000121e2b3845515e6b7884919eabb7bfb6a99c8f8376695c5043362c3945525f6c7885929fabb8bfb4a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbfbebebebab8b3ada8a099928b7f726c61574d42352b210f060000000000000000000000000000000000030f1b27333f495365727f8c98aab4bebfbfbfbbafa399897d7063564a3d2e23170c000000000000000000000000000000121e2b3845515e6b7884919eabb7bfb6a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b6bfbfb8aca095877b6e6154483b2f24180c0913202d3a4653606d7985929fabb8bfbfb8ac9f9285796c5f5246392c1f1300000004101c2934404b55606c77828f97a1a9b2bac1bfbab8b4b0aeaeaeb0b3b8babfc4beb6afa49f92867c6f62594f4432281e130800000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d5765717e8b98a2aebac7d4c8bcb1a7998d8073665b5044382b1f12070000000000000000000000000000000000000000000000000000000000000813202c3945525d6875828f9baab4bcb1a7998c807366584e43372b1b1106000000000000000000000000000000000713202d3a4653606d7985919eaab4b2b2aca196897d7063574d4236414c5663707d8996a0acb2b2b3a99e9184786c6053463c31261b0f030000101d2a3743505d6a7683909da9b2b2b2b2a89b8f8275685e5241382d3a4753606d7a8693a0adb1b1b1a79a8d8174675a4e4134271b0e00000000000000000000000001070c10131417171b1f20201f1c171515121214151919191919191919191413100d070100000000000000000000000407090a0d0d0d0d0d0d0d0d0c0b090506060c10121312100c060706040000000001050707060b10121312100b0607060400000000000000000000000000000815222e3b4855616e7b8894a8b2bdb6a99d908376655b5046443f3838322b22190f040000030f1b27333f49536673808c99acb6b2b2ada297887b6e6155483b2e22202d3a46525e697885919eabb2b2b2a99c8f8276655b5044372b1f120500000000000000000000000001070c10131417171b1f20201f2c3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000a15202a36424d57626d75818e949ea5aeb4babec4c0bbb9b8b9bbbfc4bfbab4aea69e959082796d60594f42382e231706000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225212120201d181613120f0b0600000000000000000000000000121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b1b1b4aeaca9a69f9c938e837b6e685e544a3f32281e130800000000121e2b3845515e6b7884919eabb2b2b2a99c8f8376695c5043362c3945525f6c7885929fabb2b2b2a79a8d8174675a4e4134271b0e00121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b2b1b3adaba9a19e9691877f726d625a50453b3123190f000000000000000000000000000000000000000b17222d3c4955626f7c8898a2aeb2b2b2b2b2ac9f92867a6d6053473a2d201406000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2a99c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da9b2b2b2b2aa9d908477695e53463a2d1d120706121f2b3844505c6675818e9babb5b2b2b2ac9f9285796c5f5246392c1f13000000000c18232f3944505b656e7b859197a1a8afb7bcc2c5c0bdbbbabbbdc0c5c3beb9b2aca49f928b7f726a5f53473e3320160c020000000000000000000000000000000000000000000000000000000000000000000000000714202d3a46525e6976828f9caab4bfcad6cdc3b7ab9e9184786c605346392f24180c00000000000000000000000000000000000000000000000000000000000004111d2935414c5664717e8a98a2aebab7aa9d9184776a5f5447382d22170b0000000000000000000000000000000713202c38444f5964717e8b97a1a5a5a5a5ab9e9184786c6053463b303a4854606b7784919daaa5a5a5a5a0968a7d7063584e43372b1f12060000101d2a3743505d6a7683909da5a5a5a5a5a1968a7d7063564d412f2d3a4753606d7a8693a0a4a4a4a4a49a8d8174675a4e4134271b0e000000000000000000000000000000040607060b0f121313120f0b0608060507080d0d0d0d0d0d0d0d0d07060401000000000000000000000000000000000000000000000000000000000000000003060706030000000000000000000000000000000306070603000000000000000000000000000000000000000713202d3a4653606d798696a1adb9b8ab9f9285796c605553504a47433d342b20160a000005121f2b3744505b6576828f9ca5a5a5a5a59e928578695f53463a2d211e2a36424d576975828f9ca5a5a5a5a59f9285796c605346392d201306000000000000000000000000000000040607060b0f121313202c3946535f6c7986929facb9baada194877a6e6154473b2e211408000000030e1a25313b45515b606d79828e939fa2aaadb3b7b9bdbdbdbcbdb9b7b4aeaaa29f948f837a6d675c51473d30261c1106000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f322518141413100d07060503000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a4a4aba39f9c99948f8981796e695f564d42382e20160c0200000000121e2b3845515e6b7884919ea5a5a5a5a59c8f8376695c5043362c3945525f6c7885929fa5a5a5a5a59a8d8174675a4e4134271b0e00121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a4a9a29f9b97928c847d726d625b51483e33291f1108000000000000000000000000000000000000000613202d3a4653606d7985929fa5a5a5a5a5a5a59d908376675d5145392c201306000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a59c8f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909da5a5a5a5a5a9998d807366574d42362a1e0b0103101c28343f4a5464717e8a99a3a5a5a5a5a59f9285796c5f5246392c1f130000000007121d27333f49535e696f7c8591969ea5abb0b6b9babfbdbdbdc0bbb9b7b2ada8a19a938c80746d62584e43352c210e04000000000000000000000000000000000000000000000000000000000000000000000000000815212e3b4854616e7b87939facb9c6d0dbd2c5b9ada196897d7063554b4035291d10040000000000000000000000000000000000000000000000000000000000010d19242f3a4753606d7985929facb8b8aca096887c6f6253493f33271b0f0300000000000000000000000000000915222f3b4854606b77839098989898989898998c7f72665b5044382c38444f5965727f8c98989898989898988f82766a5f53473a2e2115080000101d2a3743505d6a768390989898989898989184786c6053463b302d3a4753606d7a8693979797979797978d8174675a4e4134271b0e000000000000000000000000000000000000000003050606060300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c677884919eabb8baada297897c6f6762605c54544e463d32271b0f03000613202d394653606c788592989898989898988f827669574d42362a1e1a2530404d596673808c9898989898989897887b6e6255483b2f221508000000000000000000000000000000000000000003050613202c3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000009141f29333f45515c676d79818b92989fa2a9abadb2b0b0b0b2acababa39f98928c82796d685d554b40352b1e140a00000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0706040100000000000000000000000000000000000000121e2b3845515e6b7884919898989898989898989898989898989897969992908c88827d746d675f574d443b30261c0e040000000000121e2b3845515e6b788491989898989898988f8376695c5043362c3945525f6c788592989898989898988d8174675a4e4134271b0e00121e2b3845515e6b78849198989898989898989898989898989898979697928f8a857f796f6b625b51493f362c21170d000000000000000000000000000000000000000006121f2b3844505c6676828f9898989898989898988d807367554b4035291d1004000000000000000000000000000000121e2b3845515e6b788491989898989898988f8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a7683909898989898989897897c6f6356493c31251a0e00000b17232e3a4754616d7a8692989898989898989285796c5f5246392c1f1300000000010b17222d38414d57606a6f7c848f939c9fa6a9acaeb4b0b0b0b5afacaaa9a19e9691887f746e645b51463c32231a100000000000000000000000000000000000000000000000000000000000000000000000000006131f2b37434e5866727f8c99a4afbbc7d2d1d2c9bdb2a89b8e8174675d5145392c1f140800000000000000000000000000000000000000000000000000000000000008131f2c3945515d6775818e9ba9b3bdb2a89a8d8073655b5044372b1f12060000000000000000000000000000091623303c4956636f7c898c8c8c8c8c8c8c8c8c877a6e61544a3f3328323d4754616d7a868c8c8c8c8c8c8c8c8c887b6f6255483c2f2215090000101d2a3743505d6a76838c8c8c8c8c8c8c8c8c8073665b504438292d3a4753606d79868a8a8a8a8a8a8a8a8a8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050a0d0f10131313131313131313130b0b08050100000000000004080a0b13131313131313131313110605030000000000000000000000000000000000000004101c2834404b556975828f9ca8b5beb3a99c908279726e6d666260584e43382b1f1306000915222f3c4855626f7b888c8c8c8c8c8c8c8c8c8073665a4d4031261a1724313d4a5764707d8a8c8c8c8c8c8c8c8c8b7e7165584b3e3225180b000000000000000000000000000000000000000000000613202c3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000030d17212934404b555c676d757e858d92979b9ea1a8a3a4a3a8a19e9b99928e867f776d675d564c43392e23190c0200000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8b8b8a898886837f7b766f6b605d554d453b32291e150a000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8376695c5043362c3945525f6c78858c8c8c8c8c8c8c8c8c8174675a4e4134271b0e00121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8b8b898885827e79726d67605951483f372d241a0f06000000000000000000000000000000000000000003101c28343f4a5466737f8c8c8c8c8c8c8c8c8c8c8a7d7064574a3d2f24180d01000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8376695c504336291d10030000000000000000000000000000000000101d2a3743505d6a76838c8c8c8c8c8c8c8c8c85786d6053463a2d20130900000613202d3946525d6876828c8c8c8c8c8c8c8c8c85796c5f5246392c1f13000000000006111b262f3b454e58606a6f7a82899094999d9fa3aaa3a4a3aba49f9d9a97918c847d736d645c52493f342a201108000000000000000000000000000000000000000000000000000000000000000000000000000815212e3b47535f6a7784909dabb5c0c9c5c4c5c9c4b8ab9f9285796d6053473b3025190e02000000000000000000000000000000000000000000000000000000000004101d2935404b5564707d8a97a2adbab7ab9e9184786c605346392e23170b00000000000000000000000000000a1623303d495663707d7f7f7f7f7f7f7f7f7f7f7e71685e5242382d222d3946525d68717e7f7f7f7f7f7f7f7f7f7f7c6f6256493c2f23160900000b1824313e4b5764717e7f7f7f7f7f7f7f7f7f7a6e61544a3f33282d394653606c787e7e7e7e7e7e7e7e7e7e7c6f6256493c2f2316090000000000000000000000000003060809131313131313131313130b0a08050000000000000000000000000000000000000000000000000000030a10161a1c1d20202020202020202020181715110c06000000050b10141617202020202020202020201d13120f0b060000000000000000000000000000000000000c18232e404c5966737f8c99a8b2bdb7ab9f9490847f7b79786f6a6054473b2e221508000815222e3b4855616e7b7f7f7f7f7f7f7f7f7f7f7c6f6255483c2f221514212e3a4754616d7a7f7f7f7f7f7f7f7f7f7f7d6f6356493c30231609000000000000000000000000000000000000000000000613202c3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000050f18232f39434b555c606d717a80858a8e9196959697969596918e8b86817b726c655d554c443a30271d11080000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7e7d7b7976736e6a636059514b433b332a20170c030000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7e7164574a3e3125323f4c5865727f7f7f7f7f7f7f7f7f7f7d7063564a3d3023170a000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7d7b7975716d67605c554f463f362d251b1208000000000000000000000000000000000000000000000b17232e3b4855616e7b7f7f7f7f7f7f7f7f7f7f7f7a6d6054473a2d211407000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7e7164574a3e3124170b0000000000000000000000000000000000000b1824313e4b5764717e7f7f7f7f7f7f7f7f7f7e71665c5044382b1f1206000005111d2935414c5663707d7f7f7f7f7f7f7f7f7f7f7265584c3f3225190c0000000000000a141d29333c464e585f686d757d83888c90929896969797969993908d8a847f79706b635b524a40372d22180e0000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a54626f7c8895a0acbdc4bdb9b7b9bdc4baaea2988a7e7164564d41362a1e11050000000000000000000000000000000000000000000000000000000000000c18242f3a4653606d7985929fabb8b9ada196897c6f63544a3f34281c1003000000000000000000000000000916222f3b4854606b7072727272727272727272716c61564c412f261c2935414c56616c71727272727272727272726f6a6054483b2e22150900000a1723303d4955616c717272727272727272726e685e5242382d222b3844505b666c717171717171717171716f6a6054473b2e2215080000000000000000000000040a0f13151620202020202020202020181714110c060000000000000000000000000000000000000000000000040d151c2226292a2d2d2d2d2d2d2d2d2d2d2524211d171109000810171c2123242d2d2d2d2d2d2d2d2d2d2a201f1b17110a02000000000000000000000000000000000716222f3c4955626f7c8896a1acb9bcb0a69f96918b8886857c6f6256493c2f231609000814212d3a47535f696e727272727272727272726f6a5f53473a2e211513202d3946525d686d727272727272727272726f6b6054483b2f221509000000000000000000000000000000000000000000000613202c3946535f6c7986929facb9b9ada194877a6e6154473b2e21140800000000000007121d273139434b515a62686d73797d818487898a8a89888784817e7a746e69605b534c433a32281e150b000000000000000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3225180c00000000000000000000000000000000000000000000000b1724313d4a56626c71727272727272727272727272727272727171706e6d6666625f58544f45413a312a21180e05000000000000000b1724313d4a56626c71727272727272727272716c6155493d3024313e4a56626d72727272727272727272706b6054483c2f221609000b1724313d4a56626c71727272727272727272727272727272727271706e6c6564605d55514b433d342d241b130900000000000000000000000000000000000000000000000614212d3a46535f696e72727272727272727272726d685d5245392c201307000000000000000000000000000000000b1724313d4a56626c71727272727272727272716c6155493d3023170a0000000000000000000000000000000000000a1723303d4955616c71727272727272727272716c61544a3f34281c10030000010d1924303a4854606b70727272727272727272726d62564a3e3124180b000000000000020b17212b343c464e565e616b70767c80838688898a8a8a89888684817d79726d676059524940382e251b10060000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505c6673808d9aa7b1bcbab2acaaacb2babeb4aa9c8f8276685e5246392d20150a00000000000000000000000000000000000000000000000000000000000007131f2c3845515c6674818e9ba9b3bdb2a89a8d8074665c5044382b1f1207000000000000000000000000000713202c38444f5960636565656565656565656564615a50443b301d1924303a44505a6164656565656565656565656260584e43382c1f130700000815212d3945505a6164656565656565656565615e564c412f261c28333f4a545b60646464646464646464646260584e43372b1f130600000000000000000000060e151b1f21222d2d2d2d2d2d2d2d2d2d2423211d171008000000000000000000000000000000000000000000030d161f262d3235363939393939393939393931302d29221b1209121a22282d303139393939393939393939372d2b27221b140b020000000000000000000000000000000815222e3b4754606a7884919ea9b2bdb9b0a8a09e989992897c706356493d3023160a0006121e2b37424d575f6165656565656565656565625f584e43372b1f12111d2935414c565d61656565656565656565656360594f44382c201307000000000000000000000000000000000000000000000613202c3946535f6c7986929facadadada194877a6e6154473b2e211408000000000000010b151f273139404550565e61676d7174787a7c7d7d7d7c7a7875716d68615e575049413a312820160c03000000000000000e1b2734414e5a6774818d9aa7adadada5988b7e7265584b3f3225180c00000000000000000000000000000000000000000000000915212e3a45505a62656565656565656565656565656565656565646361605c5455534e48443d352f281f180f0600000000000000000915212e3a45505a626565656565656565656564615a5045392d222e3a46515b62656565656565656565656360594f44382c201307000915212e3a45505a62656565656565656565656565656565656565646361605b5353514b454039312b221b120901000000000000000000000000000000000000000000000005121e2a36424d575f616565656565656565656565605d564c4135291d1104000000000000000000000000000000000915212e3a45505a626565656565656565656564615a5045392d2114080000000000000000000000000000000000000815212d3945505a616465656565656565656564615a5042382e23170b0000000008131e2c38444f59606365656565656565656565625b51463a2e22160900000000000000050f19222b343c444c525960636a6f7376797b7c7d7d7d7c7b7a7774706d66605d554f4740372e261d130900000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7984919eabb8bdb2a8a09ea0a8b2bcb9ac9f92867b6e6154473c32261b0f00000000000000000000000000000000000000000000000000000000000004101c2834404b5463707d8997a1adb9b8ab9e9285796d6053463a2e23180c0000000000000000000000000004101b27323d474f545659595959595959595959575550483e32291e131e28323e485055575959595959595959595956544e463d32271b0f03000005111d28343e4850555759595959595959595954524c443b301d17222d38424a50535757575757575757575756544e463d32271b0f0300000000000000000006101820262b2e2f3939393939393939393931302d28221a120800000000000000000000000000000000000000000a151f2831383e4243464646464646464646463e3d39342d241b111a242c33393c3e46464646464646464646443937332d261d140a00000000000000000000000000000006131f2b37434e5865727f8c96a1abb4bdbab2acaaaba396897c706356493d3023160a00020e1a26313c454d53555959595959595959595955534e463c31261b0f0d1924303a444c52545959595959595959595956544f473d32271b0f03000000000000000000000000000000000000000000000613202c3946535f6c7986929fa0a0a0a0a094877a6e6154473b2e21140800000000000000030d151f272f343f444c52555c606468686d6f7071706f6d686865615e56534d443f382f281f160e0400000000000000000e1b2734414e5a6774818d9aa0a0a0a0a0988b7e7265584b3f3225180c000000000000000000000000000000000000000000000005111d29343f48505658595959595959595959595959595959585857565553504a4847433c383229241d160d0600000000000000000005111d29343f48505658595959595959595959575550483e33281e29343f4951565859595959595959595956544f473d33271c10040005111d29343f48505658595959595959595959595959595959595858565553504947454039342f271f19100900000000000000000000000000000000000000000000000000020e1a26313b454d5355595959595959595959595954524c443a2f24190d010000000000000000000000000000000005111d29343f48505658595959595959595959575550483e33281d110500000000000000000000000000000000000005111d28343e48505557595959595959595959575550483e30261c11060000000002101b27323d474f5456595959595959595959585651493f34291e12060000000000000000071019222a323a41464f54585f6266666d6e70707170706e6d676763605c54514b433d352e251d140b010000000000000000000000000000000000000000000000000000000000000000000000000004101d2935404b5563707d8997a1adb9b9aca0969196a0aab4bbafa3998c7f7265584e43372b1c11060000000000000000000000000000000000000000000000000000000000000c18232e3a4653606d7985929eabb8b9ada197897d7063554b4034281c1004000000000000000000000000000b16212b353d4448494c4c4c4c4c4c4c4c4c4c4b49453e362c20170d16202c363e45494a4c4c4c4c4c4c4c4c4c4c4948433d342b21160a000000000c17222c363e45494b4c4c4c4c4c4c4c4c4c4746413b32291e111c262f383f44464b4b4b4b4b4b4b4b4b4b4947433d342b20150a000000000000000000040e18222a32373b3c464646464646464646463e3d39332c241a100600000000000000000000000000000000000005101c26313a434a4e50535353535353535353534b49453f362d2217222c363e44494a535353535353535353535046443f382f261b11060000000000000000000000000000030f1b27323c4753606d79849199a3abb2b8bcb9b7b4a396897c706356493d3023160a000009151f2a333c4247484c4c4c4c4c4c4c4c4c4c4847433c342a20150a08131e28323a4146474c4c4c4c4c4c4c4c4c4c4948443d352b21160b00000000000000000000000000000000000000000000000613202c3946535f6c79869293939393939393877a6e6154473b2e2114080000000000000000030d151d2329323a41464b515357565d616263646362615e565854524c46423b332d261d160d040000000000000000000e1b2734414e5a6774818d939393939393938b7e7265584b3f3225180c0000000000000000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4b4b4a4846443f3b3a37312c272118130c0400000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4a49453e362c2218232d373f464a4c4c4c4c4c4c4c4c4c4c4a48443d352b21160b0000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4b4a4846443f3a38352f29231d150d0700000000000000000000000000000000000000000000000000000009141f2a333b4246484c4c4c4c4c4c4c4c4c4c4c4745413a32281e13080000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4a49453e362c22170c00000000000000000000000000000000000000000c17222c363e45494b4c4c4c4c4c4c4c4c4c4a49443e362c1e140a0000000000000b16212b353d4448494c4c4c4c4c4c4c4c4c4c4a463f372d23180d01000000000000000000071018202830363d44484e5355545c6061636364646362605d555753514a454039312c231c130b02000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3945515d6774818e9ba9b2bdb2a89e91849198a2aebab5ab9d9083776a5f5347382e23170b00000000000000000000000000000000000000000000000000000000000007121f2b3844505c6674818d9aa8b2bdb3a99b8e8174675c5145382c1f130700000000000000000000000000040f19232b32383b3d3f3f3f3f3f3f3f3f3f3f3e3d39342c241a0e050e1a242c33393c3e3f3f3f3f3f3f3f3f3f3f3c3b38322b22190f040000000006101a242c34393d3e3f3f3f3f3f3f3f3f3f3b3936302920170d141d262d3338393e3e3e3e3e3e3e3e3e3e3c3b37322b22190f040000000000000000000a15202a343c434749535353535353535353534b49453e362c22170c0000000000000000000000000000000000000a16222d38434c545a5d60606060606060606060585650483f34291d28333e48505557606060606060606060605d53504941382d22170b0000000000000000000000000000000a15202c3945515d676f7d879299a0a8acb1b5b7afa396897c706356493d3023160a0000030e18212a31373a3b3f3f3f3f3f3f3f3f3f3f3c3a37312a22180e04020c1620283035393a3f3f3f3f3f3f3f3f3f3f3c3b38322b23190f0400000000000000000000000000000000000000000000000613202c3946535f6c79878686868686868686867a6e6154473b2e211408000000000000000000030b121820283036394045464a4c5254565757565554524c4b4746413a363127221b140b04000000000000000000000e1b2734414e5a6774808686868686868686867e7265584b3f3225180c00000000000000000000000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3e3e3d3b3a38342e2e2b26201b160d070100000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3e3d39332c241a111b252d343a3e3f3f3f3f3f3f3f3f3f3f3d3c38332b23190f0500000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3e3d3b3937332d2c29241d18120b0300000000000000000000000000000000000000000000000000000000030e18212a31363a3b3f3f3f3f3f3f3f3f3f3f3f3a39352f2820160c0100000000000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3e3d39332c241a1005000000000000000000000000000000000000000006101a242c34393d3e3f3f3f3f3f3f3f3f3f3e3c39332c241a0c02000000000000040f19232b32383b3d3f3f3f3f3f3f3f3f3f3f3e3a342d251b11060000000000000000000000060e161e252a33383c4347484a51535556575757565553514b4a46444039352f271f1a110a010000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7985929facb8b9ada196897d86929facb8b8aca095887c6f62544a3f34281c1003000000000000000000000000000000000000000000000000000000000003101c28343f4a54636f7c8996a1adb9b8ab9f9285796d6053463a2f24180d010000000000000000000000000007111921272c2f303232323232323232323231302d28221a12080008121a22282d3031323232323232323232322f2e2c272119100700000000000008121a22282d30313232323232323232322e2d2a251e170e050b141c22282b2d313131313131313131312f2e2b2720191007000000000000000000030f1b26323c464e535560606060606060606060575550483e33281d110500000000000000000000000000000000010d1a26323e4a545e66696c6c6c6c6c6c6c6c6c6c64625a5045392d212d3944505a61646c6c6c6c6c6c6c6c6c6c6a605b53493f33271b0f03000000000000000000000000000004101d2935404b55606b717e8791969da0a7a8aaaca396897c706356493d3023160a000000060f181f262b2d2e323232323232323232322f2e2b26201810060000040e161e24292d2e32323232323232323232302f2c272119110700000000000000000000000000000000000000000000000006121f2c3845525e6a75797a7a7a7a7a7a7a7a7a776c605346392d2013060000000000000000000001070e161e252a2e34383a3e414647494a4a4a494746413e3a3935302a251f17110a0200000000000000000000000713202d3a4653606d797a7a7a7a7a7a7a7a7a786d6053463a2d2013070000000000000000000000000000000000000000000000000009121b22292e3132323232323232323232323232323232323231302e2d2c2823211f1a150f0b0400000000000000000000000000000009121b22292e313232323232323232323231302d28221a1209131b23292e3132323232323232323232302f2c2721191108000000000009121b22292e3132323232323232323232323232323232323231302e2d2b27221f1d18120c0701000000000000000000000000000000000000000000000000000000000000060f181f262a2d2e32323232323232323232322d2c29241e160d04000000000000000000000000000000000000000009121b22292e313232323232323232323231302d28221a12080000000000000000000000000000000000000000000008121a22282d303132323232323232323231302d28221a1208000000000000000007111921272c2f3032323232323232323232312e29231b130900000000000000000000000000050c131921272c31373a3c40444648494a4a4a49484745403d3a38342e29241d150d080000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36414c5664717e8a98a2aebab8ab9e918478818e9baab4bcb1a79a8d8073665c5044382b1f13080000000000000000000000000000000000000000000000000000000000000b17232e394653606c7884919eabb7baada2978a7d7064554b4035291d10040000000000000000000000000000070f161b202223262626262626262626262423211d1710080000000810171c2123242626262626262626262623221f1b160f0700000000000000000810171d21232426262626262626262621201e19140d0500020a11171c1f202424242424242424242423221f1b150f070000000000000000000006131f2b37434e585f626c6c6c6c6c6c6c6c6c6c64615a5045392d21140800000000000000000000000000000000030f1c2935424e5a66707679797979797979797979716c6256493d3327303c4955616c7179797979797979797979776c655b5044372b1f12050000000000000000000000000000010d18242f39434f59616c717d848b9095989b9e9fa396897c706356493d3023160a00000000060e151a1e21222626262626262626262622211f1b150e0600000000040c13191d2021262626262626262626262322201b160f0700000000000000000000000000000000000000000000000000000613202c3945515d676d6d6d6d6d6d6d6d6d6d6c655b5044372b1f1205000000000000000000000000050c13191d23282c2d3035393a3c3d3e3d3c3a3936302e2d29251e1a140b060000000000000000000000000006131f2c3845515c676d6d6d6d6d6d6d6d6d6d6d665c5044382c1f120600000000000000000000000000000000000000000000000000000911181d2124252626262626262626262626262626262525242322201f1c1714120f09030000000000000000000000000000000000000911181d2124252626262626262626262423211d171008010911181e2224252626262626262626262322201c160f08000000000000000911181d2124252626262626262626262626262626262625252322201f1b1713100c0701000000000000000000000000000000000000000000000000000000000000000000060e141a1e2122262626262626262626262621201d19130c04000000000000000000000000000000000000000000000911181d2124252626262626262626262423211d1710080000000000000000000000000000000000000000000000000810171d2123242626262626262626262423211c17100800000000000000000000070f161b2022232626262626262626262524221e18110901000000000000000000000000000002080d161c20262b2e2e34383a3b3d3d3e3d3d3b3a38352f2d2c28231c18120b0300000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3946525e6876828f9caab4bdb2a89a8d80747d8a98a2aebab8ab9e9185796d6053463a2f24190d01000000000000000000000000000000000000000000000000000102040006121f2b3744505b6573808d9aa8b2bdb3a99b8e8175675d5145392c201308000000000000000000000000000000040b1013161619191919191919191919181715110c060000000000050c11141717191919191919191919191615130f0a0400000000000000000000060c111517181919191919191919191414110e080200000000060b0f1213181818181818181818181615130f0a0400000000000000000000000815212e3b47535f6a7679797979797979797979716c6155493d3023170a0000000000000000000000000000000003101d2a3643505d697682868686868686868686867e7164594f44382c38444f5964717e8686868686868686868683786c605346392d20130600000000000000000000000000000007121d28313d47505a616b6f787e83888b8f91929994897c706356493d3023160a000000000003090e121415191919191919191919191515120f0a0400000000000002080d111314191919191919191919191615130f0b0400000000000000000000000000000000000000000000000000000004101d2935404b555d60606060606060606060605b53493f33271b0f030000000000000000000000000002080d12181c1f2024292d2e2f3031302f2e2d2a2521201d19130e0903000000000000000000000000000004101c2834404b555c60606060606060606060605c544a3f34281c1003000000000000000000000000000000000000000000000000000000060c1115171819191919191919191919191919191919181817151312100c060602000000000000000000000000000000000000000000060c11151718191919191919191919171714110c05000000060d12151819191919191919191919171613100b05000000000000000000060c11151718191919191919191919191919191919191918171513120f0b06040000000000000000000000000000000000000000000000000000000000000000000000000003090e12141519191919191919191919191413110d0801000000000000000000000000000000000000000000000000060c11151718191919191919191919171714110c050000000000000000000000000000000000000000000000000000060c11151718191919191919191919171614100b05000000000000000000000000040b10131616191919191919191919191816120d06000000000000000000000000000000000000050b10151b1f2123282c2d2e30303131302f2d2c2924201f1c18120c07010000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3b4754616e7a86929facb9b9ada196897c6f7985929facb8b9ada197897d7063554c4135291d11040000000000000000000000000000000000000000000003080b0e0e1111110f1b27333f4953626f7c8896a0acb9b8ac9f92867a6d6053473a3024190d01000000000000000000000000000000000407090a0c0c0c0c0c0c0c0c0c0c0b0a080500000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c09090703000000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0807050200000000000000000306060b0b0b0b0b0b0b0b0b0b09080603000000000000000000000000000916222f3c4955626f7c868686868686868686867e7164574b3e3124180b00000000000000000000000000000000000a1723303d4a5663707d8994939393939393939083776b6055483c313b4854606b76839093939393939393958a7d70655b5044372b1f1205000000000000000000000000000000010c161f2b353e48505960666d72777b7f8284868788887d706356493d3023160a00000000000000020608080c0c0c0c0c0c0c0c0c0c0908060300000000000000000000010507070c0c0c0c0c0c0c0c0c0c090907030000000000000000000000000000000000000000000000000000000000010d18242f39434b515353535353535353535353504941382d22170b0000000000000000000000000000000000070c101313191d2021232424232221201d191413110d080200000000000000000000000000000000000c18232e39434b515353535353535353535353504a42382e23170c00000000000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0b0b0a0807060300000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0b0a08050000000000000106090b0c0c0c0c0c0c0c0c0c0c0a0907040000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0b0a08060503000000000000000000000000000000000000000000000000000000000000000000000000000000000000020507080c0c0c0c0c0c0c0c0c0c0c070704010000000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0b0a080500000000000000000000000000000000000000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0b0a0804000000000000000000000000000000000407090a0c0c0c0c0c0c0c0c0c0c0b090601000000000000000000000000000000000000000000040a0f1215181c1f2022232424242322201f1d181312100c07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b37434e5865727f8c99a3afbbb8ab9e9184786c75818e9ba9b3beb3a99b8e8175675d5145392c201409000000000000000000000000000000000000000001090f14181a1b1e1e1e1e17222d384754606a7784919eaab7baaea2988a7e7164564c4135291d1104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8893939393939393938a7e7164574b3e3124180b00000000000000000000000000000000000916222f3c4854606b7683909ca69f9f9f9fa095897d7063584e4337434e5863707d89959f9f9f9f9fa79d9083786c6053493f33271b0f0300000000000000000000000000000000040d19232c363e474f545c60656a6f727577797a7b7c796d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d28313940454747474747474747474746443f382f261b1106000000000000000000000000000000000000000406080d11131416171717161413110d080705010000000000000000000000000000000000000007121d27303940454647474747474747474746443f3830261c11060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306070c101213151617171716151413100c070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3a47535f6a7783909dabb5bdb2a99a8d807465707d8a97a2adbab8ac9f92867a6d6054473b31251a0e02000000000000000000000000000000000000020b131a202427282a2a2a2a2a2a2b37434e586673808c99a7b1bcb4aa9b8f8275685d5245392c2014080000000000000000000000000004061313131313131313131313131313131313131313131313131313131313131313131311100e0a0600000000000000000000000003080b0d0e1313131313131313130c0b0905010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c88959f9f9f9f9f9f978a7e7164574b3e3124180b00000000000000000000000000000000000713202c38444f5963707d89949fabacacb1a79c8f82766a5f53473b47535f6a75828f9ca7b1acacaca0958a7d70655b5041382d22170b00000000000000000000000000000000000007111a242c353d424a5153585f626568666c6e6e6f6d675d5145392c201306000000000000000000000000000000000000020507080a0d0e0f0f0f0e0d0b08070502000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c161f282f35393a3a3a3a3a3a3a3a3a3a3937332d261d140a000000000000000000000000000000000000000000000001050707090a0b0a09070705010000000000000000000000000000000000000000000000000b151e272e34383a3a3a3a3a3a3a3a3a3a3a38342e261e150a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070b0f11121313131313131313130a09070400000000000000000000000000000000000000000000000000000000000000030608090c0e0f101110100e0c09070603000000000000000000000000000000000000000000000000000000000000000000000000030608091313131313131313131313090806030000000000000000000000000000000000000000000000000000000000000000000000000000020507080b0e1011121211110f0d0b0707040100000000000000000000000000000000000000000000000000000000000000000005080a0b0b0b0b0b0b0b0b0b0b08070502000000000000000000000000000000000000000000000000000000000000000000000000000000000000010507070a0d0f1011100f0e0b080806020000000000000000000000000000000000000000000000000000000000000000000000000000000000040607080a0a0b0a0a0807060400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27333f4953626e7b8895a0acbdb9ada196897c6f636d7985929fabb8baaea2988b7e7165574d42362a1e12050000000000000000000000000000000000010b151d252b30333537373737373737323c4855626e7b8895a0acb8b9ac9f92867a6d6054473b3025190d0100000000000000000001070c1013202020202020202020202020202020202020202020202020202020202020202020201e1d1a16110b04000000000000000001080f14181a1b202020202020202020181815110c0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2acacacaca4978a7e7164574b3e3124180b000000000000000000000000000000000004101c27333d4854606b7683909ca6b0bcb7ab9f94887c6f62564d424d57626f7c88949eaab9bcb1a79d9083786c6053493f2f261b11060000000000000000000000000000000000000008121a232b30394044464e535558545b60616162605d554b4135291d11040000000000000000000000000000000004080e11141417191b1c1c1c1b1a181514120e09040100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d161d24292c2d2d2d2d2d2d2d2d2d2d2d2b27221b140b02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c151d23282c2d2d2d2d2d2d2d2d2d2d2d2c28231c150c030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050c12171b1d1e202020202020202020171614100b05000000000000000000000000000000000000000000000000000001050a0f121515181b1c1d1d1d1c1b19161312100c060000000000000000000000000000000000000000000000000000000000000000040a0f12151520202020202020202020201515120f0a030000000000000000000000000000000000000000000000000000000000000000000004090e121415181a1c1e1e1f1e1d1c1a171413110d08030000000000000000000000000000000000000000000000000000000000060c111517181818181818181818181514120e0903000000000000000000000000000000000000000000000000000000000000000000000000000104080d111314171a1b1c1d1d1c1a181514120e0905010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6573808d99a7b1bcb8ab9e9184786c606774818e9ba9b3beb4aa9c8f8376695e53463a2d21150a000000000000000000000000000000000009131d272f373c404144444444444444444447535f6a7784909daab7baaea3998b7e7165564c41362a1e11050000000000000000030b12181c1f2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2a2927221c150d05000000000000020b131a202427272d2d2d2d2d2d2d2d2d2524221d181109000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afb9b9b1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000b16212c38444f5963707d89949fabb7bbb0a69b8e8174685e5246525e6974818e9ba6b0bbb8aca0958a7d70655b5041382d1d140a0000000000000000000000000000000000000000000811191e272e34383c4347484c4a505354555554514b433a2f24180d010000000000000000000000000001070c1014191e202124262829292928262421211e1a14110d0801000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c12181d2020202020202020202020201f1b17110a0200000000000000000003080b0d0e1313131313131313130d0c0a060200000003060809131313131313131313131307070501000000000000000000000000030b12181c1f20202020202020202020201f1c17110a030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d2423201c161008000000000000000000000000000000000000000000000002080d11151b1f21222527292a2a2a29282623201f1c17110f0a0400000000000000000000000000000000000000000000000000000000060e151b1f21222d2d2d2d2d2d2d2d2d2d2d22211f1a150e0600000000000000000000000000000000000000000000000000000000000001070c10141a1e20212527292a2b2b2b2a29272421201d19130f0b0600000000000000000000000000000000000000000000000000000910171d21242425252525252525252521211e1a140d050000000000000000000000000000000000000000000000000000000000000000000001070d1113191d2021242728292a2a29272522211e1a15110d080200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030607070707070707070707070604000000000000000000000000000000000000000000000613202d394653606c7884919eabb7beb2a99a8d8074655b63707d8a97a2adbab9ac9f93877b6e6154483d32271b0f00000000000000000000000000000000030f1a252f3941484c4e515151515151515151514e5866727f8c99a7b1bcb4ab9c8f8276685e5246392d20140900000000000000030d151d23292c393939393939393939393939393939393939393939393939393939393939393939393736332e271f170d0400000000010b141d252b30333439393939393939393932312e29231b12090000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bcb9ac9f92867b6e61554c56616e7b86929facb9bcb1a79d9083786c6053493f2f261b0b0200000000000000000000000000000000000000000000070c151c23282c31373a3c3f3f44464748494745413a31281d130700000000000000000000000000030b12181d1f252a2d2e3133343536353533312e2d2a25201d19130b0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d10131414141414141414141413120f0b0600000000000000000001080f14181a1b202020202020202020191916120d07040a0f121515202020202020202020201f1413110d0802000000000000000000000000070c1013131414141414141414141312100c06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050f1820282f333738393939393939393939302f2c28211a1108000000000000000000000000000000000000000001070c14191e20262b2e2f3234363637363634322f2d2c28231c1b150e09030000000000000000000000000000000000000000000000000006101820262b2e2f39393939393939393939392f2e2b262018100600000000000000000000000000000000000000000000000000000000060b12181d1f252a2d2e31343637383838373533312d2c29241f1c17110a02000000000000000000000000000000000000000000000009121a22282d30313131313131313131312e2d2a251f170f050000000000000000000000000000000000000000000000000000000000000000060b13181d20252a2d2e3133353637363634312f2e2b26201d19130d0701000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b1012131414141414141414141413100c070100000000000000000000000000000000000004101c2934404b5563707c8996a1acb9b9ada197897c6f6353606d7985929fabb8bbafa49a8c7f7366584e43372b1c12070000000000000000000000000000000814202b37414b53595b5d5d5d5d5d5d5d5d5d5d5d5d616e7b88959fabb8b9ac9f92867a6e6154473b31251a0e020000000000010b151f272f34384646464646464646464646464646464646464646464646464646464646464646464644423f3931291f150b0000000008131d262f363c40414646464646464646463f3d3a342d241b110600000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7baaea3998d8073675d525d6873808d99a3aebbb8aca0958a7d70655b5041382d1d140a000000000000000000000000000000000000000000000000030b12181c1f262b2e2f2d3338393b3b3c3a39352f281f160c01000000000000000000000001070d151d24292c3036393b3d404142424241403e3b3a36312c29241e17110a020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104060707070707070707070706050300000000000000000000020b131a202427272d2d2d2d2d2d2d2d2d2625231e19120e151b1f21222d2d2d2d2d2d2d2d2d2d2c21201d19130c050000000000000000000000000004060707070707070707070707060300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c16202a323a3f43454646464646464646463d3c38332c231a1005000000000000000000000000000000000000030b12181e252a2d31373a3c3f414243444343413f3c3a38342e2b26201a140d050000000000000000000000000000000000000000000000040e18222a31373a3c46464646464646464646463c3a37312a22180e0300000000000000000000000000000000000000000000000000020a11171d24292c30363a3b3e4143444545444442403e3a3935302b28221c140b0600000000000000000000000000000000000000000006101a242c34393d3e3e3e3e3e3e3e3e3e3e3b3a36312921170d030000000000000000000000000000000000000000000000000000000000020a11171d24292c3036393a3d404243444342413e3b3a37312d29251e18130c04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a11171c1f20202020202020202020201f1d18120b03000000000000000000000000000000000006131f2c3845515c6774818e9aa8b2bdb8ab9e9184786c60535c6674818e9aa9b3beb6ac9d9184776a605447392e23180c0000000000000000000000000000000b1824303c48535d64686a6a6a6a6a6a6a6a6a6a6a6a6a697683909da9b6bbafa3998b7f7265574d42362a1e1205000000000007121d273139404553535353535353535353535353535353535353535353535353535353535353535353514f4a433b31271c11060000030f1a252f3841484c4e5353535353535353534b4a453f372d23180c01000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bcb4ab9f9285796d6055606d7a85929fabb5bcb1a79d9083786c6053493f2f261b0b020000000000000000000000000000000000000000000000000000070c10151b1f212222282b2d2e2e2f2d2c29241d160d040000000000000000000000040c12181f272f35393b4146474a4c4e4f4f4f4e4d4b4846423b39352f27221b140b04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010b141d252b30333439393939393939393933322f2a231c1820262b2e2f39393939393939393939392e2d2a251e160e050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d28323c444b50515353535353535353534a48443e352c21160b0000000000000000000000000000000000060d151d24293036393c4347484b4e4f5050504f4e4c4946443f3837322a251f170f09000000000000000000000000000000000000000000000a15202a343c43474853535353535353535353534847433c342a20150a000000000000000000000000000000000000000000000000060c141c23282f35393b4246484b4d4f51515251504f4d4a4745413a38332d261d17110a02000000000000000000000000000000000000000c17222c363e45494b4b4b4b4b4b4b4b4b4b4846423b33291f140900000000000000000000000000000000000000000000000000000000050b141c22282f35393a4146474a4d4e4f50504f4d4b4847423c39353029241d160d0800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c141c23282b2d2d2d2d2d2d2d2d2d2d2d2c29241d150d03000000000000000000000000000000000714202d3a4753606d7985929fabb8beb2a99a8d8074665b505463707d8997a1adb9b8aca096897c6f62544a4034281c100400000000000000000000000000010e1a2733404c59646f747777777777777777777777777777777f8c98a5b2c0b5ab9c908376695e53463a2d21150900000000000c18232f39434b515f6060606060606060606060606060606060606060606060606060606060606060605d5b554d43392e22160a00000814202b36414a53585a606060606060606060585651493f34291d1105000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7baada2978b7f72665c67727f8c98a2aebdb8aca0958a7d70655b5041382d1d140a0000000000000000000000000000000000000000000000000000000000040a0f121515171c1f2021222221201d18130c040000000000000000000000040d161d242931394045474c525457595b5c5c5c5b595754534d4745413a332d261d160e0500000000000000000000000001070b0f1112131313131313131313131313131313131313131313131313131313130f0e0c0804000000000000000000000000000000000008131d262f363c4041464646464646464646403e3b352e25222a31373a3c46464646464646464646463a3936302820160c02000000000000000000030608090e0e0e0e0e0e0e0a0907030004080a0b0e0e0e0e0e0e0e0706040100000000000000000000000000000000000000000000000000000000000000000000000000000b17232f3a444e565c5e60606060606060606057554f473e33281c10040000000000000000000000000000000810181f272f353b4146474e5355585a5c5d5d5d5c5b595653504a47433c363129211b120a0100000000000000000000000000000000000000030f1b26313c464e5355606060606060606060606055534e463c31261a0f0200000000000000000000000000000000000000000000070f181e262e34394045474d5254585a5c5d5e5e5e5d5c5a5754524c46443f382f28221c140b03000000000000000000000000000000000005111d28343e4850555758585858585858585854534d453b31251a0e020000000000000000000000000000000000000000000000000000070f171d262d333a4145474c5254575a5b5c5d5d5c5a5855534d4746413a352f281f1a11090100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141e262e34383a3a3a3a3a3a3a3a3a3a3a38352f271f150b01000000000000000000000000000005111d2935414c5664717d8a97a2adbab9ada197897c6f63544a53606d7985929eabb8bdb2a89a8d8074665c5144382c1f130800000000000000000000000000020e1b2835414e5b68748183848484848484848484848484848384919eaab7c4b9ac9f93877b6e6154483c31261a0e0200000004101c2934404b555c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6a675f554a3f33271a0e01000b1824303c48535c64676c6c6c6c6c6c6c6c6c65625b51453a2e221509000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bbb3a99e9184786c606d7985919eaab4bcb1a79d9083786c6053493f2f261b0b0200000000000000000000000000000000000000000000000000000000000000030608060b0f12131415161413110d07010000000000000000000000040d161f282f353e434b5153565e61646667686968686664615e5754524c443f382f2820170e0500000000000000000000050c12171b1d1e202020202020202020202020202020202020202020202020202020201c1b18140f09020000000000000000000000000000030f1a252f3841484c4e5353535353535353534c4b4640372e2a343c43474853535353535353535353524746413a32281e130800000000000000040a0f1215151a1a1a1a1a1a1a161613100b101416171a1a1a1a1a1a1a1413110d07010000000000000000000000000000000000000000000000000000000000000000000000020f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c6361594f44382c201407000000000000000000000000000008111a222a313940454c5254585f62656769696a6969676562605c54534e46423b332d241c130a0100000000000000000000000000000000000006121f2b37434e585f626c6c6c6c6c6c6c6c6c6c6c625f584e43372b1f1409000000000000000000000000000000000000000000071019212930383f444b5153575e616467696a6b6b6b6a686664605d5653504a423d332d261d150c03000000000000000000000000000000000815212d3945505a6164646464646464646464615e574d42362a1e12050000000000000000000000000000000000000000000000000007111921292f383f444b5154565e61646668696a69696764625f5754524c45413a312c231b130a0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c2630383f44464747474747474747474745403931271d120700000000000000000000000000000713202d3946525e6875828f9ca9b3beb8ab9e9184786c605346505c6674818e9aa9b3beb8ab9e9285796d6053463a3024190d0100000000000000000000000003101d2a3643505d6976839090909090909090909090909090909196a0acb9c5bbafa49a8c7f7266574e42372b1e120600000006131f2c3845515c67767979797979797979797979797979797979797979797979797979797979797979797771675b4f4236291d1003000d1a2733404c58646e74797979797979797979726d62564a3d3124180b000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7b9aca0968a7d7066717e8b97a1adbcb8aca0958a7d70655b5041382d1d140a0000000000000000000000000000000000000000000000000000000000000000000000000003060608080907060401000000000000000000000000020c161f283139404550555d6065686e7073747575757473716e6965605d565049413a322920170d030000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d282725201a130c03000000000000000000000000000814202b36414a53585a606060606060606060595751494035313c464e5355606060606060606060605f54524c443a3025190d010000000000060e151b1f2122272727272727272322201b171c2123242727272727272721201d18130c040000000000000000000000000000000000000000000000000000000000000000000004111d2a3743505c687278797979797979797979706b6155483c2f2316090000000000000000000000000008111a232c343c434b51565e61666a6f7274757677767674726f6d66625f58534d453e362e251c13090000000000000000000000000000000000000815212e3a47535f6a7679797979797979797979796f6a5f53473b30251a0e0100000000000000000000000000000000000000071019222b333b424a50555d6065696e71747677787877777573716d6864605b544f443f382f271e150b000000000000000000000000000000000a1724303d4955616c717171717171717171716e695e53463a2d211407000000000000000000000000000000000000000000000000071119232b333b424a50555d6065686d7073757677767574716e6966615e56514b433d352d251c130a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17232e38424a505353535353535353535353514b43392f24180c00000000000000000000000000000714212e3a4754616d7a86929facb9beb3a99a8d8074665b50444a5463707d8997a1adb9b9ada1978a7d7064564c4135291d110500000000000000000000000003101d2a3643505d697683909c9d9d9d9d9d9d9d9d9d9d9d9d9d9ea0a8b2bdc8c0b6ac9d9083776a5f53473a2e21150a0000000714202d3a4753606d7986868686868686868686868686868686868686868686868686868686868686868683776a5d5144372a1e1104000e1b2734414e5a6774808686868686868686867f7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bbb2a89c9083766c7884919da9b3bcb1a79d9083786c6053493f2f261b0b0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141e28313a434b515a62676d72767a7d7f8182828281807e7b77726d68605b534c443b32291f150b01000000000000050f1820282f333738393939393939393939393939393939393939393939393939393939393534312c251e150c020000000000000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6c66635b51463b37434e585f626c6c6c6c6c6c6c6c6c6c6c615e564c41362a1d11050000000006101820262b2e2f34343434343434302f2c2722282d3031343434343434342d2c29241d160d0400000000000000000000000000000000000000000000000000000000000000000005121e2b3845515e6b78848686868686868686867d7063574a3d3024170a00000000000000000000000007101a232c353e464e555d60686e73787b7e818283838382817f7c79746f6a615e57504840372e251b110700000000000000000000000000000000000915222f3c4855626f7c86868686868686868686877c6f62574d42362a1e1308000000000000000000000000000000000000050f19222b343d454d545c60676d72767b7e8082848485848382807d7a76706c666059504a423930271c12070000000000000000000000000000000b1824313e4b5764717e7e7e7e7e7e7e7e7e7e7b6e6154483b2e23180c0000000000000000000000000000000000000000000000060f19232b353d454d545b60676d72777a7d808182838382807e7b77736d68605d554f473f372e251c12080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a545c60606060606060606060605d554b4035291d100400000000000000000000000005121e2b37424d5765727f8b99a3aebbb9ada197897c6f63544a3f4653606c7885919eabb8beb3a99b8f8275685d5246392d20140900000000000000000000000003101d2a3643505d697683909ca9aaaaaaaaaaaaaaaaaaaaaaaaaaacb2bac3cec7b8aca095887b6e6255483c32261b0f0000000714202d3a4753606d7a86939393939393939393939393939393939393939393939393939393939393939084776a5d5144372a1e1104000e1b2734414e5a6774818d939393939393938b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7b7ab9f94897c707d8a96a0acbbb8aca0958a7d70655b5041382d1d140a000000000000000000000000000000000000000000000000000000000000000000000000000000000003060706030000000000000000000000000006111c26303a434c555d606c71797e83878a8c8e8f8f8f8e8c8a87837f7a726c655d564c443b31271d12070000000000010c16202a323a3f43454646464646464646464646464646464646464646464646464646464642403d372f271e13090000000000000000000000000d1a2733404c58646e74797979797979797979736d63574b3e3a47535f6a7679797979797979797979796d685e5246392d201307000000040e18222a32373b3c414141414141413d3b38322c33393c3e414141414141413a39352f281f160c01000000000000000000000000000000000000000000000000000000000000000005121e2b3845515e6b788491939393939393938a7d7063574a3d3024170a0000000000000000000000040d19222c353e474f585f676d737a8084888b8d8f9090908f8e8c8985817c756e69615a524940372d23190d03000000000000000000000000000000000815212e3a47535f6a75828f939393939393939a8e8174695e52463a2f24190d0000000000000000000000000000000000020b17212b343d464f575f666d72797e83878b8d8f90919191908f8d8a86827d78706b605b544a42392e23180f060000000000000000000000000003101d2a3643505d6976838b8b8b8b8b8b8b8b8b7f7366554b4034281c1004000000000000000000000000000000000000000000020c18212b353d474f575e666c727a7f83878a8d8e8f90908f8d8b88847f7a736d67605951493f372e241a0e0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505c666d6d6d6d6d6d6d6d6d6d6d675d5145382c1f13060000000000000000000000000714212d3a46535f697683909dabb5bfb8ab9e9185786c6053463944505b6674808d9aa8b2bdb9ac9f92867a6d6154473c31261a0e00000000000000000000000003101d2a3643505d697683909ca9b6b7b7b7b7b7b7b7b7b7b7b7b7b9bdc3cccbc8bcb1a7998c807366584e43372b1b110600000714202d3a4753606d7a86939f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9d9084776a5d5144372a1e1104000e1b2734414e5a6774818d9a9f9f9f9f9f988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bbb0a69b8e817683909da8b2bcb1a79d9083786c6053493f2f261b0b02000000000000000000000000000000000000000000000000000000000000000000000000000003060c10121312100c0600000000000000000000000b17232e38424c555d676d757e858b90939a999a9b9c9b9b999795908c857f776d685e564c43392f24180c040000000007121d28323c444b5051535353535353535353535353535353535353535353535353535353534f4d4841392f251a0f0400000000000000000000000e1b2734414e5a6774808686868686868686867f7366594c40404b55626f7c86868686868686868686867a6d6154473a2e2114070000000a15202a343c4347484d4d4d4d4d4d4d4948443d363e44494a4d4d4d4d4d4d4d4745413a31281d1307000000000000000000000000000000000000000000000000000000000000000005121e2b3845515e6b7884919e9f9f9f9f9f968a7d7063574a3d3024170a00000000000000000000010c161f2a343e474f59616a6f7980868c9196989a9c9c9d9c9c9a9897928e88827b716c635b52493f352b1f150b0100000000000000000000000000000006121f2b37434e5863707c89959f9f9f9f9f9f9f92867b6e61554c4135291c1207000000000000000000000000000000000a141d29333d464f5960696e787f858b9095979a9c9d9e9e9e9d9b9999928f8a837d736c665c544a40342821170d03000000000000000000000000000d192633404c5966737f8c979797979797978f8376675c5145382c1f13060000000000000000000000000000000000000000000a141e2a333d474f5960696e787f858c909597999b9c9d9c9c9a9795918c868079706b625b51493f362c20170d0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d787a7a7a7a7a7a7a7a7a796d6053473a2d2014070000000000000000000000000815222e3b4855616e7b88959fabbdbeb3a99a8d8074665b5044383f4a54636f7c8996a1adb9baaea3998b7e7265574d42372b1b1106000000000000000000000003101d2a3643505d697683909ca9b6bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb7aa9d9184776a5f5347382d22170b00000714202d3a4753606d7a8693a0acacacacacacacacacacacacacacacacacacacacacacacacacacacaa9d9084776a5d5144372a1e1104000e1b2734414e5a6774818d9aa7acacaca5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7b9ac9f92877e8b959fabbab8aca0958a7d70655b5041382d1d140a00000000000000000000000000000000000000000000000000000000000000000000000000060b0f12171c1f201f1c17110a03000000000000000003101c28343f4a545d676d79818b91979d9fa4aca7a8a8a8a7a6a7a09d97928b827a6e685e554b40352921160a000000000b17232f3a444e565c5e606060606060606060606060606060606060606060606060606060605b59534b41372c20140800000000000000000000000e1b2734414e5a6774818d939393939393938c7f7366594c4045515c6774808d93939393939393938e8174685e5246392d2013070000030f1b26323c464e53555a5a5a5a5a5a5a56544f473e485055575a5a5a5a5a5a5a54514b433a2f24180d010000000000000000000000000000000000000000000000000000000000000005121e2b3845515e6b7884919eabacacaca3968a7d7063574a3d3024170a0000000000000000000007121d28313c464f59616b707c848d92989ea1a8a7a8a9aaa9a9a7a9a29f9a938f867e736e635b51473d31271d1207000000000000000000000000000000030f1b26313c4854606b7683909da8b2acacaea3998d8073675d5145392e23180c00000000000000000000000000000006111b262f3b454e58606b6f7b838b92979d9fa7a7a9aaababaaaaa8aba39f9c95908880786d665c51443f33291f1409000000000000000000000000000916232f3c4956626f7c8997a2a4a4a4a49f9286796d6053463a2d201307000000000000000000000000000000000000000006111c26303c454f59606b6f7b838b92979da0a7a6a8a9aaa9a8a7a7a09d98928d847d726d635b51483e32291f140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8686868686868686868276695d5043362a1d10000000000000000000000007131f2c38434e586673808c99a7b1bcb9ada197897c7063544a3f33394653606c7884919eabb8bfb4ab9d908376695f5346382d22170b000000000000000000000003101d2a3643505d697683909ca9b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2aca096887c6f6253493f33271b0f03000714202d3a4753606d7a8693a0adb9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b7aa9d9084776a5d5144372a1e1104000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bbafa3999286929fa7b1bcb1a79d9083786c6053493f2f261b0b020000000000000000000000000000000000000000000000000000000000000000000001080d11171c1f23282c2d2c28231c150c03000000000000020c16202b3844505c666d79838e939ea1a9acafb6b4b5b5b5b4b3b1aca9a29e948f837a6e675d51453d32271b0f040000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c68655d53483d3125180c00000000000000000000000e1b2734414e5a6774818d9a9f9f9f9f9f998c7f7366594c404753606d7985929f9f9f9f9f9f9f94887c6f62564c41362a1d1105000006121f2b37434e585f62676767676767676360594f44505a616467676767676767605d554b4135291d11040000000000000000000000000000000000000000000000000000000000000005121e2b3845515e6b7884919eabb7b9b0a3968a7d7063574a3d3024170a000000000000000000010d18242f39434e58616b707d8691969fa3aaacb2b4b5b6b6b6b5b4b3adaba69e98928b80736d62594f43392f24180c010000000000000000000000000000000a15202c38444f5964707d8a96a0acb8bfb4ab9f92857a6d60544a4034281c100400000000000000000000000000000b17222d38414d57606a6f7d8590959ea1a9abb1b3b5b7b7b8b7b6b5b5afaca7a09a938d81786d605b51453b31261a0e030000000000000000000000000713202d3a4653606d7985929fabb1b1aea398897c706356493d2f24180c00000000000000000000000000000000000000000b17232e38424d57606b707d8590959ea1a9acb1b3b4b5b6b6b5b3b1acaaa29f9691877f726d635a50443b3025190e04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a93939393939393908376695d5043362a1d1000000000000000000000000915222e3b4854606a7784919eaab7c2b8ab9e9185786c605346392d3744505b6574808d9aa8b2bdb7ab9f95887b6e6153493f33271b0f030000000000000000000003101d2a3643505d697683909ca5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a89a8d8073655b5044372b1f1205000714202d3a4753606d7a8693a0adb9d1c6cbc6c2c1bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7aa9d9084776a5d5144372a1e1104000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7b5aba3999299a3afb9b8aca0958a7d70655b5041382d1d140a00000000000000000000000000000000000000000000000000000000000000000003090e13191c22282b2e34383a38342e261e150a00000000000008131e2a36424d57606d78828f959ea5adb3b9bab9b4b1b0b1b4b8bab8b3ada69f959083796d60594f43382c20150a000000111d2a3743505c68727879797979797979797979797979797979797979797979797979797979756f65594d4034271b0e00000000000000000000000e1b2734414e5a6774818d9aa7acacaca6998c7f7366594c424d5764717e8a97a2adacacb2a89c8f82766a5f53443a3025190d0100000815212e3b47535f6a6f74747474747474706b60544955616c71747474747474746d675d5145392c201306000000000000000000000000000000000407090a0b0b0b0b0b0b0b0b0b0b0b0b121e2b3845515e6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000004101d2935404b555f6a707d879298a0a8aeb4b9bdc0c1bfbebec1c1bebab8b0aaa29f928c7f726b60554b4035291d120700000000000000000000000000000004101b27323d4653606c7884919da9b2bdbaaea2988c7f72665c5144382c1f160b00000000000000000000000000030f1b27333f49535e696f7c8692979fa7adb3b8bcc0bfbcbbbabbbec2c0bbb9b1aca49f938e81746d62574d42362a1f140900000000000000000000000006121f2b3844505c6675828f9ba8b5bfb4aa998c807366554b4035291d100400000000000000000000000000000000000003101c28343f4a545f69707d8692979fa7adb3b8bcc0c1bfbebec0c0bcb8b4aea8a199938b7f726c61564d41362a20150a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a0a0a0a0a09c908376695d5043362a1d100000000000000000000004101c2834404a54626f7c8996a0acb9beb3a99a8d8174665b5044382b333f4953626f7c8996a1acb9bcb1a7998c8073655b5044372b1f12070000000000000000000003101d2a3643505d6976839098989898989898989898989898989898989898989898989898989184786c605346392d201306000714202d3a4753606d7a8693a0b5c0cbc9c0bab6b4aeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaa9d9084776a5d5144372a1e1104000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bdb5aba39fa3abb5bcb1a79d9083786c6053493f2f261b0b0200000000000000000000000000000000000000000000000000000000000000060b0f151a1e24292d3338393f4446443f3830261c110600000000010d1925303a46535f69737f8c949fa7afb9bcb4aeaca8a4a3a4a7acaeb4bcb9b0a79f958e81746b6054483c31261b0f030000121e2b3845515e6b7884868686868686868686868686868686868686868686868686868686868175685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4b9b2a6998c7f7366594c47535f697683909ca9b3beb8aca0968a7d7063584e4332281e13080000000915222f3c4855626f7c808080808080807d7063564a5764717e80808080808080796d6054473a2d2114070000000000000000000000000000050b10141617171717171717171717171717171e2b3845515e6b7884919eabb7bdb0a3968a7d7063574a3d3024170b0500000000000000000613202c3945515d676f7c869299a2aab2babfbebab8b4b2b1b1b4b8b9bec1bcb4aea49f93877d70675d5145392f24180d010000000000000000000000000000000b161f2b3744505b65717e8b96a1adb9beb3aa9e9184796d6053463d33271c100400000000000000000000000005121f2b3744505b656e7b859298a1a9b1b9bebdb9b7b3afaeaeafb1b6b7bbc2beb6afa59d938b7f72695f53463b31251a0e02000000000000000000000003101c28343f4a5465727e8b98a8b2bdb6a99c908376675d5145392c1f130600000000000000000000000000000000000006121f2b3844505c666e7b859298a1a9b1b9bebfbab8b4b2b1b2b3b7b9bdbfbab2aba49f93887e70685e52463c32261b0f010000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3adadada99c908376695d5043362a1d100000000000000000000006121f2c3844515c6674818d9aa8b2bdb9ada197897c7063544a3f33282d394653606c7884919eabb7bfb7aa9e9184786c605346392f23180c0000000000000000000003101d2a3643505d6976838c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c897c6f6356493c30231609000713202d3a4653606d798699a3afbbc7c0b7afa9a7a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a29d9084776a5d5144372a1e1104000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7bdb5afacafb5bdb8aca0958a7d70655b5041382d1d140a000000000000000000000000000000000000000000000000000000000001070d11171b1f262b2f35383f44464a5053504a42382e23170c0000000005111d2935414c56616e7b86929fa6b0b9b8b0aaa39f9b9896979a9fa2aab0b8b9b1a79d92897c6f63584e43372b1f12060000121e2b3845515e6b78849193939393939393939393939393939393939393939393939393938e8175685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4a54626e7b88949fabbbbeb3a99d9184786c6053463c3120160c020000000b1825313e4b5864717e8b8d8d8d8d8d8c7f7366594e5b6874818d8d8d8d8d8d887b6e6155483b2e22150800000000000000000000000000080f161c20222324242424242424242424242424242b3845515e6b7884919eabb7bdb0a3968a7d7063574a3d30241c16100800000000000005121e2a36424d57606d79849198a2abb4bcc0bbb3adaba8a5a4a5a7abadb3bbc0bfbaafa4999184796d60554b4035291d1004000000000000000000000000000000030f1b27333f4953606d7984919ea9b3beb9ada1968b7e7164594f44382c20150a000000000000000000000003101c28343f4a54606c77828f97a1aab3bbc0bbb2adaba6a3a1a1a2a5a9abb0babec0bbafa59f92867b6e61574d42362a1e12050000000000000000000000000b17232e3b4855616e7b8896a0acb9b9ac9f92867a6d6053473a2d201407000000000000000000000000000000000004101c2934404b55606d78839097a2aab3bbc0bcb4aeaca8a6a4a5a7aaacb2babfbdb5afa49a92867b6e61584e43372b1e13080000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b9b6a99c908376695d5043362a1d10000000000000000000000713202d3a4653606d7985929eabb2b2b2ab9e9185786c605346392d222b3744505b6573808d9aa8b2b2b2aca096897c6f63554b4034291c1004000000000000000000000b1824313e4b5764717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7c6f6256493c2f2316090006131f2c3845515c677986929facb9c5baafa59d9a9595959595959595959595959595959595959595959084776a5d5144372a1e1104000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bbc0bbb9bbc0bcb1a79d9083786c6053493f2f261b0b0200000000000000000000000000000000000000000000000000000003090e13181b22272b31373a41454a5053545c605c544a3f34281c10030000000713202d3946525e6874818e99a3aeb8b9b0a69f98928e8b8a8b8e92989fa6b0b8b9afa59c8f83766a5f53473a2e2115070000121e2b3845515e6b7884919e9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c515c6673808d9aa6b0bbbaada2978b7e72655b5044372b1f1205000000000c1925323f4c5865727f8b989a9a9a9a8d8073675a4f5c6875828f9a9a9a9a95897c6f6256493c2f23160900000000000000000000000008111a21272c2f303131313131313131313131313131313845515e6b7884919eabb7bdb0a3968a7d7063574a3d302c28211a110800000000000714202d3a46525e6973808d96a0aab4bdbdb5afa9a29f9b9897989a9ea1a9afb5bdc0b5aba1968c7f73675d5145392c201408000000000000000000000000000000000b17222d3845515c66727f8c97a2adbabdb2a89d9083776b6155483c32261b0f030000000000000000000006121f2c3844505c66717e8b949fa9b3bcbeb6afa8a19e9996949495989c9fa6adb3bbc1baaea2988e8175695e53463a2d2114080000000000000000000000000614212d3a46535f697784919eaab7baaea399897d7063564a3d2f24180d010000000000000000000000000000000006131f2c3845515c67727f8b95a0a9b3bcbeb6aeaaa29f9b9998989a9ea0a8aeb4bcc0b6aca2988e81756a5f53473a2f24190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000004111d2935414c5664707d8a97a1a5a5a5a5a99a8d8174665b5044382b1c27333f4953626f7c8896a0a5a5a5a5a89a8e8174675c5145382c1f1306000000000000000000000a1723303d4955616c7172727272727272727272727272727272727272727272727272727272726f6a6054473b2e2215080004101c2834404b556c7885929fabb8c5b6a99d938e8888888888888888888888888888888888888888888883776a5d5144372a1e1104000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7c2c7c5c7c4b8aca0958a7d70655b5041382d1d140a0000000000000000000000000000000000000000000000000000040b10141a1d24292d33373c42474c51545b6063666d665c5044382c1f12060000000714212e3a4754616d7a86929fabb4bcb1a79f948f86817e7d7e81868f949fa6b0beb7ab9f94887c6f6255483c2f23180c0000121e2b3845515e6b7884919eabacacacacacacacacacacacacacacacacacacacacacaca89b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c53606d7985919eabb8c0b5ab9f9285796d6053493f33271b0f03000000000d192633404c5966737f8c99a6a7a79a8e8174675b505c6976838f9ca7a7a396897d7063564a3d3023170a0000000000000000000000050f1a232b33383c3d3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e45515e6b7884919eabb7bdb0a3968a7d7063574a3d3c38332c231a100500000003101c28343f4a54616e7b86929fa8b2bcbeb5aba49f97928e8c8b8b8e92979fa4abb5bebdb2a89f9285796d6053473b3025190e0200000000000000000000000000000006111b2834404b54606d7a85929faab4bfb8aca095897d7063584e43372b1f1409000000000000000000000713202d3a4653606d7884919ea6b0bbc0b6aca49f96918c898887888b90949fa2a9b3bcbfb4aa9f93877b6e6154483b3025190d01000000000000000000000005121e2a36424d576774818d9aabb5bfb4ab998d807366554b4135291d1104000000000000000000000000000000000714202d3a4753606d7985929ea7b1bcbeb5aca49d98928e8c8b8b8d91969fa2aab4bcbeb4aa9e93887c6f62554c4135291d110400000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000713202c3945525d6875828e9898989898989897897c7063544a3f33281c222d384754606a778491989898989898989285796d6053473a2d201407000000000000000000000814212d3945505a616465656565656565656565656565656565656565656565656565656565656260584e43372b1f130600000c18232e44515e6b7784919eaab7c1b4a79a8e817c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e6155483b2e22150800000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000000000005101c27333d4854606b7683909ca6b0bbc7d2c8bcb1a79d9083786c6053493f2f261b0b02000000000000000000000000000000000000000000000001070c10161c1f262a2f35383f44464d53555d60666c7076786d6053463a2d2013070000000b1825323e4b5865717e8b98a3aebdb8ab9f958f827b75717071747a828f949facb6bbb0a6998d807366554b4034291c100400121e2b3845515e6b7884919eabb7b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b5a89b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594d5764717d8a97a1adb9bbafa3998d8073675d5141382d22170b00000000010d1a2734404d5a6773808d9aa6b3a89b8e8275685b515d6a7784909daab0a4978a7d7164574a3e3124170b00000000000000000000000b16212b353d44484a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a515e6b7884919eabb7bdb0a3968a7d7063574a4a48443e352c21160b00000006121f2b3844505c6673808d98a3aebac0b6aca499938c85817f7e7e81858c9399a4acb6c0baada2978b7e7265564c41362a1e1105000000000000000000000000000000000c18232e3945515d6773808d98a3aebabcb1a79c8f82766a5f53473b31251a0e01000000000000000005111d2935414c5664717e8a96a1adb8c2bbafa49a938c84807d7b7b7c7e838a9297a2aab4bfbbafa4998c807366564c41362a1e11050000000000000000000000020e1a26313e4a5764717d8a99a3afbbb6a99d908376675d5145392c20130600000000000000000000000000000005111e2a36414c5665717e8b97a1adb9c2b8aca39b928d86817f7e7f80848b9298a2aab4bfbcafa59b8e8174675d5145392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000714212d3a4754606d7a868c8c8c8c8c8c8c8c8c85786d6053463a2d22171b2b37434e586673808c8c8c8c8c8c8c8c8c8a7d7164574a3e3124170b0000000000000000000005111d28333e48505557595959595959595959595959595959595959595959595959595959595956544e463d32271b0f030000071c2936424f5c6975828f9ca8b5c1b4a79b8e81746f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e695f53463a2d21140700000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000000000b16212c38444f5963707d89949fabb7c4d0c4b8aca0958a7d70655b5041382d1d140a0000000000000000000000000000000000000000000003090e12181d1f272c31363a4045495053575f62676d72787d827f7265584b3f3225180c000004101c2834404b556875828e9baab4beb3a99d9083796e69656364686e78828f9aa4afbbb6aa9d908377675c5145382c1f130600121e2b3845515e6b7884919eabb7c4c6ccc7c3c2bbbbbbbbbbbbbbbbbbbbbbbbbbbbb5a89b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659535e6976828f9ca9b3beb9ac9f92867b6e61554b402f261b110600000000010e1b2834414e5b6774818e9aa7b4a99c8f8276695c515e6b7884919eabb1a5988b7e7265584b3f3225180c0000000000000000000004101c27333d474f54565757575757575757575757575757575757575e6b7884919eabb7bdb0a3968a7d7063575757554f473e33281c100400000713202d3a4653606d7985929eaab4bfbbafa49a9387807a7572717274798087939aa4afbbbeb3a99c908376685e5246392d2014070000000000000000000000000000000007121d2935414c55616e7a86929fabb5c0b7ab9f94887c6f62574d42362a1e130800000000000000000713202d3946525d6876828f9ca8b2bdbbb0a69f9388807973706e6e6f72767d859298a2aebac0b5ab9d908477685e5246392d2013070000000000000000000000000914212d3a4754606d7a86929facb9b9ac9f92867a6d6054473a2d2114080000000000000000000000000000000714202d3946525e687683909ca9b3bebbb0a69b918b807a7573717274787e869298a2aebac1b8ac9f92867a6d6054473a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000815222e3b4855616e7b7f7f7f7f7f7f7f7f7f7f7e70665c5044382b1c111b27323c4854616e7b7f7f7f7f7f7f7f7f7f7f7d7063564a3d3023170a00000000000000000000000c17222c363e45494b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4947433d342b20160a0000000d1a2733404d5a6673808d99abb5c0b7aa9d918477696262626262626262626262626262626262626262615f574d42362a1e120500000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000000000000000005101c27333d4854606b7683909ca9b6c3cfc3b7aa9d9083786c6053493f2f261b0b020000000000000000000000000000000000000000040b10141a1d24292c33383b42464b51535b6063696e747a7f848a8b7f7265584c3f3225190c000006131f2c3845515c677784919eaab7b9ada297897c6f675e5757565e666e7b87939facb9b9ac9f9286796d6053473a2d20140700121e2b3845515e6b7884919eabb7c4cac2bbb7b5aeaeaeaeaeaeaeaeaeaeaeaeaeaeaea89b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665954616e7b87939facb9bcb1a79b8e8175695e5243392f1d140a0000000000020f1c2835424f5b6875828e9ba8b5a99d9083766a5d505b657885929fabb2a5998c7f7266594c3f3326190c000000000000000000000714202c38444f596063646464646464646464646464646464646464646b7884919eabb7bdb0a3968a7d706464646361594f44382c20140700000a1623303d495663707c8997a1adbcc0b6ac9f93887e736d67656465676d737e88939facb6c0b9ac9f93877a6e6154473b2e211408000000000000000000000000000002080e1119242f3a46525e6874818e99a4afbbbbb0a69b8e8175695e53463a2f24190d00000000000000000714212e3a4754616d7a86929facb9c4b7ab9f948b7f736d6663616162656c707c86929facb6c0b8aca095877a6d6154473a2e2114070000000000000000000000000713202c3945525d687683909da9b6bbafa3998a7d7063574a3d2f24190d0100000000000000000000000000000814212e3b4754616e7a86939facb9c5b7aa9f948b7e736d68666565666c717d86929fa8b2bdbaaea3988a7d7164574a3e2e23180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000714212d3a46535f696e72727272727272727272706c61544a3f34281c0a15212d3a46535e696e72727272727272727272706b6054483c2f221609000000000000000000000006101a242c33393d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3c3b37322b22190f040000000b1724313e4a5764717d8a99a3afbbb8aca095887b6e615755555555555555555555555555555555555555534d453b31261a0e0200000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000000000000000b16212c38444f5963707d8996a3afbcc9bdb0a3978a7d70655b5041382d1d140a00000000000000000000000000000000000001070c10161c1f252a2f35393d44484d53555d60656c70767b80858b91968b7f7265584c3f3225190c00000713202d3a4653606d7986939facb9b8ab9e9285796c60554d4a4c545f697783909daab7bbafa399887b6f6255483c2f22150900121e2b3845515e6b7884919eabb7c4c2b8b0aaa9a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a29b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366595b6673808c99a4afbbb8ab9f95897c6f62574d4231281d0b02000000000003101c2936434f5c6976828f9ca9b5aa9e9184776b5e53606c7986939facb3a6998d8073665a4d4033271a0d000000000000000000000916222f3c4854606b7071717171717171717171717171717171717171717884919eabb7bdb0a3968a7d71717171706b6155483c2f23160900000d192633404c5966737f8c99a9b3bebbafa49a8d81746c605d5558555c606c74818d9aa4afbbbbafa49a8a7e7164574b3e3124180600000000000000000000000002080d14191e20232a36414c56616e7b87939facb9c2b9ac9f92867b6e61554c4135291c1106000000000000000a1724313d4a5764707d8a99a3afbbbfb4aa9c8f82766d605c545554555a616a73808c9aa4afbbbcb1a7968a7d7063574a3d3024170a00000000000000000000000004111d2935414c566673808c99aab4beb5ab9a8d807367564c4135291d110400000000000000000000000000000b1724313e4a5764717e8a99a4afbbbeb3a99c8f82766c605d5658545b606b727f8b96a1adb9bfb4aa9b8e817468544b4034281c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000005121e2a36424d575f616565656565656565656564615a5042382e23170b121e2a36424d575e61656565656565656565656360594f44382c20140700000000000000000000000008121a22282d303132323232323232323232323232323232323232323232323232323232322f2e2b2720191007000000000714212d3a4754606d7a86929facb9bcb1a79a8d8074695f5349484848484848484848484848484848484846423b332a1f14090000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000000000005121f2b3744505b65717d8a97a4b0bdcabeb1a4988b7e71665c5144392e23180c0000000000000000000000000000000000030b12181d1f272c3136394045474f54575f61676d72787d82878d92989e988b7f7265584c3f3225190c00000815222e3b4855616e7b889aa4afbbb6aa9d908377665b50433d424d576875828f9ba8b5c0b5ab96897d7063564a3d3023170a00121e2b3845515e6b7884919eabb7c4bbb0a69e9c95959595959595959595959595959595958e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659606c7884919eabb5bdb2a89d9083766a6054453b301f160c00000000000004101d2a3743505d6a7683909da9b6ab9e9285786b5554606d7a8799a4afb4a79a8e8174675b4e4134281b0e010000000000000000000a1723303d4a5663707d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7e85929eabb8c0b3a6998d807d7d7d7d7d7063574a3d3024170a00030f1c2936424f5c6975828f9ca8b1b1b1ac9f93877b6e615a514b4b4b515a616e7b87939facb9c0b6ac9a8d8074675a4d412e23170b0000000000000000000000040c13191f252a2d2e34383b47535f6975828e9ba6b0bbbbafa3998d8073675d5145382e23170c000000000000000d1a2633404d596673808c99abb5b1b1aea3988a7d70635b514b4848495058616e7a87939facb9beb2a5988b7f7265584c3f3225190c000000000000000000000000010d19242f3c4956636f7c8998a2aebab6aa9d908377685d5245392c20130700000000000000000000000000000e1a2734414d5a6774808d9aabb5c0b9ada297897c6f635a524c4b4a5059606d7984919eabb8c3b7aa9d908477665c5145382c1f1306000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000020e1a26313b454d535559595959595959595959575550473e30261c11060e1a25313b454d53545959595959595959595956544f473d33271c1004000000000000000000000000000810171d212324262626262626262626262626262626262626262626262626262626262623221f1b160f0700000000000713202c3945525d687683909caab4bfb9ac9f92877b6e655b50443d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3b3a36312a21180e030000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000000000000030f1b27333f4953606c7883909daab7c3d0c4b7ab9e9184796d60544a4034281c1106000000000000000000000000000000070d151d24292c32383b42464b5153596063696e747a7f848a8f939a9fa2aa988b7f7265584c3f3225190c00000915222f3c4855626f7b8895acb6c0b6a99c90837669544a3f31414e5b6874818e9ba7b4bdb0a4978a7d7164574a3e3124170b00121e2b3845515e6b7884919eabb7c4b7aa9e948f8888888888888888888888888888888888888175685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665663707d8a96a1adbdb9ada1968a7e7164584e4333291f0d0400000000000004111e2b3744515e6a7784919daab7ac9f928679675d54616e7b8794a1b5b5a89b8e8275685b4f4235281c0f02000000000000000000111e2b3744515e6a77848a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a9297a1adb9c1b4a89c928d8a8a8a8a84786b5e5145382b1e1200030f1b27333f49536a7784919da4a4a4a4a49d908477695f5345403e4046535e697783909daab7c2b6a99c8f837669544a3f34281c1003000000000000000000080e161e25293036393b404546484d57626f7c89949fabb7c0b5ab9f92857a6d60544a3f34281c10030000000000000f1b2835424e5b6875818e9ba4a4a4a4a49f92867a6d605347403b3b3e46525e687784919daab7c0b3a6998d8073665a4d4033271a0d000000000000000000000000000813202d3a4653606d7985929fabb8b9ac9f93867a6d6054473a2d2114080000000000000000000000000000101c2936434f5c6976828f9ca9b5c2b8ab9e9285796c605346413e3f44505c6674818e9ba7b4c1b9ac9f9286796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000009141f29333b4246484c4c4c4c4c4c4c4c4c4c4a49443e352c1e140a0009141f29333b4246484c4c4c4c4c4c4c4c4c4c4a48443d352b21160b000000000000000000000000000000060c1114171819191919191919191919191919191919191919191919191919191919191615130f0a0400000000000004111d2935414c5665727e8b98a2aebabbaea3998f82776c60594f463d342f2f2f2f2f2f2f2f2f2f2f2f2e2d2a261f180f06000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000000000000000005121f2b3744505b65717d8a95a0acb8c5d1c5b9aca1968b7e71665c5144382e23170c00000000000000000000000000000710191f272f35383d44484d53555d60656b70757b80858b91969c9fa4acaea5988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d50432d414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c2b5a99c8f827c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e6154483b2e21150800000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665e6875828f9ba8b2bdb4aa9e9184796d6053463d3220170d0000000000000003101c28343f4a546b7885919eabb8aea399867a6d6055626f7b8895a2aeb5a99c8f8276695c4f4336291c0600000000000000000000111e2b3744515e6a77849197979797979797979797979797979797979797979ea1a9b3bec5b9aea49c999797979184786b5e5145382b1e120005121f2b3744505b65798592979797979797978e817468574d42352f36424d576774808d9aa7b3c0b8ab9e918578665c5044382b1f12060000000000000000081119202830353b4146474b5153555657606a76828f9ca7b1bcbaaea2988c7f72665c5044382c1f160a000000000000101d2a3643505d6976839097979797979797908376675d5145392e2e36414c56697683909ca9b6c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000006121f2c3844505c6675828f9ca8b5bbafa4998a7d7064574a3d3025190d0100000000000000000000000000111e2b3744515e6a7784919daab7c2b5a99c8f8276665b5044382f343f4a5465727f8c98a5b2bfbbaea399877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000030d18212931363a3b3f3f3f3f3f3f3f3f3f3f3d3c39332c231a0c0200030d17212931363a3b3f3f3f3f3f3f3f3f3f3f3d3c38332b231a0f05000000000000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c090806030000000000000000010d19242f3a4754606d7a86929faab4bfb5ab9f948c7f726b61584e463c342b2222222222222222222222211e1a140e0600000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000000000613202d394653606c7883909da7b1bcc8d4c9bdb2a89e9184796d60544a3f34281c1106000000000000000000000000040f19222b31394045474f54575e61676d72777d82878d92989da0a8acafb6b2a5988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e82756f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e695e52463a2d20140700000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366616e7a86929facb9baaea2988c7f72665c5044382c1f12050000000000000006121f2c3844505c667985929facb8b4ab94877a6e6156636f7c8996a2afb6aa9d9083776a5d50442d22170b00000000000000000000111e2b3744515e6a7784919da4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4abadb3bbc5cac0b6aea8a6a4a49e9184786b5e5145382b1e12000613202d394653606c79878b8b8b8b8b8b8b8b8b8073675a4d403125313f4c5965727f8c98a5b2bfb9ac9f9386796d6053463a2d2013070000000000000008121a232b323a41464d5254545c606263646464707d8995a0acb8beb4aa9e9184796d6053463d32271b0f010000000000111d2a3744505d6a77838b8b8b8b8b8b8b8b8b817568554b4035292b3844505b667683909da9b6c1b4a79a8e8174675b4e4134281b0e0000000000000000000000000003101c28343f4a5465727f8b98a5b2c0b5ab9a8d807467564c41362a1d110500000000000000000000000000121f2c3845525f6b7885929eabb8c1b4a79b8e817468544a3f33282e3e4a5764717d8a97a4b0bdbfb5ab95887c6f6255483c2f221509000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000060f181f262a2d2e3232323232323232323231302d28221a1108000000050f171f252a2d2e32323232323232323232302f2c27211a1108000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000813202c3945515d6774818d98a2aebabdb0a69f92877d706a60584e463d342b231a151515151515151514120e09030000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000000000000000814202d39444f5964707d8a95a0acb9c3cecccec4b9aca1968b7e71665c5044382e23170c0000000000000000000000000a15202b343d434b5153596063696e73797e84898f93999fa2aaacb2b9b3adaba7988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e82756862626262626262626262626262626262615e574d42362a1e120500000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736666727f8c99a3aebbb6ac9f92867a6d60544a3f34281c1003000000000000000713202d3a4653606d798698a2aebaaea195887b6e625763707d8a96a3b0b7aa9e9184776b5e493f33271b0f03000000000000000000111e2b3744515e6a7784919daab0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b8b9bec5cdd1c8c0b9b4b3b0ab9e9184786b5e5145382b1e12000613202d394653606c787e7e7e7e7e7e7e7e7e7e7c6f6255493c2f25313e4b5864717e8b97a4b1bebbafa499877a6d6154473a2e21140700000000000007101a242c353d444c52565e6165666d6e70717170707783909daab7c3b9ada1968a7e7164584e43382b1d130700000000000a1724313d4a5764707d7e7e7e7e7e7e7e7e7e7d6f6356493c2f2a333b4653606c7985929fabb8c0b3a6998d8073665a4d4033271a0d0000000000000000000000000004101c2834404a5466727f8c99a5b2bfb7aa9d908377685e5246392d20130700000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e412d22303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000060d141a1e2122262626262626262626262423201c1710080000000000050d141a1e2121262626262626262626262322201c160f080000000000000000000004080a0a131313131313131313100f0d0a050000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c55616e7b86929fa8b2bdbbafa39992867c6f6a5f584e463d352c241b1209090909090807050200000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000005101a23303c4955616c7783909da7b1bcc4c0bfc0c4bdb2a89e9184786d60544a3f34281c110600000000000000000000030f1b27323d464e555d60656b70757b80858b91959c9fa4abaeb3b5aeaca9a19e9a958b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b55555555555555555555555555555554524d453b30251a0e0200000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73666b7784919eabb5bbafa49a8d8174685d5242382e23170c00000000000000000714212e3a4754616d7a8794aab4bfafa295897c6f625864717e8b97a4b1b8ab9e928578655b5044372b1f1205000000000000000000111e2b3744515e6a7784919daab7bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdc5c6c9cfd6dad1cac4c1bfb7ab9e9184786b5e5145382b1e120006121f2b3844505b666c717171717171717171716f6a5f53473b2e25313e4b5864717e8b97a4b1bec0b5ab94877b6e6154483b2e2115080000000000040d19232c363e474f565e61686e7276797b7d7d7e7d7c7b7e8a97a4b1bdbdb2a89d9083766a6054473a2f24180d01000000000a1623303c4955616c707171717171717171716f6b6054483b2f323b45505a63707d8998a2aebac0b5ab988c7f7265594c3f3226190c0000000000000000000000000006121f2c3844515c6676828f9ca9b5c2b9ac9f93867a6d6154473a2e21140800000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000003090e12141519191919191919191919171614100b050000000000000003090e12141519191919191919191919171614100b05000000000000000000050b101416172020202020202020201d1c1a16110a030000000000000000000000000000000000000000000000000000000000000000000000010d19242f3a46525e6973808c96a0abb5bfb5aba29892857c6f6a60584f473e362d241c130a0200000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000000000b16212c38444f5964707d8a95a0acb9bfb8b4b2b4b8bfb9aca0968b7e71665c5044382e23170c0000000000000000000006131f2b37434e5860676d71777d82878d92979da0a7acafb5b1ababa39f9b97928d89837d6f6356493c3023160900000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f48484848484848484848484848484846423b33291f14090000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366707c8996a0acbdb9ac9f93877b6e62564c4130261c110600000000000000000815222e3b4855616e7b8894a1aebbb0a396897d70635865727f8b98a5b2b9ac9f9286796c605346392d201306000000000000000000111e2b3744515e6a7784919daab7c4c5beb9b8b0b0b0b0b0b0b0b0b0b0b0b0b8b9bec5cdd1c8bfb9b4b3b0ab9e9184786b5e5145382b1e1200030f1c28333f4a545b6064646464646464646464625f584e43372b25313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000000010c161f2b353e48505960686d747b7f838688898a8a8a898785929fabb8c5c4b8ab9f95897c6f62554b4135291d1104000000000814202d3944505a61646464646464646464646360594f4338313a444d57616c76828f9caab4bebbafa3998a7d7064574a3d3124170a000000000000000000000000000713202d3a4653606d7985929facb8c5bbafa49a8a7d7164574a3e3025190d01000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000020507080c0c0c0c0c0c0c0c0c0c0a0a08040000000000000000000000020507080c0c0c0c0c0c0c0c0c0c0a090704000000000000000000000810171c2023242d2d2d2d2d2d2d2d2d2a2926221c150d04000000000000000000000000000000000000000000000000000000000000000000000008131e2a36424d56606d79849199a3aebbbdb4aaa29792857c6f6a605950483f362d251c140a02000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000000000004101c27333c4855616b7783909da7b1bcb5ada7a5a7adb5bdb2a89e9184786d60544a3f34281c11060000000000000000000815222e3b4754606a6f797e83898f92999fa2a9acb1b2adaba79f9d99928f8a85807c776f6b6054483b2f22150900000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423c3c3c3c3c3c3c3c3c3c3c3c3c3b3a36302921170d020000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736875818e9ba8b2bcb1a79c8f82756a5f53443a301e150a0000000000000000000916222f3c4955626f7c8895a2afbbb0a4978a7d71645966737f8c99a6b2bbafa399877a6d6054473a2d211407000000000000000000111e2b3744515e6a7784919daab7c4bbb3adaba3a3a3a3a3a3a3a3a3a3a3a3abadb3bbc5cabfb6aea8a6a3a39e9184786b5e5145382b1e1200000b17222d38424a50535858585858585858585855534e463c322625313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f2215080000000007131d28313d47505a616b707a81868c9092989697979796979297a2adbac6c8bcb1a79b8e8175675d5145392c2014090000000004101c28333e4850555758585858585858585856544f463d333b434c565f69717e8a949fabbcc5b9ac9f92867a6d6054473a2d21140700000000000000000000000000091623303c4956636f7c8998a2aebac6c0b6ac9a8d817467564c41362a1e1105000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a22282d30313939393939393939393635322d271f160d0300000000000000000000000000000000000000000000000000000000000000000000010e1925303b45515d676f7c87929fa5afb8bcb3a9a19792857c706b615a50483f372e261c140b020000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000714202c38444f5963707d8a959fabb9b9ada39c999ca3adb8b9aca0968b7e71665c5044382e23170c0000000000000000000916232f3c4956626f7c858b90959b9fa3abadb3aeaca8a19e9995908b86827d79746f6a6360594f44382c20130700000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352f2f2f2f2f2f2f2f2f2f2f2f2e2d2a251f170f05000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f75757a86929facb8b8aca095897d7063574e4232281e0c030000000000000000000a1623303d495663707c8996a3afbcb1a5988b7e72655a6773808d9aa6b3c0b5ab94877b6e6154483b2e211508000000000000000000111e2b3744515e6a7784919daab7beb3a9a19e9796969696969696969696969ea1a9b3bec4b9aea49c999696969184786b5e5145382b1e12000006111c262f383f44464b4b4b4b4b4b4b4b4b4b4947433c342a2025313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000000010d18242f3a434f59616c717d858d92999c9fa3aaa4a4a3a9a29fa2a9b3becacdc2b8ac9f92867a6d6054473b30251a0e02000000000b17222c363e44494a4b4b4b4b4b4b4b4b4b4948433d343d454d565e686e7b85929fa6b0bbbeb3a99d908376685d5245392c20130700000000000000000000000004101c2934404b5566737f8c99aab4bfcac4b7aa9d918477685e5246392d201407000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000020608080b0d0f0f0f0f0e0d0b0807050200000000000000000000000000000000000000000000000000000005101a232c33393c3d46464646464646464643423e3831281f150a000000000000000000000000000000000000000000000000000000000000000000000009141f2935404b55606a727f8c939ea6b0babbb3a9a19792867d716c625a514940382e261d140b0100000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000050f19232f3c4855616b7683909da7b1bcb1a79c918c919ca6b0bcb2a89e9184786d60544a3f34281c110600000000000000000a1724313d4a5764707d8a979da0a7acafafacaaa29f9b96918d88837f7a75706d66626058544f473d32271b0f0300000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423528222222222222222222222221201e1a140d0500000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7aa9d90838282829098a3aebab3a99d9184776b6054453c3120160c000000000000000000000a1724313d4a5764707d8a97a3b0bdb2a5998c7f72665b6774818e9aa7b4bbaea295887c6f6255483c2f221509000000000000000000111e2b3744515e6a7784919dabb5b9ada197928a8a8a8a8a8a8a8a8a8a8a8a9297a1adb9c1b4a89c928c8a8a8a8a84786b5e5145382b1e120000000a141d262d3338393e3e3e3e3e3e3e3e3e3e3c3b37322a221825313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000004111d2935414b55606b717e8792979fa3abacaeb4b0b1b0b3adabadb3bbc5d0d3c7baaea2988b7e7164574d42362a1e12050000000005101a232c33393c3d3e3e3e3e3e3e3e3e3e3c3b38343f464f575e686d7a839098a2aeb8c2b9ada1978b7f7265564c4135291d110400000000000000000000000006131f2c3845515c6776838f9ca9b6c2d0c5b8aca095877a6e6154473b2e211409000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000205090f121415181a1b1c1c1c1b19171414110e0804000000000000000000000000000000000000000000000000000b17222c363e44494a535353535353535353504e4a433a31271c110500000000000000000000000000000000000000000000000000000000000000000000020d18242f39434e58606c77818e949fa8b1b9bbb3a9a29892867e716c635b524a40382e261d140a01000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000000000b16212c38444f5963707d89959fabb9b8aca0958c7f8c949fabb7b9aca0968b7e71665c5044382e23170b00000000000000000a1724313d4a5764707d8a97a9acb1b6aca49f9c98928e8984807b77726d6864605c54544e48443d352b21160b0000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c151515151515151515151514120e09020000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8aca095908e8e90949faab4b9ada1978b7e7165594f44332a200e04000000000000000000000b1825313e4b5864717e8b97a4b1beb3a6998d8073665b6875828e9ba8b5bcafa396897c706356493d3023160a0000000000000000000f1c2936424f5c6975828f99a3afb8ab9e92857e7d7d7d7d7d7d7d7d7d7d7d85929eabb8bfb3a6998c807d7d7d7d7d706356493d3023160a000000020b141c22282b2d31313131313131313235362e2d2a251e1625313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f2215080000000613202c3945515d676f7d879299a1a9aeb4b9babcb8b6b4b3b4b5b8babec5cad0cabfb4aa9c8f8276695e52463a2d201406000000000008111a22282d30313131313131313131313030394045505960696e7a839095a0aab3bebcb1a79e92857a6d6054473a3024190d010000000000000000000000000714202d3a4753606d7986929facb9c5d2c8bcb1a7978a7e7164574b3e30251a0e020000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000002090e12151a1f212225272829292828262421201e1914100c070100000000000000000000000000000000000000000004101c28333e485055576060606060606060605d5a544c43382d22160a000000000000000000000000000000000000000000000000000000000000000000000007121d28313d44505b656d79829095a0a7b1b9bbb3aaa29892877e726d635c524a40382e261c130a000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000004101c27333c4854606b7683909da7b1bcb2a89d90837783909ca8b2bdb2a89e9184786d60544a3f34281c1106000000000000000a1724313d4a5764707d8a97a3b0bbafa49a938f8b86817d78736e6a65615e5653514b47433d38322b23190f040000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c1b1b1b1b1b1a1916130e0807050200000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bcb1a7a09d9b9b9c9fa6b0bcb8ab9e9285796d6053473d3320180e00000000000000000000000c1925323f4c5865727f8b98a5b2beb4a79a8d8174675c6976828f9ca9b5bdb0a3978a7d7064574a3d3124170a0000000000000000000915222f3c4855626f7c87929faab4ada1978b7e717070707070707070707884919eabb7bdb0a3968a7d70707070706b6054483b2f22160900000000020b141b22272b2d312d3337393b3d3f41433a393630282025313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000005111e2a36424d56606d79849199a3abb3babfbbb9b1abaaa8a6a7a9abaeb3babec5cec6b9ac9f93867b6e6154483b2d22170b0000000000000810171c20232425252525252525252b333b434b515a626b6f7b8390959fa7b1bcbfb4aaa0958c7f72675d514539281e1308000000000000000000000000000a1623303d495663707d8998a3aebac7d3cec1b4a79a8e817467574d42362a1e12050000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000001070d141a1e20262b2e2f3133353536353533312e2d2a251f1d18120b0600000000000000000000000000000000000000000814202d3944505a61646c6c6c6c6c6c6c6c6c69665e544a3e32261a0d0000000000000000000000000000000000000000000000000000000000000000000000010c161f27333f49535c676d7a839195a0a7b1b9bcb4aaa399938b7f736e645c524a40382e251c12080000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000000713202c38444f5963707d89959fabb9b9ada1968a7e717d8a96a0acb9b9aca0968b7e71665c5044382e23170b000000000000000a1724313d4a5764707d8a97a3b0b9ac9f9387827e7a75706c66625f5854524c4645403937322c2721191107000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235282828282828282625231f19120a010000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c3b9b1acaaa8a8a9abb0b8c0b3a6998d8073675d5145382c1f130600000000000000000000000c1926333f4c5966727f8c99a5b2bfb4a89b8e8175685d6a7783909daab6beb1a4978b7e7164584b3e3125180b0000000000000000000815212e3a47535f6a74818e98a2aeb3a99e9184796d636363636363636b7884919eabb7bdb0a3968a7d706363636360594f44382c201307000000000a141d262d3337393d3f3f4446484a4c4e504746413a322825323f4b5865727e8b98a5b1bebbaea194887b6e6155483b2e22150800000714202d3a46525e6974818e96a0abb5bdbeb6afaca79f9d9b9a9a9c9fa2aaaeb3bcc5c7bbafa4998b7e716553493f33271b0f03000000000000050b1014161718181818161d2429353d454d555c606c717d8590959fa7b1b9c0baaea3989083786d60554b413529160c0200000000000000000000000004111d2935404b556673808c99aab4bfcbd7d1c4b7aa9e918477695e52463a2d2014070000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000040c12181f252a2d31373a3b3e404242424241403e3b3936302c29241d17110a020000000000000000000000000000000000000a1623303c4955616c707979797979797979797670665a4e4235291c0f000000000000000000000000000000000000000000000000000000000000000000000000040d17222d38414b555d686e7a839095a0a7b0b8bcb4aba49f918c80736e645c524a40372e241a100700000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000000040f19232f3c4854606b7683909ca7b1bcb4aa9e9184796d7884919ea9b3bdb2a89e9184786d60544a3f34281c11060000000000000a1724313d4a5764707d8a97a3b0bbafa49a90837f7a75706c65615f5753514b48433d3a36302b2620181006000000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42353535353535353533322f2a241c130a0000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0cbc3bcb8b7b5b5b6b7bcc2bbaea194887b6e61554b4035291d100400000000000000000000000d1a2733404d5a6673808d99a6b2b2b2a89c8f8275695e6b7784919eaab2b2b2a5988c7f7265594c3f3226190c00000000000000000006121f2b37434e58616e7a85929fa8b2ada1968c7f73685e575757575e6b7884919eabb7bdb0a3968a7d7063575756544f473d33271c100400000006111b262f383f44464a4c4950535557595b5d54524c443a3025333f4c5966727f8c99a5b2bfbfb4aa94877a6e6154473b2e21140800030f1b27333f4953616e7b86929fa8b2bdc0b6aca49f9a95908e8d8d8f92989fa2aab3bcc5c0b5ab9b8e8275655b5044372b1f1205000000000000000004080a0a0b0b0f171f282f353f474f575e676d747e879197a0a7b1b9bfb6aea49f92867c6f665c50433a2f241804000000000000000000000000000613202c3945515d677683909da9b6c3d1dcd2c5b8aca096877b6e6154483b2e2115090000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000060d161d242930363a3c4347484b4d4e4f4f4f4e4c4a4746413b39352f27221b140b0500000000000000000000000000000000000a1724313d4a5764707d8686868686868686868276695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000000000000006111b262f39434c565e686e7a8390959fa6b0b8bdb5afa39c928d80746e645c52493f362c22190e04000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000b16212c38444f5963707d89949fabb9baaea2988c7f7266727f8b97a2adbab9aca0968b7e71665c5044382e23170b0000000000000a1724313d4a5764707d8a97a3b0bfb6ac9f95908b86817d78736e6964605d55544f4746423b37322a22180e040000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f424242424242424242403f3b352e251c120700000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c3bab2acaaa8a8a9abb1b9beb1a4988b7e71655b5044372b1f150a00000000000000000000000e1b2734414e5a6774818d9aa5a5a5a5a59c90837669556b7885929ea5a5a5a5a5998c807366594d4033261a0d000000000000000000030f1b26313c46525e68737f8c96a1acb2a89f92867a6e61584e4a515e6b7884919eabb7bdb0a3968a7d7063574a4948443d352b21160b000000000b17222d38414950535759535b606163656869615e564c41362d36424d576774818e9aa7b4c1baaea398877a6d6054473a2d2114070005121f2b3744505b6573808c99a3afbac4bbafa49a938d888381808182858b9298a2aab3bec5b8ab9e9285786c605346392d2013060000000000000000000000000710192129313a4045515960696e79818b9299a1a9b1b9bfbbaea49d928b7f726a5f544a3f31281d1307000000000000000000000000000714202d3a4753606d7a86929facb9c5d2dfd4c8bdb2a8978a7e7164574b3e31251a0e0200000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000060f181f282f353b4246484e5355585a5b5c5c5b5b595754524c47454039332d261d170e06000000000000000000000000000000000a1724313d4a5764707d8a93939393939393908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000000a141d27303a444d565e686d7a8390949ea6afb7c0bbada49c928d80746e635b51483e342b20160c020000000000000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f3225190c0000000000000000000000000000000000000000000000000000000000000000000000000000030a0f16222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000030f1b27323b4854606b7683909ca6b0bcb5ab9f92857a6d606d7985929fabb5bdb2a89e9184786d60544a3f34281c110600000000000a1724313d4a5764707d8a97a3aeb4b9b1a79f9d98928e8984807b76716d6763605954524d47433c342a20150a0000000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4e4e4e4e4e4e4e4e4e4d4b4740372e24190e02000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bdb2a8a09d9c9c9d9fa7b1bcb7aa9d9184786c6053463c32261b0f02000000000000000000000f1b2835424e5b6875818e989898989898989184776a5d67798692989898989898988d8074675a4d4134271a0e000000000000000000000a15202a36414c56606d7984919ea7b1aea2988d81746a5f5347515e6b7884919eabb7bdb0a3968a7d7063574a3d3b38332b23190f05000000030f1b27333f49535b60646668656c6e707274766d685e52463d393c46525e697783909daab6c3b8ac9f928579675d5145392c201306000613202d394653606c7885919eabb5c0baafa59f9388807b7775737476797e869298a2aebac5b9ada197887c6f6255493c2f2216090000000000000000000000081119222a333b434b515b636b707b838e939fa3abb3bbbdb5aea49c928d80736d62584e42382e1f160c01000000000000000000000000000a1724303d4a5763707d8a99a3afbbc7d3d2d3cec1b4a79b8e817468574d42362a1e120500000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000061018212a313940454d5254585f62646668686968686664615e5653514b443f382f2920180f060000000000000000000000000000000a1724313d4a5764707d8a979f9f9f9f9f9c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000000000000000020b151e28323b444d565e686d7a828f949ea5aeb6bfb6aea49d928d80736d635a50463d32281e13080000000000000e1b2734414e5a6774818d9aa7b4bfb2a5998c7f7266594c3f3326190c00000000000000000000000000000000000000000000000000000000000000000000000000060e151b1f222f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000713202c38444f5963707d89949fabb8bbafa3998d8073685d6773808d99a3afbbb8aca0968b7e71665c5044382e23170b00000000000a1724313d4a5764707d8a979fa3aaadb2b1abaaa29f9b96918c87827e79746f6b66615e56534e463c32261b0f0300000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5b5b5b5b5b5b5b5b5b5b5957524940352a1f1307000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8aca096918f8f90959faab4b8aca0958a7d7063584e43372b1f1409000000000000000000000f1c2936424f5c6975828c8c8c8c8c8c8c8c8c84786b606d7a868c8c8c8c8c8c8c8c8c8175685b4e4235281b0f00000000000000000000040d1925303b45515c67717e8a959fabb4aa9f92877c6e62594f515e6b7884919eabb7bdb0a3968a7d7063574a3d302c27211911070000000005121f2b3744505b656c70727577797b7d7f81837a6d61594f4746474d57616e7b87939facb9c4b7aa9d9184776a554c4135291d1104000915222f3c4855626f7b8897a1adbdc7b6a99e938b7e746e69686767666d727c86929fa9b3bebeb3a9988b7e7165584b3e3225180b0000000000000000000008111a232b343c454d555d606d727d8590959da5aeb4bdbbb3aba39f928c80776c605b51463c30261c0d040000000000000000000000000004111d2935414c566773808d9aabb5c0cac6c5c6cac4b7ab9e918478695e53463a2d21140700000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000050e18222a333c434b51575e61666a6e7173757575757473716e6865605d555049413a322921180e0500000000000000000000000000000a1724313d4a5764707d8a97a3acacaca99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000000000030c162029323b444c565e686d79828e939da4aeb6bfb6aea49c928c7f726c61584e443a3024190c0300000000000e1b2734414e5a6774818d9aa7b4bfb3a6998c807366594d4033261a0904000000000000000000000000000000000000000000000000000000000000000000000006101820262b2e2f3c4955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000040f19222f3b4854606b76828f9ca6b0bbb9ac9f92867b6e6156616e7b86929facb9bdb2a89d9184786d60544a3f34281c1106000000000a1723303d4a5663707d888e92989ea1a8abb0b4aeaca8a19e9a938f8b85817c77726e69625f584e43372b1f120600000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e827568686868686868686868686866635c52473b2f23160a000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7aa9d91848282839098a3aebab1a79c8f82766a5f53473b30251a0e010000000000000000000b1724313e4a5764717e7f7f7f7f7f7f7f7f7f7f7265606d797f7f7f7f7f7f7f7f7f7f7d7064574a3d3124170a000000000000000000000008141e2934404b55606c7883909da5afafa3998f82756b60544a5e6b7884919eabb7bdb0a3968a7d7063574a3d30241c160f0700000000000613202d394653606c777e7f818385888a8c8e8d80746b6059545354575f6973808c9aa4afbbc2b5a89c8f8275695c4f422f24190d01000b1825323e4b5865717e8b98a9b3bebeb3a99b8e81746c615f575a545c606a717e8b97a1adb9c0b3a79a8d8074675a4d4134271a0700000000000000000007101a232c353d464e575e676d757f8792979fa7afbabfb9b1a9a199928b80746c655b50493f342a1e150a00000000000000000000000000000713202c3945525d687783909daab6c3bfbab8babfc6b9aca196877b6e6154483b2e21150900000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000020b17202a343c454e555d60696e73787b7e8081828282817f7d7a77726d67605b534c443b332920160c02000000000000000000000000000a1724313d4a5764707d8a97a3b0b9b6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000000000040e172029323a444c565d676d78818d929ca4adb5bfb6aea49f93887e716a60564c4135291e150a00000000000e1b2734414e5a6774818d9aa7b4c0b4a79a8d8174675a4e4131261a13100c070005000000000000000000000000000000000000000000000000000000000000030e18222a31373a3c454955626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000000a16202c38434f59636f7c89949fabb8bbb0a69b8e8175695e535e6975818e9ba6b0bbb8aca0968a7e71665c5044382d22170b000000000916232f3c4855616b707c81868c91969c9fa6acaeb4b2acaca49f9c98928e89847f7b756f6a5f53473b2e21150800000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8175757575757575757575757575736e63574b3f3225190c000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f75757a86929facb8b7ab9f94887c6f62574d42362a1d13070000000000000000000a1723303d4955616c71727272727272727272726d625d676d72727272727272727272706c6155493c3023160a0000000000000000000000020c18232f3944505b656f7c89939eaab4ab9e94897d70665b505e6b7884919eabb7bdb0a3968a7d7063574a3d3024170b0500000000000005121f2b3744505b6578858c8e90929896989b93877d706b6360606163696e7b86929facb6c0beb3a9998c7f7366594c403326190800000e1b2834414e5b6774818e9aa7b4c1b9ada197897c6f625a534d4d4b5158606d7985929eabb8c2b5a99c8f8276695c4f432f23180c0000000000000000050f19222c353d474f585f696e79818c9399a1a9b1b9beb9aea79f9792877e736e605b53493f372d22180c0300000000000000000000000000000714212d3a4754606d7a86939facb9bcb4aeacaeb4bcbdb2a8978b7e7164584b3e31261a0e02000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000a141d29333c464e575f676d737b8084888b8d8e8f8f8e8e8c8a87837e79716c655e564d453b32281e1308000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000000000000000000000050e172029323a434c555c666d77808c929ba3adb5bfbbafa49a92867c6f685d52463e30261c1106000000000e1b2734414e5a6774818d9aa7b4c0b6a99c8f837669584e43372b201f1c181216110b03000000000000000000000000000000000000000000000000000000000a15202a343c434748515255626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000030f1b27323b4854606b76828f9ca6b0bbb7ab9f94887c6f62574d57626f7c88949fabb7bdb2a89d9184786d60544a3f33281c11060000000714202c38444f59616a6f747a7f848a8f949a9fa2aaacb2b6afacaaa29f9a96918c86827c6f6255483c2f22150900000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4b7ab9e918481818181818181818181818181807366594d4033261a0d000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736875818e9ba7b1bbb0a69b8e8175695e52463a2f24180d0000000000000000000814212d3945505a616465656565656565656565625b555d606565656565656565656564615a5044392d20140800000000000000000000000007121d27333f4953606b75818e98a3aeb0a69d9083786c60555e6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000030f1b27333f49536a7683909b9d9fa2aaa5a49992857d75706d6c6d6f747b849198a2aebec7baada297897d706356493d3023160a0000101d293643505c6976838f9ca9b6c2b8ab9e9285796c60534642404045515c6675828e9ba8b5c1b7ab9e9184786b554b4034291c1004000000000000030c17212b343d474f59606a6f7b838e939fa4abb3bbbbb3ada49d9590857d716c635c504941382d251b10060000000000000000000000000000000a1724313d4a5764707d8a99a4afbbb4aaa29fa2aab4bfb4a79b8e817468574d42372b1e1206000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000006111b262f3b454e585f6a6e7980868d919697999b9b9c9b9b999795908b857e776d685f574d443a3025190d050000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000000000000000050e172028313a434b545c656c74808c919ba3adb6c0b6aca39891847a6d61594f42382e23170c000000000e1b2734414e5a6774818d9aa7b4c0b8ab9e9185786a5f5347392f2d2c28231d221c150d050000000000000000000000000000000000000000000000000000030f1b26313c464e53555e5e5e626f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000006131f2b38434e58636f7c89949fabb2b2b1a89c8f83766a60544754606a7683909ca8b2b2b2aca0968a7e71665b5044382d22170b00000004101c27333d474f585f62686d72787d83888e92989ea1a8abb0b8b3aeaba8a09d99928b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4b9aca196918e8e8e8e8e8e8e8e8e8e8e8e8e83776a5d5044372a1d11040000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73666f7c8995a0acb8b9ac9f92867b6e61554b4035291c1106000000000000000005111d28333e485055575959595959595959595856514b515359595959595959595959575550473e33281c1004000000000000000000000000010b17222d38414f59616e7b86929fa9b3aca0958b7e71675d5e6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000b17222d424e5b6875818e9ba8acaeb4b5aba2979287817d7a797a7c80869196a1aab4bfc0b6ac9f9285796d6053463a2d2013070000111d2a3744505d6a7783909daab6c2b5a99c8f8276665b5044383134404b5466737f8c99a6b2bfb9ac9f928679675c5145382c1f13060000000000000a151e29333d464f59616b707c8590959ea5afb5bdb9b1a9a29e928d837b6f6b625a52443f382f261b120900000000000000000000000000000005111e2a36414c566774808d9aabb5baaea2989298a2aebab7ab9e918478695f53473a2d211408000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000b17222d38414d575f6a6f7c838d92999ea1a8a6a8a8a8a8a7a6a7a09d97918b827a6e695f564c41362a22170c0000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050e161f283139424a535b606e737f8b919ba4adb7beb4aaa1968e81756b61544a3f34281c10030000000e1b2734414e5a6774818d9aa7b4c0b9ada196887b6e62554b413b3a38342e332d271f170d030000000000000000000000000000000000000000000000000006121f2b37434e585f626b6b6b696f7c8895a2afbbbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000815222e3b4754606a76828f9ca6a6a6a6a6a0958a7d7063584e434e5864707d8a96a0a6a6a6a6a89d9184786c60544a3f33281c0f030000000b16212c353d464e53565e61666d71767c81868c91969c9fa6acaeb4b8b2acaba3988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4bdb2a8a19e9b9b9b9b9b9b9b9b9b9b9b9b9083776a5d5044372a1d11040000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73666b7784909daab4bbaea3998d8073675d5145382e23170b0000000000000000000c17222c363e45494a4c4c4c4c4c4c4c4c4c4c4a464045474c4c4c4c4c4c4c4c4c4c4a49443e352c22170b000000000000000000000000000006111b262f3d46535e6973808d97a1adb1a79e9184796d60566b7884919eabb7bdb0a3968a7d7063574a3d3024170a000000000000000006192633404c5966737f8c99a6b2babfbdb3a9a299938e89878687898d9298a1a8b2bcc6bbafa49a8e8174665c5144382c1f12060000111e2b3844515e6b7784919eaab7c1b4a89b8e817568544a3f33282e3f4b5865727e8b98a5b1bebbaea39986796d6053473a2d201407000000000006111c26303b454f59616b707d869197a0a7afbbbfbaaea79f97928a80786e696059504840332d261d140a000000000000000000000000000000000713202d3946525e687784909daab7b8ac9f9285929faab4b9ada196887b6e6155483b2e221509000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000030f1b27333f49535e696f7c8591959fa3abacb2b3b4b5b4b5b4b2b1aca9a19e948f847b6e685e52463e33281c110400000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050d161f2730384149505b636d727f8b919ca5afb9bcb2a89e938a7d70665c5044382c1f160a0000000e1b2734414e5a6774818d9aa7b4c0bdb2a9998c7f72675d514c47464540393e3931291f150b000000000000000000000000000000000000000000000000000815212e3a47535f6a6f78787776747c8895a2afbbbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000004101d2935404b55626f7c8994999999999999999184786c6053463c4653606c78849199999999999999968a7e71665b5044382b1f120600000005101a232c343c43474c52545c60646a6f747a7f848a8f949a9fa2aaacb2b7b5a5988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4c4bab2acaba8a8a8a8a8a8a8a8a8a8a89d9083776a5d5044372a1d11040000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736665727f8b98a2aebab5ab9f92857a6d60544a3f34281c1003000000000000000005101a242c33393d3e3f3f3f3f3f3f3f3f3f3f3e3a35383a3f3f3f3f3f3f3f3f3f3f3d3c39332c231a10050000000000000000000000000000000a141d2a36424d57606d7a85929ea7b1ada1968c7f73685e6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000b1724313e4a5764717d8a97acb6c0cac5bbb3aba49f9b96939394969a9fa3aab2bac4bcb3a99f93877c6f62544a4034281c10040000121f2c3845525f6b7885929eabb8c0b4a79a8d8174675a4e412d22313e4b5864717e8b97a4b1bebfb5ab94877a6e6154473b2e21140800000000000c17232e38424d57606b707d869298a1a9b1b9bcb4aea49d9590857d736d665e574f473f3627221b140b02000000000000000000000000000000000714212e3a4754616d7a86939facb9b4aa9a8d818d98a2aebab2a8988b7e7165584b3e31261a0f020000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000005121f2b3744505b656e7b849197a0a7aeb4b9b2adaba8a7a8abadb3b8b3ada69f9691847a6d615a5045392d20150a00000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000000306060b0b0b0b0b0b0d151e262f383f44525b626d737f8c939ea7b1bdbaafa59e9184786d6053463d32271b0f0300000e1b2734414e5a6774818d9aa7b4c0c4b8ab9e9184796d605d555453514b4f4a433b31271c11050000000000000000000000000000000000000000000000000915222f3c4855626f7c84858483807f8c98a5b2bfbdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000006131f2c3945515d6776828c8c8c8c8c8c8c8c8c8b7e71655b50443844505b66727f8b8c8c8c8c8c8c8c8c8c84796c605346392d2013060000000008111a222a32373a41464a5053585f62686d72787d82888e92989ea0a8abb0a5988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b4b4b4b4b4b4b4b4b4b4aa9d9083776a5d5044372a1d11040000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366606d7a86929facb8baada2978b7f72665c5044382b1f160a00000000000000000008121a22282d303132323232323232323232312e292c2d3232323232323232323231302d28221a110800000000000000000000000000000000020b1a25313b45515d67727e8b95a0acb2a99f92867a6e616b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000915222f3c4855626f7b889aa4afbbc8c4bab2acaaaca8a3a09fa0a2a7acaeb4bcc2bbb3aaa1978e81756a5f5342392e23180c000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea194887b6e6155483b2e2215080000000003101c28343f4a545e696f7d869298a2aab2bbbab2aaa29f928d837b706c605c544d453d352d2417110a0200000000000000000000000000000000000b1724313e4a5764717d8a9aa4afbaaea398897c85929fabb8b4a89b8e817568584e43372b1f12060000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000030f1b27333f4953606c77828f96a1a9b1bab3ada8a19e9b9a9b9ea1a9adb3b9b0a8a1968f82756c6155493d32271b0f03000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000000000060b0f12131818181818181818151d262d334049515b636d74818e95a0abb5c0b9aca0968b7e7165584e43382c1f130700000e1b2734414e5a6774818d9aa7b4c0c6b9ada1978d80746d676361605c545b554d43392d22160a0000000000000000000000000000000000000000000000000916222f3c4955626f7c8891918f8d8c919ba7b4c0bdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000714202d3a4753606d797f7f7f7f7f7f7f7f7f7f7f796d6053493f333f4a54606d797f7f7f7f7f7f7f7f7f7f7f7b6e6154473b2e211408000000000008101820262b3036383f44464e53565d61666d70767c81868c91969c9fa6a5988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b4b4b4b4b4b4b4b4b4b4aa9d9083776a5d5044372a1d11040000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665d6874818e9ba7b1bcb3a99e9184786d6053463d32271b0f030000000000000000000810171d2123242626262626262626262524221d1f20262626262626262626262423201c17100800000000000000000000000000000000000009141f2935414c55606d7883919da6b0aea2988e81746a6b7884919eabb7bdb0a3968a7d7063574a3d3024170a00000000000000000714202d3a4753606d7a86939facb9c6bdb2a8a09ea0a8afadacadafb3b9babfbab8b0a9a29891857a6d61584e4330271c1207000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000000020d17202c3844505c666e7b859298a2aab4bcb9b1a8a198928a80786e696159514a423b332b231b120607060400000000000000000000000000000005111e2a36424d576774818d9aacb6b8ac9f928678838f9ca9b6b8ab9e9185786a5f53473a2e2114060000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000005121f2b3744505b65717e8a949fa9b2bbb3a9a29e96918f8d8e91979fa2a9b3bab2a89e948a7e7164584e43372b1f1306000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000020a11171c1f2025252525252525252525212227373f49515b606d79839199a3afbbbdb2a89d9083776a6054483b2e22150800000e1b2734414e5a6774818d9aa7b4c0c9beb2a99d928d807a73706e6d666a665f554a3e33261a0e0000000000000000000000000000000000000000000000000916222f3c4955626f7c88959e9c9a989ba3adb8c4bdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000006131f2c3945515d676d73737373737373737373736d675c5141382d3845515d676d73737373737373737373736e695e52463a2d201407000000000000060e151b1e252a2e34383c43474c52545c60646a6f747a7f848a8f949a9f988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4c4bab2acaba7a7a7a7a7a7a7a7a7a7a79d9083776a5d5044372a1d11040000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736656626f7c8995a0acb8b9aca1968a7e7164594f43382c1f140900000000000000000000050c1114171719191919191919191919181510131419191919191919191919171614100b0500000000000000000000000000000000000000030d19242f3a44505c66707d8a949fabb4aa9f92877c6f6b7884919eabb7bdb0a3968a7d7063574a3d3024170a000000000000000006131f2c3845515d677884919eabb7c4b9aca09691969ea5acaeb4b3b4b4b3b4aeaca69f9792867d6f685e52463c311e150b00000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000008131e2a36424d57606d78839097a1aab4bcb9b1a79f9691867e746d665e574f444039302920191818181313100c07000000000000000000000000000714202d3a46525e697784919eaab7b6a99c908376808d99a6b3b9ada197887b6e6255483b2d22170b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000613202d394653606c7884919ea6b0bbb3a9a197928a84828182858b9297a2a9b3bab0a69d9083776a6054473b2e221508000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000020b141c22282b2d313131313131313131312e2d2a2d374045515d676f7c87929fabb5c0b8aca095897c6f6256493c3024190d01000e1b2734414e5a6774818d9aa7b4c0cfc4bbaea49d928d85807d7a79797771665b4f4236291d100000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2a9a7a5a7adb5bfc9bdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000004101d2935404b555d606666666666666666666666605c554b402f2935404b555d606666666666666666666666615e574d42362a1e110500000000000000040a0f13191c23282b31373a41464a5053585f62686d72787d82888d92988b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4bdb2a8a19e9b9b9b9b9b9b9b9b9b9b9b9b9083776a5d5044372a1d11040000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659606a7783909daab4bdb2a89d9083766b6054483c31261a0e02000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c0b090406070c0c0c0c0c0c0c0c0c0c0a0a08040000000000000000000000000000000000000000000008131e28343f4a54616b76828f99a3afafa3998f82766b7884919eabb7bdb0a3968a7d7063574a3d3024170a000000000000000004101d2935404b556976828f9ca9b5c2b7aa9e91848e939b9fa2aaa7a8a7a6aaa39f9b948f857d706b60564c41342a200c0300000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f2215080000010d1925303a46525e69727f8c959fa9b3bcbab1a79f9590847c716c605c544d453e342e27252525252525201f1c18120b0300000000000000000000000814212e3b4754616e7b8796a0acb8b3a69a8d80737d8a97a8b2bdb3a9988b7e726553493f33271b0f0300000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000a1723303d4a5663707d8996a0acb8b9ada19791857e79757475797e859297a2adbab8aca095897c6f6256493c2f231606000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000a141d262d3338393e3e3e3e3e3e3e3e3e3e3b3936302935404b555f6a74818d99a3afbbbcb1a79a8d807367564c4135291d1105000e1b2734414e5a6774818d9aa7b4c0c5bebab8aea49d97928d8987868583776a5d5044372a1d110000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afb3b2b4b8bfc7cabdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000c18242f39434b5153595959595959595959595953514b43392f242f39434b5153595959595959595959595954524d453b30251a0e0200000000000000000002080d11171c1f262b3035383f44464e53565d60666c70767b81868c8b7f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4b9aca196918e8e8e8e8e8e8e8e8e8e8e8e8e83776a5d5044372a1d11040000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366595865727e8b98a2aebab8ab9f95897c6f63574d42372b1e1308000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010b17232e38424f59626f7c87929faab3ab9e94897d707884919eabb7bdb0a3968a7d7063574a3d3024170a0000000000000000000c18242f414d5a6774808d9aa7b3bdb0a4978a7e81898e9298999a9b9a9a9898928f89827b706b60594f443a3022180e0000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000005111e2a36414c56616e7b86929fa7b1bbbdb2a89f9590837a6f6a615a514a423b333131313131313131312d2c28231d150c03000000000000000000000b1825313e4b5864717e8b97a8b2bdb3a9978a7d717a8796a1adb9b5a89b8e8275655b5044372b1f120500000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000005111e2a36424d576874818e9ba8b2bdb2a89e91857b716d6667666d717c85929fabb8b8b1a7998c7f7366594c402d22170b000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000006111c262f383f44464b4b4b4b4b4b4b4b4b4b4746413b322f39434e58616e7b86929facb9c3b7aa9d918477685d5246392d201307000e1b2734414e5a6774818d9aa7b4c0bcb4aeabacafa9a19e9a9694989184776a5e5144372b1e110000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbbfc0c4c9d1cabdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000007121d2731394045474c4c4c4c4c4c4c4c4c4c4c4745403931271d2831394045474c4c4c4c4c4c4c4c4c4c4c4746423b33291f140900000000000000000000000000060b10151b1e24292e34383c43474c52545b60646a6e747a7f847f7265584c3f3225190c00000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c4b7ab9e9184818181818181818181818181817f7366594c403326190d000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73665954606d7a86929facb8bcb1a79b8f8275695f53463a3025190d0000000000000000000000000406070a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a090704000000000000000000000000000000000000000000000000000000000006111c26303e47535f6a74818e98a2aeb0a69d9083787884919eabb7bdb0a3968a7d7063574a3d3024170a000000000000000000071925323f4c5865727f8b98a5b2beb2a5988c7f747c8285898c8d8e8e8d8b8986827d766e6960594f473d32291e10060000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000713202d3946525e6874818e98a2aeb9c0b5aba1969083796d685f58504440393b3e3e3e3e3e3e3e3e3e3e3a38342e271e150b00000000000000000005121e2a36424d576874818e9ba7b4b9ada197877b6e7884919eabb8b8ab9e9285796c605346392d20130600000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000714202d3a46525e697884919eabb8b9ada1968a7d7169605c545c606a727f8c98a9acacaca99c8f827669544a3f33281c0f030000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000b17222d38424a50535858585858585858585854524c443b30313c46525e6875828e9ba8b5c1b9ac9f93867a6d6154473a2e211407000e1b2734414e5a6774818d9aa7b4beb4aaa29f9fa4abadaba6a3aa9d9184776a5e5144372b1e110000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afb8babec5ced2cabdb1a4978a7e7164574b3e3124180b000000000000000000000000000000000000010b151f272f35393a40404040404040404040403a38342f271f161f282f35393a40404040404040404040403b3a36302920170d02000000000000000000000000000000030a0f13191c23282b31373a41454a5053585f62686d72797a6d6154473a2e21140700000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8175747474747474747474747474736d63574b3e3225190c000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659515d6774818e9aa7b1bcb9ac9f93877b6e61564c4135291d1207000000000000000001070c10131417171717171717171717171717171717171717171613100b05000000000000000000000000000000000000000000000000000000000a141e2b37434e58616d7a85929fa8b2aca0958b7e7884919eabb7bdb0a3968a7d7063574a3d3024170a0000000000000000000a1723303d4a5663707d8996aab4bfb4a79a8e81746f75797d7f808181807f7c7975706b615f574f473d352b20170d000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000714212e3a4754616d7a86929faab4bfbbafa39991847a6e675e564e463e4246474b4b4b4b4b4b4b4b4b4b4645403930271d120700000000000000000714212d3a46535f697884919eabb7b8ab9e9185786975828f9ba8b5b9ada197887c6f6255483c2d22170b00000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000814212e3b4754616e7b8796a1adb9b7ab9e9184786c6057504a5058616e7a87979f9f9f9f9f9e928578665b5044382b1f12060000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000030f1c28333f4a545b6064646464646464646464615e564c41362a36414d5664717e8a97abb5c0bbafa49a897c706356493d3023160a000e1b2734414e5a6774818d9aa7b4baaea298929399a4afb8b3b0aa9d9184776a5e5144372b1e110000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2a8abadb3bcc1c9cabdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000030d151d24292c2d33333333333333333333332d2c29231d150d161d24292c2d33333333333333333333332e2d2a251f170e0500000000000000000000000000000000000002080d11171c1f262b3035383f44464e53565d60666c6d685d5246392d20130700000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e827568686868686868686868686866635b52463b2f23160a000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c55626f7c88959fabb8bbafa4998d8174685e5246392e23180c00000000000000030b12181d1f20242424242424242424242424242424242424242322201c160f08000000000000000000000000000000000000000000000000000000020c1a26313c46525e68727f8c96a1acb1a79e91847a84919eabb7bdb0a3968a7d7063574a3d3024170a0000000000000000000815212e3b4854616e7b8798a2aebab6a99c90837669676d707274757473726f6d67636059534d453d352b23190e05000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000b1825323e4b5865717e8b99a3aebcc0b5ab9f92877c6f685e554c443c444d52545858585858585858585853514b42392e23180c00000000000000000815222e3b4855616e7b8896a1acb9b5a89b8f827568727f8c99abb5beb3a9988b7f7265544a3f33281c0f03000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000a1723303d4a5663707d8996a9b2bdb4a79b8e8174655b50443f46525e687885929292929292929286796c605346392d2013060000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000006121f2b3844505b666c717171717171717171716e685e5246392d303b4854616e7b8799a3afbbc0b6ac988b7e7165584b3e3225180b000e1b2734414e5a6774818d9aa7b4b8ab9f928687939fa9b1bab7aa9d9184776a5e5144372b1e110000000000000000000000000000000000000000000000000916222f3c4955626f7c8895999b9fa2a9afb7c1ccbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000030b12181d1f202626262626262626262626201f1c18120b040c12181d2020262626262626262626262621201e1a140d0500000000000000000000000000000000000000000000060b10151b1e24292d33383c43474c52545b60615d564c4135291d110500000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5b5b5b5b5b5b5b5b5b5b5957524940352a1e1307000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c54606a7783909daab4beb5ab9f92867a6d61554b4034281c10040000000000030d151d24292c2d31313131313131313131313131313131313131302f2c27211911080000000000000000000000000000000000000000000000000000000a15202a36414c56606d7984919ea7b1ada1978c7f84919eabb7bdb0a3968a7d7063574a3d3024170a0000000000000000000613202d394653606c7985929facb8b8ab9e928578685d606366676867676563605d55544f46423b332b2319110700000000000000121f2c3945525f6c7885929fabb8c1b4a79a8e8174675b4e413428323e4b5865717e8b98a4b1bebbaea195887b6e6255483b2f22150800030f1c28333f4a546875828e9babb4bfbbafa3998d80736a60564c433a424d565e6164646464646464646464605c544b4034281c1004000000000000000b1825323e4b5865717e8b98a8b2bdb5ab998c7f7266707c8999a4afbbb5a89b8f8275665b5044382b1f1206000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000b1825313e4b5864717e8b97a4b1beb3a6998d80736653493f36414c566a77848585858585858585867a6d6154473a2e2114070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000613202d394653606c797e7e7e7e7e7e7e7e7e7e7a6e6154473b2e2d394653606c7986929facb9bfb2a5998c7f7266594c3f3326190c000e1b2734414e5a6774818d9aa7b2b2aa9e9184828f96a0a7aeb4aa9d9184776a5e5144372b1e110000000000000000000000000000000000000000000000000916222f3c4955626f7c888b8c8e92979ea5afbac3bdb1a4978a7e7164574b3e3124180b00000000000000000000000000000000000000000001070c10131419191919191919191919191413100c07010001070d10131419191919191919191919191414110e090200000000000000000000000000000000000000000000000000030a0f13191c22282b31373a41454a505354524c443a3024190d0100000916232f3c4956626f7c8995a2afbcb6a99c908376695d504336414e5b6874818e9ba7b4beb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4e4e4e4e4e4e4e4e4e4c4b4640372e24190d02000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4e5865717e8b98a2aebabaaea2988c7f73675c5145382c1f160b00000000010b151f272f35393a3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3c38332b23190f050000000000000000000000000000000000000000000000000000030d1925303a45515c67717e8a959fabb2a99f928585929fabb8bdb0a3968a7d7063574a3d3024170a00000000000000000005121f2b3744505b657784909daab7b9ada197877a6d605456595a5b5b5a585653514b48443d363129211911070000000000000000121f2c3845525f6b7885929eabb8c1b4a89b8e8175685b4e423126323f4c5865727f8b98a5b2bebbaea194887b6e6155483b2e2215080006121f2b3844505b667885919eabb8c4b9ac9f92867b6e61584e443b3a46525e696e717171717171717171716d665c5145382c1f130600000000000006121f2b37434e586875818e9ba8b4bbafa499897c70636d7a86939facb9b8ab9f9285796c605346392d201306000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000c1926323f4c5965727f8c98a5b2bfb3a6998c807366594d40303b4f5b6772777979797979797979796d685d5246392d2013070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000006121f2b3844505b6679878b8b8b8b8b8b8b8b8a7d7063574a3d302c3845515c667885929fabb8bfb3a6998c807366594d4033261a0d000e1b2734414e5a6774818d9aa6a6a6a69e91847b8491959fa2aaaa9d9184776a5e5144372b1e110000000000000000000000000000000000000000000000000714212d3a4754606d7a7e7e7f82858e939ea8b2bdbdb1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000406070d0d0d0d0d0d0d0d0d0d0d070604000000000000010406070d0d0d0d0d0d0d0d0d0d0d08070502000000000000000000000000000000000000000000000000000000000002080d11171c1f262b2f35383f44464746413a32281e13080000000916232f3c4956626f7c8995a2afb2b2a99c908376695d504336414e5b6874818e9ba7b2b2b1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f424141414141414141403e3b352e251c120700000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4753606d7a85929fabb8bfb4aa9e9185796d6053463d33271c100100000007121d2731394045474a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a48443d352b21160b00000000000000000000000000000000000000000000000000000008131e2834404b55616c7683909da5afaea298929297a2adbabdb0a3968a7d7063574a3d3024170a000000000000000000030f1b27333f49536875828e9ba8b5beb3a995897c6f62564a4c4d4e4e4d4c494745403938322a2625221e18110a01000000000000121e2b3845515e6b7884919eabb7c2b5a99c8f827669574d42372b333f49536673808c99a6b3bfbbafa49a877a6e6154473b2e211408000613202d394653606c7986929facb9c2b5a89c8f8275685e52463d323b4754616e7b7e7e7e7e7e7e7e7e7e7e796d6053463a2d2013070000000000000814212e3a47535f6a7885919eabb8b9ac9f93867a6d60677784909daab7baada297887c6f6255493c2e23170c000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413025313d4a5764707d8a97a3b0bdbbafa295887c6f6255493c2f221609000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000c1926333f4c5966727f8c99a5b2bfb3a6998c807366594d40333f4b5660676a6c6c6c6c6c6c6c6c6c615d564c4135291d11050000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000030f1c28333f4a5f6c788592979797979797978b7e7265564c4137353c4653606d7986939facb9bfb2a6998c7f7366594c403326190d000e1b2734414e5a6774818d9999999999999184777b838c92989b9d9d9184776a5e5144372b1e110000000000000000000000000000000000000000000000000713202c3945525d686d717173757a818e96a0acb2b2b1a4978a7e7164574b3e3124180b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b0f151a1e24292d3338393a3935302820160c020000000916232f3c4956626f7c8995a2a6a6a6a69c908376695d504336414e5b6874818e9ba6a6a6a6a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42353535353535353533322f2a241c130a0000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c45515d6774818d9aa7b1b2b2ada1978b7e7164594f44382c1d12070000000c18242f39434b51535757575757575757575757575757575757575756544f473d33271c10040000000000000000000000000000000000000000000000000000020c18232e3943505a626f7c89939eaab4aaa29f9fa2a9b3bebdb0a3968a7d7063574a3d3024170a000000000000000000000b17222d404d596673808c99a6b3beb1a4978b7e7164584b3f414241403f3c3a38352f36363632312e2a231c130a000000000000111d2a3744505d6a7783909daab6c3b8ab9e918578695f53473b383944505b6575828e9ba8b5c1b9ac9f9386786d6053463a2d201307000714212e3a4754616d7a8799a3afbbc0b3a6998d807366564d4134313d4a5764707d8a8b8b8b8b8b8b8b8b867a6d6053473a2d2014070000000000000815222f3b4855626e7b8897a1adb9b7aa9d908477675d6774818e9aa7b4beb3a9988c7f7265544a3f34281c10030000000000121e2b3845515e6b7884919eabb7c2b5a89b8f827568564d41362c303e4b5864717e8b97a4b1bebdb2a894887b6e6155483b2e221508000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d403c3c444e565b5e5f5f5f5f5f5f5f5f5f54524c443a3024190d010000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000b17222d44515d6a7783909da4a4a4a4a49b8e8175685e52474341464e58636f7c899aa4afbbbeb1a5988b7e7265584b3f3225180c000e1b2734414e5a6774818c8c8c8c8c8c8c8c84776e7980858b8e90929184776a5e5144372b1e1100000000000000000000000000000000000000000000000004111d2935414c565d60646466676d7884919ea5a5a5a5a4978a7e7164574b3e3124180b000000000000000000000000000000000002070a0c0d1313131313131313130e0d0b080300000001040707131313131313131313130807050200000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a0f13191c22282b2d2e2d29241e160e04000000000916232f3c4956626f7c8995999999999999908376695d504336414e5b6874818e999999999999978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235282828282828282625231e19120a010000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c404b55626f7c88959fa6a6a6a6a99d9083776b605548392f23180c000004101d2935404b555d60646464646464646464646464646464646464646360594f44382c20130700000000000000000000000000000000000000000000000000000007121d27303e4754606a75818e98a3aeb4aeacabadb3bbc5bdb0a3968a7d7063574a3d3024170a00000000000000000000061824313e4b5764717e8a97a4b1bdb3a6998d8073665a4d43434343434343434343434343433f3e3a352d251c110700000000000f1c2935424f5c6875828f9ba8b5c2b9ada197887b6e62574d4644464b54606c7884919eabb7c4b8ab9e918578665c5145382c1f1306000814212e3b4754616e7a8794aab4bfbeb2a5988b7f7265584c3f3134404b5465727e8b979797979797979286796c605346392d2013060000000000030f1b27333f495365727e8b98a9b2beb4a79a8e8174675565717e8b98aab4bfb5a89c8f8275665c5044382c1f12060000000000111d2a3744505d6a7783909daab6c3b7aa9d908477685e52463c393a424d576673808c99a6b3bfb9ada196877a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d49494949494949515252525252525252524746413a32281e1308000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000061b2835424e5b6875818e9ba8b1b1b1ac9f92867a6e615c534e4c52575f6a74808d9aacb6c0bcb1a796897d7063564a3d3023170a000a1724303d4a5763707d7f7f7f7f7f7f7f7f7f72676d737a7e8184858684776a5e5144372b1e11000000000000000000000000000000000000000000000000010d19242f3a444c52545758555d6673808c989898989898978a7e7164574b3e3124180b00000000000000000000000000000000070d1316191a2020202020202020201b1a18140f0802080d111314202020202020202020201514120e09030000000000000000000000000000000000000000000000000000000000000000000000000000000000000001080d11171c1f2021201d19130c0400000000000916232f3c4956626f7c898c8c8c8c8c8c8c8c8376695d504336414e5b6874818c8c8c8c8c8c8c8c8b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c1b1b1b1b1b191916130d0d0c0a0702000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4047535f6a7683909999999999999995897d7063554b4034291c10040006131f2c3945515d676d70707070707070707070707070707070707070706b6054483c2f221609000000000000000000000000000000000000000000000000000000000b151e2b38434e58616e7b86929fa9b3bab8b8babec5cdbdb0a3968a7d7063574a3d3024170a000000000000000000000916232f3c4956626f7c8995a9b3beb5a89b8f827568544a4f4f4f4f4f4f4f4f4f4f4f4f4f4f4c4a463f372d23180d01000000000d1a2633404d596673808c99aab4bfbeb3a9998d8073695f57535053555c66707c8996a1acb9c2b5a99c8f827669544b4034281c1004000714212d3a4754606d7a8798a2aebabfb2a6998c7f7366574d43403f45515c6674818e9aa4a4a4a4a49e918478655b5044372b1f1205000000000005121f2b3744505b6575828e9ba8b5bfb4aa988b7e716558626f7c8898a2aebab8ab9f9285796d6053463a2d20130700000000000f1c2835424f5b6875828e9ba8b5c1b8aca095877b6e61564d4745474b545f6976828f9ca9b6c2b8ab9e918478685d5245392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c8073665956565656565656565656565656565656565653514a42392e23180c000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000c1925323f4c5865727f8b98a7b1bcbaaea3988e81756e625f58565e61696e7c86929facb9c5b8aca095877a6e6154473b2e211408000916232f3c4855616b707373737373737373726d6260686d7175777879796d6053463a2d2013070000000000000000000000000000000000000000000000000008131e28323a4145474a4b4b5464717e8a8c8c8c8c8c8c8c8a7e7164574b3e3124180b0000000000000000000000000000010a12191e2325262d2d2d2d2d2d2d2d2d282724201a130c13191d20212d2d2d2d2d2d2d2d2d2d21211e1a140d05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b0f12131413110d08020000000000000814212e3b4754616e7b7f7f7f7f7f7f7f7f7f7e7164584b3e313d4a5763707d7f7f7f7f7f7f7f7f7f7c6f6255483c2f22150900121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281e1e1e1e1e1e1e1e1e1e1e1a1917130e080000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c40434e5865717e8b8c8c8c8c8c8c8c8c8c8276675c5145382c1f1306000714202d3a4753606d797d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7063564a3d3023170a00000000000000000000000000000000000000000000000000000000030c1b27323d46535e6973808d97a1adb9c3c5c6cad0c9bdb0a3968a7d7063574a3d3024170a000000000000000000000714212d3a4754606d7a8797a1adb9b7aa9d918477665c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c595751493f352a1e1206000000000a1724303d4a5763707d8a98a2aebac4b8ac9f92867b6e6962605b5e61676d7883909da8b2bdbdb2a8998c807366594d402e23180c00000713202c3945525d687985929facb8c2b5a89c8f8275695f554e4c4a5058606d7985919eabb1b1b1a99c8f83766953493f33271b0f0300000000000613202d394653606c7985929eabb8baaea298887b6f6255606d7985929facb8baaea298897c6f6256493c2e23180c00000000000c1926333f4c5966727f8c99a9b3bebcb1a7998c7f72685f57535153555d666e7b87939facb9c2b5a89c8f827569564c4135291d1104000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c80736662626262626262626262626262626262626262605c544a4034281c10040000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b8895a0acb8bfb4aa9e938c80766f6a6968686d727b839199a3aebac4b7aa9d918477685e5246392d201407000714202c38444f596163666666666666666665625b565d6064686a656c6d665c5145382c1f130600000000000000000000000000000000000000000000000000010c1620282f35393a3e3e4855616e7b7f7f7f7f7f7f7f7f7f7b6e6255483b2f22150800000000000000000000000000000a131c242a2f32333939393939393939393433302b251d161e24292c39393939393939393939392e2d2a251f170f05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306060707050100000000000000000714202d3a46525e696e737373737373737373716c6156493d303c4855616b707373737373737373736f6a5f53473a2e21150800121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352a2a2a2a2a2a2a2a2a2a2a2a2726231f19120a02000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403c4753606d797f7f7f7f7f7f7f7f7f7f7f796d6053473a2d201407000815212e3b4854616e7b878a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a84776b5e5144382b1e1100000000000000000000000000000000000000000000000000000000000a16202a36424d57606d7a85929ea7b1bcc8d3d6dbc9bdb0a3968a7d7063574a3d3024170a000000000000000000000613202c3945525d687885919eabb8b9ac9f9286796d6969696969696969696969696969696965635b51463a2e221609000000000714202d3a4753606d7a86929facb8c2baaea29891847b736f6c66696e7279818e959fabbac4b9aca196897c6f6256493c2f231607000004111d2935414c566a7784909daab7c3b9ac9f92867b6e67605859545c606a727f8b97a1adb9bfb4aa9a8d8073675a4d402d22170b0000000000000915222f3c4855626f7c8897a1adb9b8ac9f9285796d60535c667683909ca9b6beb4aa998c7f7266544b4034281c100400000000091623303c4956636f7c8997a1adb9c3b8ab9f92867a6e6962605d5f61676d78828f99a4afbbbcb1a7988c7f7265594c3f2f24190d01000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c80736f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6d665c5144382c1f12060000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000814212d3a47535f697784919da9b3bebcafa59c928c827c777575777a7f859195a0abb4bfbdb0a6998d807366564c41362a1e11050004101c28333e474f555759595959595959595856514c5254585b535b60605c544b4034281c10040000000000000000000000000000000000000000000000000000040d161e24292c2d313a46535f696e7272727272727272726e695f53473a2e2114080000000000000000000000000007121c252e353b3f4046464646464646464641403c362f26202830353946464646464646464646463b3a36312921170d0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36424d575e6166666666666666666664615a5045392d38444f596163666666666666666666625f584e43372b1f120600121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423737373737373737373737373733322f2a241c140a000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403945515d676d73737373737373737373736d675c5145382c1f1306000815212e3b4854616e7b8794979797979797979797979797979797979184776b5e5144382b1e110000000000000000000000000000000000000000000000000000000000040e1a25313b45515d67727e8b95a0acb8c2cfd9d6c9bdb0a3968a7d7063574a3d3024170a0000000000000000000004111d2935414c56697683909ca9b6bbafa399887c7676767676767676767676767676767676726d63574a3e3125180c0000000006131f2c3945515d6775828e9ba6b0bdbfb4aaa0969186807b7978797b7e848e939ea7b1bcbeb3a99e9184786c605346392d2013060000010d19242f414e5b6774818e9aaab4bfbbaea3999083796f6a676666666d717c86929fa9b3bebaaea2988a7d7063574a3d30241706000000000003101c28343f4a5465727f8c98a9b3beb6a99c8f8376665c50546773808d9aa6b3c0b5a99c8f8276665c5145382c1f1306000000000713202d3a4653606d7985929eacb6c0baaea29891847b746f6d67696e7279818e949fabb5c0b8ab9f95887b6e6155483b2e22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8e817c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c796d6053463a2d2013070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000006121e2b37424d5765727f8b97a2adbac1b7aea49c948f8884828283868c9297a0a8b1bdc0b5ab9e94887b6e6255483b3025190d0100000b16212c353e44484a4c4c4c4c4c4c4c4c4b4a464145474b4e49505353514b42392e23180c00000000000000000000000000000000000000000000000000000000040c13191d20212a36424d575f61656565656565656565625f574d42372b1e1206000000000000000000000000020d19242e3740474b4d5353535353535353534e4c4841382f28323a414553535353535353535353534846423b33291f1409000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a25303b454d5254595959595959595959585650483e3428333e474f555759595959595959595955534e463c31261b0f0300121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4444444444444444444444444444403f3b362e261c12080000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4035404b555d606666666666666666666666605c554b4034291c1004000815212e3b4854616e7b8794a1a3a3a3a3a3a3a3a3a3a3a3a3a3a39e9184776b5e5144382b1e1100000000000000000000000000000000000000000000000000000000000009141f2935414b55606d7883909da6b0bdc7d1dcc9bdb0a3968a7d7063574a3d3024170a00000000000000000000010d19242f414e5b6774818e9aa7b4c0b5ab9d908382828282828282828282828282828282827f7265594c3f3226190c0000000004101d2935404b5563707d89949fabb5c0bcb2a8a098928c88868586878b91969ea5afb9c2b9ada1978c7f72655b5044372b1f1205000000081724313e4a5764717d8a98a2aebabfb5ab9f9590837c7774737375797e859298a2aebbc0b5ab9f9285796d6053473a2d201407000000000006121f2b3844505c6675828f9ca8b5c0b3a6998d807366544a5764717d8a97a9b3beb8ac9f9285796d6053463a2d2013070000000006121f2b3844505c6674818d9aa4afbbbeb4aaa0969186817c7a78797b7f848e939ea6b0bdbdb2a89d908376695f53463a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb5a99d938e8989898989898989898989898989898989898989877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000020e1a26313c4753606d7985929fa7b1bbbfb6aea69f9c96918f8f9092989fa2a9b1bac2bbafa4998f82756a5f53473a2e1e140800000005101a232c33383c3d40404040404040403f3d3a35393a3e423f44464645403930271d1207000000000000000000000000000000000000000000000000000000000001080d11131a26313b454d535559595959595959595955534d453c31261a0e0200000000000000000000000007131e2a3540495257596060606060606060605b59534a4136303a444c525f606060606060606060605f534d453b31251a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f29333b4246474c4c4c4c4c4c4c4c4c4b49453e362d222c353e44484a4c4c4c4c4c4c4c4c4c4847433c342a20150a0000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5151515151515151515151515151514d4b4740382e24190e0200000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c402f39434b5153595959595959595959595953514b43392f23180c00000815212e3b4854616e7b8794a1aeb0b0b0b0b0b0b0b0b0b0b0b0aa9e9184776b5e5144382b1e11000000000000000000000000000000000000000000000000000000000000030d18242f3a44505c66707d89949eabb5c0cbd7c9bdb0a3968a7d7063574a3d3024170a0000000000000000000000081926323f4c5965727f8c98a5b2bfb8ab9f95908f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8e8175685b4e4235281b0f02000000000c18242f394854606b76839099a3afbbc1bab2aaa29f999993929299989ea0a8afb7c1bab0a69e92857a6d6053493f33271b0f030000000714202d3a4753606d7985929faab3bebdb1a79f95908983817f8082858b9297a2aab4bfbbafa3998e8174675d5145382c1f130600000000000713202d3a4653606d7985929fabb8bdb2a8978a7d7064574a54616e7b8797a1adb9baaea298897c6f6356493c2f23180c0000000003101c28343f4a54626e7b87939faab4bebcb2a8a098928d88868586888c91969ea5afb8c2b8aca0968a7e7164574d42372b1e120500000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfbaafa59d9a9595959595959595959595959595959595959594877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000915202c3945515d67727f8b95a0a9b3bcbfb8b0aaa8a09e9c9b9d9fa3aaadb3bcc1b9b0a69f93877c6f62584e43372b1f0d020000000008111a21282c2f30333333333333333332312e292c2d312d3337393a38342e271e150b0000000000000000000000000000000000000000000000000000000000000000010409141f29333b4246484c4c4c4c4c4c4c4c4c4847423c332a201509000000000000000000000000000a16232f3b47525b63666c6c6c6c6c6c6c6c6c67645d53483c35414c565d6c6c6c6c6c6c6c6c6c6c6c6c5e574d42362a1e1205000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d17202930363a3b4040404040404040403e3d39342d241b232c33383c3d4040404040404040403c3a37312a22180e040000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5a58524a40362a1f130700000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403331394045474c4c4c4c4c4c4c4c4c4c4c4745403931271d120700000815212e3b4854616e7b8794a1a7a7a7a7a7a7a7a7a7a7a7a7a7a79e9184776b5e5144382b1e110000000000000000000000000000000000000000000000000000000000000007131d28343f4a54606b76828f99a3afbbc5d0c9bdb0a3968a7d7063574a3d3024170a00000000000000000000000a1724303d4a5763707d8a96abb5bfbcb1a79f9d9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9b8e8175685b4e4235281b0f020000000007121d2c38444f59626f7c87929fa6b0b8c1bcb4aeababa49f9e9fa3abaaacb2bac1bab2a89e948b7e72675d5141382d22170b0000000006131f2c3945515d6774808d98a2aebac1b9b1a7a09d95908d8c8c8e92979fa2a9b3bcbcb2a89f92877b6e62554b4035291d100400000000000916232f3c4956626f7c8997a2adbab9ada196877a6e615447535e697885919eabb8bfb4aa998c7f7366554b4034291c1004000000000b17232e3847535f6a75818e98a2aebac0bab2aaa29f9a9597929299989ea1a9afb7c1b9afa59e9184796d6053463c31261a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfc0b7afa9a7a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000004101d2935404b55606d78839097a1aab2bbc0bbb7b2acaaa8a8aaacaeb4babebeb9afa79f948d80746a6054463c31261a0f0000000000000810161c20232426262626262626262524221d20212522272b2d2d2c28231d150c0300000000000000000000000000000000000000000000000000000000000000000000030d18212931363a3b3f3f3f3f3f3f3f3f3f3b3a37312a21180e03000000000000000000000000000c1925323f4b57636d73797979797979797979746f64594c383945525d68767979797979797979797976695e53463a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050e171f252a2d2e33333333333333333331302d28221b121a21282c2f303333333333333333332f2e2b2620181006000000121e2b3845515e6b7884919eabb7c1b5a89b8e82756a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a66635c52473b2f23170a00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4033272f35393a40404040404040404040403a38342f271f150b0100000815212e3b4854616e7b87949a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9184776b5e5144382b1e1100000000000000000000000000000000000000000000000000000000000000010b17232e38424f59626e7c87929fa9b3becac9bdb0a3968a7d7063574a3d3024170a00000000000000000000000815222f3b4855626e7b8899a3aebbc2b9b1aba9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a89b8e8175685b4e4235281b0f020000000001101c27323d4754606a73808c939ea6afb9bebebab8b5afacabacaeb4b7b9bdbfbab1a8a0968f82766d62554c412f261b11060000000004101d2935404b55616e7a85929fa5afb8c1b9b1aca7a09d9a99999b9fa2a9adb3bbbcb4aaa1968d81746a5f5343392f24180c000000000004101c2834404a5466727f8c99a9b3beb7ab9e918478685e52464d576875828f9ba8b5c2b6a99c8f8376675c5145382c1f13060000000006111c2b37434e58616e7b86929fa4aebbc0bcb4aeaca7a9a29f9fa3ababadb2bbc1b9b1a79e938a7d70665c5144382a1f14090000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfc5bcb4aeababababababababababababacafb5afafafada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000010d18242f3944505c666e7b859298a1a8afb6bbc0bdb9b7b5b5b7b9babfbebab3ada59e959082796d60584e43342a20150a00000000000000050b10141617191919191919191918181511131418171b1f20201f1c18120b03000000000000000000000000000000000000000000000000000000000000000000000000060f181f262a2d2e3232323232323232322f2e2b2620180f0600000000000000000000000000030f1b27333f4953667380868686868686868686817467544a3f3a4754606d7a868686868686868686867b6e6154483b2e2115070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050d141a1e20212626262626262626262524211d17100910171c20232426262626262626262622211f1b150e0600000000121e2b3845515e6b7884919eabb7c1b5a89b8e81777777777777777777777777777777777777736e63584b3f3226190c00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c40332624292c2d33333333333333333333332d2c29231d150d030000000815212e3b4854616e7b878d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d84776b5e5144382b1e11000000000000000000000000000000000000000000000000000000000000000006111c26303d47535f6a74818d97a2adbabfbfbdb0a3968a7d7063574a3d3024170a00000000000000000000000713202d3a4653606d7986929facb9c5c2bcb8b6b5b5b5b5b5b5b5b5b5b5b5b5b5b4a89b8e8175685b4e4235281b0f0200000000000b16212b37434e58606c78818f949ea5adb3babec4c0bbb9b8b9babfc4bfbbb4aea79f9691847a6d615b51433a2f1d140a0000000000000c18242f3946525e68727f8b939ea6afbabfbcb8b1acaaa7a6a6a8abadb3babebbb3aaa29891847a6d60574e4231271d1207000000000006121f2c3844515c6676828f9ca9b5c1b5a89b8e827568564d414c5966727f8c99acb6c0b9ac9f9286796d6053473a2d20140700000000000f1a26313c46535e69717e8b929da4afb5bdbfbab8b4b3adabacaeb5b8b9bdbebab0a7a0958e81756b61544a403428180e030000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfbeb4aaa29f9e9e9e9e9e9e9e9e9e9e9e9fa3abb5c0baada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000007121d28343f4a545f696f7d8691969fa4acafb5b8babebdbdc0bbb9b7b3ada9a19e938e837a6d675c51463d3222180e030000000000000000000407090a0d0d0d0d0d0d0d0d0c0b09040707060b0f12131313100c07000000000000000000000000000000000000000000000000000000000000000000000000000000060d141a1e212226262626262626262622211e1a150e06000000000000000000000000000005121f2b3744505b6576828f93939393939393908377665c50443d495663707c8993939393939393938a7e7164574a3e2e23180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002090e111414191919191919191919181715110c0600050b101416171919191919191919191515120f0a040000000000121e2b3845515e6b7884919eabb7c4b8ab9f92858384848484848484848484848484848484838073665a4d4033271a0d00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326181d1f202626262626262626262626201f1c18120b03000000000714212e3a4754616d7a81818181818181818181818181818181818181807366594d4033261a0d0000000000000000000000000000000000000000000000000000000000000000000a141e2b37434e58616d7a85929fa8b2b2b2b2b0a3968a7d7063574a3d3024170a000000000000000000000006121f2c3844505c667784919daab7bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb4a89b8e8175685b4e4235281b0f020000000000050f1b27323c44505b666d79828e939ea2a9adb3b7b9bbc0bcbcbeb9b8b5aeaba39f9590847b6e685d52483f31281e0b0200000000000007121d2a36414c56626d75818e949ea5aeb4babfbcb8b7b4b2b3b5b8babebcb8b0a9a29892867c6f685d52453c311f150b0100000000000713202d3a4653606d7985929facb8c0b5ab988c7f7265594c3f495663707d899aa4afbbbaaea398897c706356493d2f24180d01000000000915202a36424d57616c73808d929fa3abb1b8bdc3c0bebab8b9bbbfc3beb9b3ada69e959083796d60594f42392e231806000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfbaaea2989291919191919191919191919299a3afbbbaada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000010b17232e38424d57606b6f7c848e939a9fa3ababaeb4b0b0b5afacaaa9a29f97928b81796d685d554b40342b200f0600000000000000000000000000000000000000000000000000000000000003050607060400000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e1214151919191919191919191514120e09030000000000000000000000000000000613202d394653606c7985929f9f9f9f9f9f9f9286796d6053463f4c5965727f8c989f9f9f9f9f9f9a8d807467544b4034281c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020507080d0d0d0d0d0d0d0d0d0b0a0805000000000004070a0a0d0d0d0d0d0d0d0d0d0908060300000000000000121e2b3845515e6b7884919eabb7c4baada2979290909090909090909090909090909090908e8175685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4033261910131419191919191919191919191413100c070100000000000713202d3946525e686d74747474747474747474747474747474747474736e63574b3f3225190c000000000000000000000000000000000000000000000000000000000000000000020c1a26313c46525e68727f8c96a0a5a5a5a5a5a3968a7d7063574a3d3024170a000000000000000000000003101c28343f4a546975828f9ca8b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a89b8e8175685b4e4235281b0f020000000000000a152028333f4a545d676d79818b92979fa2a9aaacafb6afafb3adababa39f99928d837a6e695e564c41362d1f160c00000000000000010e1925303b44515b606d79828e939fa2aaaeb4b8b9bdbdbdbdc0bbb9b7b1aca69f9792867d706a60564c41332a200d03000000000000091623303c4956636f7c8998a2aebabbafa399897c6f6356493c4754606d7a86939facb9bfb4aa998c807366554b4035291d100400000000030e1a25313b45505a606c77808c9299a0a7acb2b7b9bbc0bcc0bbb9b7b3ada9a29f948f837a6e675d51473e30271c1207000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb8ab9f9286848585858585858585858487929facb9baada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000000006111c26303b454f59606a6f7a81878e92999c9fa2aaa3a3aba49f9d9b97928d857e756d675d564c43392e22190f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020507080c0c0c0c0c0c0c0c0c0808060200000000000000000000000000000000000815222f3b4855626e7b8897a2adacacacaea398887b6f625548404b556875818e9ba8acacacaca99d908376665c5145382c1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4beb3a9a29f9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d06070d0d0d0d0d0d0d0d0d0d0d070604000000000000000005111d2935414c565e616767676767676767676767676767676767676766635c52473b2f23160a000000000000000000000000000000000000000000000000000000000000000000000a15202a36414c56606d79849198989898989898968a7d7063574a3d3024170a0000000000000000000000000c17232e404d5a6773808d9aa5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a59b8e8175685b4e4235281b0f02000000000000040b17222d38424b555d676d757e858d92979b9e9fa4aca3a2a9a19e9b99928e8680786e685e574d443a30241b0d04000000000000000008141e29323f45515c676d79818b92989fa2aaabadb2b0b0b0b6afacaaa7a09d948f857d706b61584e433a2f21180e00000000000004101c2934404b5566737f8c99aab4bfb9ac9f92867a6d6053473a45515d677784919daab7c3b6a99c908376675d5145392c201306000000000009141f29333e44505b656c747f8790959ea0a8aaacafb5afb5afacaaa9a19e97928b82796e685e554b40352c1e150b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c80787878787878787878787884919eabb8baada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000a141e29333d474f585f686d747c82868b8f9298969697969993908e8a85807a716c605d554c443a30271d100700000000000000000000000000000000000000000000040607090c0e0f1011100f0e0c09070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825313e4b5864717e8b97a9b3beb9bfb4aa978b7e7164584b45515c677784909daab7b9b9b9ac9f9286796d6053463a2d20130700000000000000000000000000000003080b0d0e1313131313131313130c0b090501000004090e1112131313131313131313130807050200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c5bbb3adabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa89b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000010d1925303a444c52545a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5957524940352a1f130700000000000000000000000000000000000000000000000000000000000000000000030d1925303a45515c67717e8a8c8c8c8c8c8c8c8c8a7d7063574a3d3024170a000000000000000000000000061825323e4b5865717e8b9898989898989898989898989898989898989898989898988e8175685b4e4235281b0f020000000000000006111c262f39434b555c606c717a80858a8e91939a9596959597918f8b86817b736d665e564d453b32281e1209000000000000000000020d17202934404b555c676d757e868d92989b9ea1a9a3a4a3aca49f9d9a95908a827b706b61594f463d31281e0f0600000000000006131f2c3845515c6776838f9ca9b6c2b6aa9d908377675d514538414c556874818e9ba7b4c1b9ac9f92867a6d6053473a2d2014080000000000030d172127333f49535b606d727d838b91969a9d9fa3aba3aba39f9d9a97928c857e756d675e564d43392f231a0c0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c80736b6b6b6b6b6b6b6b6b7885919eabb8baada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000000000020c17212b343d464e565d616a6f757b7f838588898a8a89888684817d79736d68625a514b433a32281e150b000000000000000000000000000000000000000001070c10131416191b1c1d1d1d1c1b19161413100c0701000000000000000000000000000000000000000000000000010406070b0e0e0c0808060200000000000000000000000000000000000000000000000000000000000000000000000004101d2935404b556774818d9aa7b4c0cfc0b3a79a8d8074675a4d4753606d7986929facb9c5c7baaea398897c6f6256493c2f2316080000000000000000000000000001080f14181a1b202020202020202020181815110c06080f151a1d1f202020202020202020201414110e08020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cdc5bebab8b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5a89b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000008131e28323a4146474e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4d4b4740372e24190e02000000000000000000000000000000000000000000000000000000000000000000000008131e2834404b55616c727f7f7f7f7f7f7f7f7f7f7b6e6155483b2e221508000000000000000000000000091623303c4956636f7c898c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8175685b4e4235281b0f0200000000000000000a141d273139434b515a62686d73797d81848688898989888785827e7a746e69605c544d443b332920160c0000000000000000000000050e18232f39434b555c606d727a80858b8e919695969797969a93918d89837e766e6960594f473e342b1f160c000000000000000714202d3a4753606d7986929facb9bfb4a79a8d817467554b40353f4b5865727e8b98aab4bfbbaea399897d7063564a3d2f24190d010000000000050f17222d384149505b636b6f787e84898d9092999596959992908e89857f7a716c605d554d443b31271d11080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c8073665e5e5e5e5e5e5e6b7885919eabb8baada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000060f19222b343c444c52586062696e7276797b7c7d7d7c7b7a7774716d67615d5650454039312820160c03000000000000000000000000000000000000050b1012181c1f2023262829292a2929282623201f1d1812100b05000000000000000000000000000000000000000001070d101314181a1b191514120f09030000000000000000000000000000000000000000000000000000000000000000000006131f2c3945515d677783909daab6c3cfc2b6a99c8f837669574d4956626f7c8999a3afbbc7cbbfb4aa988b7f7265584c3f3025190d010000000000000000000000020b131a202427272d2d2d2d2d2d2d2d2d2524221d1811121920262a2c2c2d2d2d2d2d2d2d2d2d21201e19140d0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb5a89b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000000020c1620283035393a41414141414141414141414141414141414141403f3b352e251c1207000000000000000000000000000000000000000000000000000000000000000000000000020c18232e3943505a626d727272727272727272726e695f53463a2d2114070000000000000000000000000714212d3a4754606d797f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7d7063574a3d3024170a000000000000000000020b151f273039404550565e61676d7174777a7b7c7c7c7b7a7875726d68625f57514a423b322921170e0400000000000000000000000007121d273139434b515b62686e747a7e828587888a8a8a89888684807c77716c615e574f473e352c22190d04000000000000000a1623303d495663707d8998a3aeb2b2b3a9978b7e7164584b3e2f3c4955626f7c8898a2aeb2b2b5ab998d807366554c4135291d110400000000000006111b262f383f44515960666d71787c80838688898989888684817d79726d68625a514c433b32291f150b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c8073665952525252525e6b7885919eabb8baada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000071019222a323a41464e54575e6165656c6e6f7070706f6d676864605d55524c443f352f271f160e040000000000000000000000000000000000050b10161c1d23292c2d30333435363736353433302d2c29241d1c160f0a040000000000000000000000000000000000040c12181d20202427272622211f1a150c070100000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a86929facb9c5d2c5b8ab9f928578695f534b5865717e8b98abb5c0cbd1c1b4a89b8e817568564c41362a1d110500000000000000000000010b141d252b30333439393939393939393932312e29231b1b242b313638393939393939393939392e2d2a251e170e05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a89b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7b4b9b2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000040e161e25292d2e3434343434343434343434343434343434343433322f2a241c130a000000000000000000000000000000000000000000000000000000000000000000000000000007121d27303e48515b6265656565656565656565615f574d42362a1e12050000000000000000000000000613202c3945515d676d7272727272727272727272727272727272727272727272727272706b6155483c2f23160900000000000000000000030d151e272e343f444c52555d606468676d6e6f706f6f6d676865615e56534d444039302920170f0500000000000000000000000000010b151f273139404551565e61676d7175787a7c7d7d7d7d7b7a77746f6b64615a534d453d352c231a10070000000000000004111d2935404b556673808c99aaa6a6a6a6a297887b6e6255483b2f3a4653606d7985929fa6a6a6a6a69d908376675d5145392c201306000000000000000a141d262d333f474f545c60656c6f7477797b7c7c7c7b7a7774706d66605d565045413a312920170d03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d454545525e6b7885919eabb8baada194877a6e6154473b2e2114080000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000000000000000000071018202830353d43474d5254535b60616363646362605d555753514b46413a3229241d150d040000000000000000000000000000000000060c161c21272c2f34383a3c3f414243444342413f3c3a38352f2c27211b150f07000000000000000000000000000000080d161d24292c2d313434332f2e2b262018120b0300000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8999a3afbbc7d3c6baada297887b6e61554a546774818d9aa7b4c0d1d1c4b7aa9e918477685e5246392d2013070000000000000000000008131d262f363c40414646464646464646463f3d3a342d24242d353d4245464646464646464646463b3936302920170d020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a59b8e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa7adadada6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000000040c13191d2021272727272727272727272727272727272727272625231f19120a010000000000000000000000000000000000000000000000000000000000000000000000000000000b151e2c363f4951565859595959595959595955534d453b31261a0e0200000000000000000000000004111d2935414c555d6065656565656565656565656565656565656565656565656565656361594f44382c2014070000000000000000000000030c151d2328323a41464b515357555c606262636262605d555854524c47423c342e271e170e05000000000000000000000000000000030d151f272f343f444c52555d606468686d6f707170706f6d6767636059555046423b332b231a110800000000000000000613202c3945515d67768390999999999999999285796c605346392d3844505c667683909999999999999992867a6d6054473a2d21140700000000000000020b141b2227353d424a50535b606367666d6e6f706f6e6d676763605c54524c443f352f281f170e0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000c1926333f4c5966727f8c99a5b2bfb3a6998c807366594d403845525e6b7885919eabb8baada094877a6d6154473a2e2114070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000000000060e161e242932373b42464849505355565757565553514b4a474540393530282018120b0300000000000000000000000000000000030a111721272c333839404547494c4e4f5050504f4e4c494745403938332b27201910090100000000000000000000000008111a1f282f35393a3e41413f3b3a373129241d150d030000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c99abb5c0cbd6cabeb3a9978a7d706457505c667683909da9b6c3d0d2c5b9aca096877a6d6154473a2e211406000000000000000000030f1a252f3841484c4e5353535353535353534b4a453f372d2b353f474e52535353535353535353535346413b32291e14080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b78849198989898989898989898989898989898989898989898989898988e8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d9aa0a0a0a0a0998c7f7366594c403326190d0000000000000000000000000000000000000000000000000000000002080d1113141b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1a1916130e070000000000000000000000000000000000000000000000000000000000000000000000000000000000030c1a242d373f464a4b4c4c4c4c4c4c4c4c4c4846423b33291f140900000000000000000000000000010d19242f3a434c5154595959595959595959595959595959595959595959595959595957554f473e33281c1004000000000000000000000000030b121820283035394045474a4b5153555656565554514c4b4746413a373128231c150c050000000000000000000000000000000000030d151d2329323b41464c515458565e61626364646362605d5556544f49453e363129211911080000000000000000000714202d3a4753606d7a868c8c8c8c8c8c8c8c8c8276655b5044372b343f4a546773808c8c8c8c8c8c8c8c8c8a7d7063574a3d3024170a0000000000000000020a1117232b30383f4449505356545c606162636261605c555653514a45413a3229241e160d050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000c1926323f4c5965727f8c98a5b2bfb3a6998c807366594d4036414c566b7885929eabb8bbafa499877a6d6054473a2d2114070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000000000040c131920272b30363a3b3f444648494a4a49484745403e3a39352f29241e160e070100000000000000000000000000000000030c151c232833383d44484b515356595b5c5c5d5c5c5b595653514b48443d37322b221b130a010000000000000000000008121a232c31394045474b4d4e4c4847433c352f271f150c030000000000000000000000000000000000000000000000000000000005121e2a36424d576875828f9ba8b5c2d1dbd0bfb3a6998c8073665953606d7985929facb8c5d2d5c9bdb2a8968a7d7063574a3d2d22170b0000000000000000000814202b36414a53585a606060606060606060585651493f34313d4751595e5f6060606060606060605f524c443b3025190e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8275685b4f4235281c0f00000000000000000000000e1b2734414e5a6774818d939393939393938c7f7366594c403326190d000000000000000000000000000000000000000000000000000000000000010507070e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0d0c0a07020000000000000000000000000000000000000000000000000000000000000000000000000000000000000008121b252d343a3d3f3f3f3f3f3f3f3f3f3f3b3a36312921180d03000000000000000000000000000008131e28313a4145474c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a48443e352c21160b000000000000000000000000000000070e161e25292f35393a3e40454748494949484745413f3a3936302b261f18120b0300000000000000000000000000000000000000030b1218202930363a4145474b4c525455575757565553514b4948443d39332a251f170f07000000000000000000000814212e3b4754616e7b7f7f7f7f7f7f7f7f7f7f7d706353493f33272e3c4955626f7c7f7f7f7f7f7f7f7f7f7f7d6f6356493c30231609000000000000000000000610191e262e34383f4446494a5153555656565553514b4a46444039352f282019130c04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000b1825323e4b5865717e8b98a4b1beb3a6998c807366594d403946525e687985929facb8b9ac9f9386796d6053463a2d2013070000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000000000000002080d151b1f252a2d2d3337393b3c3d3d3d3c3a39352f2d2c29241d19130c040000000000000000000000000000000000030d151e262e343d44484f55555c6063666768696a6968676663605d55544f47433c342d251c140a000000000000000000050e1a242c353e434b5153575a5a5955534e45403931271e150b000000000000000000000000000000000000000000000000000000000714202d3a46525e697884919eabb8c4d1dbcfc2b5a89c8f8275695655626e7b8898a2aebac6d3d9cebfb3a6998c807366544a3f33281c0f0300000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6c65625b51453a36424e59636a6c6c6c6c6c6c6c6c6c6c6c5e564c41362a1e1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7d7063574a3d3024170a00000000000000000000000e1b2734414e5a6774808686868686868686867f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009131b23292e31323232323232323232322e2d2a261f180f06000000000000000000000000000000010c161f282f35393a3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3d3c38332c231a100500000000000000000000000000000000040c13191d24292c2d2f34383a3b3c3d3c3c3a39352f2e2d2a251e1a150c070000000000000000000000000000000000000000000001070e171e252a2f35393a3e414647494a4a4a4a484745403c3b38322d28221a140d0500000000000000000000000714202d3a46525e696e73737373737373737373706b605441382d222e3b47535f6a6f737373737373737373736f6b6054483b2f2215090000000000000000000000070c151c23282d3337393c40444648494949484745403d3a38342e29241e160d080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000000000000000a1724303d4a5763707d8a96aab4beb3a79a8d807467564c413d4754616e7a8798a3aebab8ab9e918578665c5044382b1f12060000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f141a1e2022272b2d2e303031302f2d2c2924201f1d18120d08020000000000000000000000000000000000020b151f2730383f444f54596163676d6f7274757677767574726f6d67636059544e463f372e261c120900000000000000020d17202c363e474f555d6064676766625f58514b433930271c12070000000000000000000000000000000000000000000000000000000815212e3b4854616e7b8796a1adb9c5d2ded1c4b8ab9e918478685e5764717e8a97aab4bfcad6dccfc2b6a99c8f8276665b5044382b1f120600000000000000000d1a2733404c58646e74797979797979797979726d62564a3d3845525e6a757979797979797979797976685e5246392d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313d4a56626c7172727272727272727272727272727272727272727272727272727272706b6155483c2f23160900000000000000000000000713202d3a4653606d797a7a7a7a7a7a7a7a7a786d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000911181d22242526262626262626262622211e1a140d060000000000000000000000000000000000040d161e24292c2d3232323232323232323232323232323232323232323232323232302f2c28211a110800000000000000000000000000000000000002080d12181d1f2023292c2d2f2f302f2f2d2c292421201d19130e090300000000000000000000000000000000000000000000000000050d14191e24292c2d3036393a3c3d3e3d3d3c3a39352f2f2c27211d170e090300000000000000000000000005111e2a36424d575e61666666666666666666666360594f442f261b2b37434e585f62666666666666666666666360594f43382c1f1307000000000000000000000000030a11171b22272b2d2e34383a3b3c3d3c3b3a38342f2d2c28231c19130c04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bcb6a99c908376695d5043362a1d100000000000000000000815222f3b4855626e7b8898a2aebab5a99c8f8276685e524b4a4e5863707d8a96aab4bfb6a99c90837669544a3f34281c10030000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e1214171b1f2022232424232220201d181413100c0701000000000000000000000000000000000000000a141d273139424a505960636b7076797c7f818283838382817f7c7975706b626058514940382e241b0f0500000000000008141e29323e48505961676d717474726e6a605d554b42392e23180c0000000000000000000000000000000000000000000000000000000b1724313e4a5764717d8a97a8b2bdc9d2d1d2c5b9ada196877a6d615a6773808d9aa6b3c0d0d1d2d2c5b8ab9f9285796c605346392d20130600000000000000000e1b2734414e5a6774808686868686868686867f7265584b3f3946535f6c79878686868686868686867a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915212e3a45505a6265656565656565656565656565656565656565656565656565656565656361594f44382c201407000000000000000000000006131f2c3845515c676d6d6d6d6d6d6d6d6d6d6d665c5144382c1f12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c121518181919191919191919191514120e090300000000000000000000000000000000000000040c13191d202126262626262626262626262626262626262626262626262626262423201c16100800000000000000000000000000000000000000000001070c101314181c1f20222323232221201d191413110d08020000000000000000000000000000000000000000000000000000000002080d13191d2021252a2d2e2f303131302f2d2c292422201b16110c060000000000000000000000000000020e1a25303b454d52545959595959595959595956544f473d331d1b26323c464e53555959595959595959595956544f473d32271b0f030000000000000000000000000000060c11171b1f2023282c2d2e2f302f2e2d2c2923201f1c18120d080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3afafafa99c908376695d5043362a1d100000000000000000000613202d394653606c7985929fabb8b8ac9f92867a6d615c5456575f6a74818e9ba7b4bfb4ab9a8d8174675a4e412e23170b000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000205060b0f12131516171716151413100d07060400000000000000000000000000000000000000000006111b262f39434b545c606b70777d8286898c8e8f8f908f8f8e8c8986827d776f6a625b524a40362d21170d0300000000020e1925303b44505a616b70797e80817f7b746d675d544a4034281c12070000000000000000000000000000000000000000000000000003101c28343f4a546773808d9aa6b3c0cac6c5c6c8bdb2a896897d7063576976828f9ca9b6c2c5c4c5c9c6baaea298887b6f6255483c2f22150700000000000000000e1b2734414e5a6774818d939393939393938b7e7265584b3f3946535f6c79869293939393939393877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d29343f485056585959595959595959595959595959595959595959595959595959595957554f473e33281c1004000000000000000000000004101c2834404b555c60606060606060606060605c544a4034281c10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000106090b0c0c0c0c0c0c0c0c0c0c080705020000000000000000000000000000000000000000000001080d1113141919191919191919191919191919191919191919191919191919171614100b05000000000000000000000000000000000000000000000000000406070c10131415161616151413110d08070501000000000000000000000000000000000000000000000000000000000000000001080d111314191d202122242424232220201d1815130f0b04000000000000000000000000000000000009141f29333b4246474c4c4c4c4c4c4c4c4c4c4a48443d352b2115202a343c4347494c4c4c4c4c4c4c4c4c4c4948433d352b21160a0000000000000000000000000000000000060b0f1213181c1f202223232322201f1c181312100c0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a2a2a2a2a29c908376695d5043362a1d1000000000000000000006121f2b3844505b6675828f9caab4baaea3988e81746d66646364696e7c87929facb9baaea3998a7d7164574a3e31241706000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003050608090a0a0a09070604010000000000000000000000000000000000000000000000000b17222d38414b555d666d737d83898f9299999a9b9c9d9c9b9a9999928f89837c726d635c52483f33291f14090000000005111e2a36414c56616c717d858a8d8d8c8781796d665c5144392e23180c0000000000000000000000000000000000000000000000000006121f2c3844505c667683909ca9b6c3beb9b8b9bbc0b2a5998c7f72665e697885929eabb8bdb9b8b9bdc4beb3aa988b7e7165584b3e2f24180d01000000000000000e1b2734414e5a6774818d9a9f9f9f9f9f988b7e7265584b3f3946535f6c7986929f9f9f9f9f9f94877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a48443e352c21160b000000000000000000000000000c18232e39434b515353535353535353535353514a42392e23180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010406070c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0a0907040000000000000000000000000000000000000000000000000000000000000004060708090a0909070604010000000000000000000000000000000000000000000000000000000000000000000000000000010406080d1113141617171717151413110d07070300000000000000000000000000000000000000020d17202930363a3b404040404040404040403d3c38332b231a0f18222a32373b3c404040404040404040403c3b38322b23190f04000000000000000000000000000000000000000305070c10121315161616151413100c070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a95959595959595908376695d5043362a1d10000000000000000000030f1c28333f4a5465717e8b98a2aebab4aa9d938d807973707071747b849199a3aebbb9ac9f92867a6d6154473a2e211407000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27333f49535d676d78808890959c9fa3aba7a8a9aaa9a8a7aba39f9c9590877f736e635a50453b31251a0e030000000714202d3946525e68717e8791979a9a9a938e82786d60544a4034281c10040000000000000000000000000000000000000000000000000713202d3a4653606d7985929facb8bbb3adabacafb6b4a89b8e817568616e7b8797a1adb9b2adabadb2bbc1b4a79a8e817467554b4135291d1104000000000000000e1b2734414e5a6774818d9aa7acacaca5988b7e7265584b3f3946535f6c7986929facacacaca194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3d3c38332c231a10050000000000000000000000000007121d2730394045464747474747474747474644403930271c120700000000000000000000000000000000000000000000000000000000000000000000000000000000000000030606090c0e0f101110100e0c0907060300000000000000000000000000000000000000000000000000000000000000000000000000020507080b0d0f1111121211100f0c0a0706040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001050707090a0b0a0a09070604010000000000000000000000000000000000000000000000050e171f252a2d2e33333333333333333333302f2c27211a1108101820262b2e2f33333333333333333333302f2c272119100700000000000000000000000000000000000000000000000004060708090a090807060400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707e8989898989898989898276695d5043362a1d10000000000000000000000b17222d3a4753606d7a85929fa8b2bcafa59d928d84807d7d7e81869196a0abb5bbafa59b8e8275685d5246392d201307000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000000000000305060706040000010000000000000000000000000000000000000000000000000000000104070709090807060300000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b656d79828d939aa0a7acaeb4b4b5b6b6b6b5b4b5aeaca7a099928c80736c62574d42362a1f14090000000814212e3b4754616e7a869299a1a9aca49f948c7f73665c5144382c1f12060000000000000000000000000000000000000000000000000916222f3c4955626f7c8898a2aebab3a9a19e9fa4acb6aa9d9184776764707d8a97a9b3b2a9a19ea1a9b2bdb7aa9d908477675d5145392c201306000000000000000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3946535f6c7986929facb9b9ada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b22292e313232323232323232323232323232323232323232323232323232323232302f2c28211a11080000000000000000000000000000000b151e272e34383a3a3a3a3a3a3a3a3a3a3a38342e271e150b000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b0f121316191b1c1d1d1d1c1b19161312100c0600000000000000000000000000000000000000000000000000000000000000000104090e111414181a1c1d1e1f1e1e1d1b19161413100c0704000000000000000000000000000000000000000001070b0f1112131313131313131313100f0d0a05000000000003070b0d0e1313131313131313131313090806030000000000000000000000000000000000000000000000000000020507080b0d0d0a070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050d141a1e2021262626262626262626262322201c160f0800070e151b1f21222626262626262626262623221f1b160f0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a7c7c7c7c7c7c7c7c7c7b6e6255483b2f221508000000000000000000000613202c3945515d6773808d96a1abb5b7aea49d96918d8a898b8e9298a0a8b2bcb3a99e93897c6f62564c4135291d1105000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000000000060b0f12131313100c070e0b08070502000000000000000000000000000000000000000002080d1113141616151312100b0606030000000000000000000000000000000000000000000000000000000005121e2a36424d57606c77828f949fa4acb1b9b9b4aeacaaa9aaacaeb4b9b9b1aba39f928b7e71695e53463b31261a0e0200000d1a2633404d596673808c98a2abb3b6afa69f9285786d6053463a2d2013070000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98aab4b9ada19792939aa4afac9f93867a6d66737f8c99a6b2ada1969196a1adb9b9ac9f93867a6d6054473a2d211407000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000911181d212425262626262626262626262626262626262626262626262626262626262423201c16100800000000000000000000000000000000030c151d23282c2d2d2d2d2d2d2d2d2d2d2d2c28231c150c0300000000000000000000000000000000000000000000000000000000000000000000000000000003090e11171c1f20222527292a2a2a29282623201f1c17110f0a0300000000000000000000000000000000000000000000000000000001080d11141a1e20212427292a2b2b2b2b2a282623201f1c1812100c070000000000000000000000000000000000050c12171b1d1e2020202020202020201d1c1916100a030001080e13171a1a20202020202020202020201615130f0a040000000000000000000000000000000000000000000002090e111414181a19171313100c0700000000000000000000000000000000000000000000000000000000000000000000000000000000010507070a0d0f1011100f0e0b08080602000000000000000000000000000000000000000000000000000002090e11141419191919191919191919171614100b05000000040a0f131516191919191919191919191615130f0a040000000000000000000000000000000000000000000000000000000000000004080c0e0f121212121212121210100d0a0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c3945525d686d6f6f6f6f6f6f6f6f6f6e6a5f53473a2e2114080000000000000000000004111d2935404b55606d7a849199a4afb5b6aea8a19e999796979b9fa3aab2bab3aaa1978e81756a6054443a3024190d01000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000000020a11171b1f20201f1c181d1b181514120e09030000000000000000000000000000000000040c13191d2021232221201f1c1715130f0a0400000000000000000000000000000000000000000000000000000714202d3a46525e69727f8c949ea6afb6bab2acaaa29f9d9c9d9fa3abadb3bbb5aea49f92867b6e61574d42362a1e12050000101d2a3643505d697683909caab4bdc0baada297887c6f6255493c2f221609000000000000000000000000000000000000000000000005111d2935414c566875818e9ba8b4b8ab9e928588939facafa499897c6f6875828f9ba8b5ab9e9185919ea9b3bbafa499897c706356493d30231609000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c1115171819191919191919191919191919191919191919191919191919191919171614100b05000000000000000000000000000000000000030b12181c1f20202020202020202020201f1c18120b03000000000000000000000000000000000000000000000000000000000000000000000000000002080d141a1c22282b2d2f323436363737363432302d2c28231c1a150e0802000000000000000000000000000000000000000000000000060c13191d20252a2d2e3134353738383837363533302d2c29231f1c18120b060000000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d292926211c150d040b131a1f2426272d2d2d2d2d2d2d2d2d2d2d22221f1b150f070000000000000000000000000000000000000000070c141a1e202125262624201f1c18120b0300000000000000000000000000000000000000000000000000000000000000000000000104080d111314171a1b1c1d1d1c1a181514120e09050100000000000000000000000000000000000000000000000000020507080d0d0d0d0d0d0d0d0d0d0a09070400000000000000030608090d0d0d0d0d0d0d0d0d0d090907030000000000000000000000000000000000000000000000000000000000000002090f14181b1b1e1e1e1e1e1e1e1e1d1c1a16110a0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c565d60626262626262626262625f584e43372b1f120600000000000000000000010d18242f3a45525d68707d87939fa3abb2b9b2adaba6a3a3a4a7acaeb4b8b1aaa29892857a6e61584e4332281e130800000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000000020b141b22272b2d2d2c282329272421201e1a140f0b060000000000000000000000000000040e161e24292c2d302f2e2d2b2823221f1b16100b05000000000000000000000000000000000000000000000004101c2834404a54616e7b86929fa6b0bbb8b0a8a09e9892908f9092999ea2a9b3bbbaaea3998e8174695f53463a2d2114070000111e2a3744515d6a7784909daab7c3c9beb3a996897d7063564a3d3023170a00000000000000000000000000000000000000000000000713202d3946525d687784919eaab7b5a89c8f8284919eaab5ab988b7e72687884919eabb5ab998d808d97a2adb9b5ab998c7f7266594c3f31251a0e020000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0a09070400000000000000000000000000000000000000000000070c1013131414141414141414141312100c07000000000000000000000000000000000000000000000000000000000000000000000000000000050c13191f262a2d3338393c3f414243444343413f3c3a38342e2b262019140d05000000000000000000000000000000000000000000030a11171e24292c30363a3b3e4042444445454443423f3d3a38342f2c28231c17110a020000000000000000000000050f1820282f3337383939393939393939393635322d261f160d141d242b30333439393939393939393939392f2e2b27201910070000000000000000000000000000000000030b12181f252a2d2e323333302d2c28231d150c08000000000000000000000000000000000000000000000000000000000000000001070d1113191d2021242728292a2a29272522211e1a15110d0802000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b131a202527282b2b2b2b2b2b2b2b2a2926221c150d040000000000000000000000000000000000000000010101000000000000000000000000000000000000000000000000010d1924303a444c525456565656565656565655534e463c31261a0f02000000000000000000000007131d2935414c56606b727f8b9299a1a8adb2b6b7b3b0b0b1b4b8b5b1aca79f9892867d6f685e52463d3220160c0200000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100000000a141d262d3337393a38342e3634312e2d2a251f1b17110a020000000000000000000000020c1620283035393a3c3c3b3a38342e2e2b27201c160c070100000000000000000000000000000000000000000006121f2c3844515c6673808d98a2aeb8bcb0a69f96918a86838384868b9297a1a9b3beb4ab9f93877b6e6155483b2e2215060000101c2936434f5c6976828f9ca9b3bdc0b9ada197887c6f6255483c2f22150900000000000000000000000000000000000000000000000714212e3a4754616d7a8796a0acb8b3a6998c80818e9ba8b4a79a8e81746d7a8796a1acafa399887c85929eabb8b5a89b8f827568574d42362a1e12050000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004060707070707070707070707060400000000000000000000000000000000000000000000000000000000000000000000000000000000080e171e252a3136383f4446494c4e4f5050504f4e4c4946443f3837312a251f170e0800000000000000000000000000000000000000050c151c23282f35393b4246474b4d4f5051525151504e4c494745403a38342e28221c140b05000000000000000000010c16202a323a3f434546464646464646464643423e3831281f0c1d262f363c3f4146464646464646464646463c3b37322b22190f04000000000000000000000000000000030c151d232830363a3b3e40403d3a38342e271e191108000000000000000000000000000000000000000000000000000000000000060b13181d20252a2d2e3133353637363634312f2e2b26201d19130d07010000000000000000000000000000000000000000000000000000000000000000030506080b0e0f1011100f0d0a070604010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b151d252c31343538383838383838383735322d271f160d0000000000000000000000000000030506090b0d0e0e0e0d0b090706030000000000000000000000000000000000000008131e28323a4145474949494949494949494847433c342a20150a000000000000000000000000010d19242f3a434f59626d727f8791969ea1a9a9abadb3b6afacaba9a7a09d9590867d706b60564c41342b200e040000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000006111b262f383f44464645404443413e3b3a36302b27221b140b060000000000000000000008131e28323a41454749494846443f3c3b38322c272118120b0300000000000000000000000000000000000000000713202d3a4653606d7985929eaab4beb4aa9f9490847e797776777a7e859197a1adb9bbafa4998b7f7265584c3f2d22170b00000c1926333f4c5966727f8c97a2abb2b5afa69e9185786c605346392d20130600000000000000000000000000000000000000000000000a1724303d4a5763707d8a96a8b2bdb3a9978a7d7f8c99a5b2aa9d908377707d8996a8b2ac9f928679828f9ca9b6b8ab9e918578695e53463a2d2114070000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000010407070a0b0c0d0d0d0c0b0a0807050200000000000000000000000000000000000000000000000000000000000000000000000406070a0d0e101011100f0e0b080705020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009111a202930363b42464a505355585a5c5d5d5d5c5b595653504a47433c363029201a120a0100000000000000000000000000000000060f171e262e343a4145474d5254575a5c5d5e5e5e5e5d5b595653514b46444039332d261d170e06000000000000000007121d28323c444b5051535353535353535353504e49423a3126151e2f3841474c4d53535353535353535353534947433c342b20150a0000000000000000000000000000030c151e272e343b4246474b4d4c4a46454039302b231a1208000000000000000000000000000000000000000000000000000000020a11171d24292c3036393a3d404243444342413e3b3a37312d29251e18130c040000000000000000000000000000000000000000000000000000000000060b0f121315181b1c1d1d1d1c1a171413110d080300000000000000000000000000000000000000000000000000000000000000000000000000000000000009131d272f373d4042454545454545454543423e3831281f10060000000000000000000000060b0f121315181a1b1b1b1a18161312100c060000000000000000000000000000000000020c1620283035393a3c3c3c3c3c3c3c3c3c3b3a37312a22180e030000000000000000000000000008131e28313d47515b626d727d848c91969a9d9ea2a9a1a49f9e9c9995908b837b706b60594f443b3022190f000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000000b17222d384149505353514b51504e4b4846423b37332d261d1810080000000000000000010d1924303a444c525456555453504a4947433d383329231d150d03000000000000000000000000000000000000000a1623303d495663707d8997a2adbcbaaea298908279716d6769676d717b85919eaab4bfb5ab9c8f82756953493f33271b0f03000714212d3a4754606d7a859299a1a8aba39f948b7f72665b5044382b1f120600000000000000000000000000000000000000000000030f1b27333f49536673808c99a6b3b9ada197877b7d8996a8b2ac9f928679727f8c98a5b2aa9d908477808d99a6b3b9ada197877b6e6154483b2e2115070000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000306080d111314161819191a1a1918171514120e090503000000000000000000000000000000000000000000000000000000000001070c10131417191b1d1d1d1d1c1a181514120e090400000000000000000000000000000000000000000000000000000002050708131313131313131313130b0b09050100000000000000000000000000000000000000000000000000000000000000000009121b232b323a41464d53545b6062656769696a6a69676563605c54534e46413b322c241c130a020000000000000000000000000000061018212930383f444c5254575e616467686a6b6b6b6a69686663605c5553514a443f382f2920180f06000000000000000b17232f3a444e565c5e6060606060606060605c5a544c42382d1d2730414a52585a606060606060606060606055544e463c32271b0f03000000000000000000000000000b151e27303940454d52545859595753514b423d352c241a0e0500000000000000000000000000000000000000000000000000050b141c22282f35393a4146474a4d4e4f50504f4d4b4847423c39353029241d160d080000000000000000000000000000000000000000000000000003090f11171b1f20222527292a2a2928262421201d19130f0b06000000000000000000000000000000000000000000000000000000000000000000000000000000040f1a252f3941484d4e5151515151515151504e4a433a3122180e040000000000000003090e11171b1f20222526272827272523201f1c17110f0a04000000000000000000000000000000040e161e24292c2d2f2f2f2f2f2f2f2f2f2f2e2b2620180f060000000000000000000000000000010c161f2b353f49515b626b70797f84898d90929794949a93918f8c88837e776e6960594f473d32291e1007000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1000030f1b27333f49535b60605c5f5e5c5a5754524d46443f382f2a221a11080000000000000004111d2935414c565d60636261605c5456544e48443d342f271f150d030000000000000000000000000000000000000d192633404c5966737f8c99a9b3aeaeab9f92867a6d67605c555d6069717e8a98a2aebab8ab9e918578655b5044372b1f1205000713202c3945525d68707d8791969a9a99928d82786c60544a3f33281c0f030000000000000000000000000000000000000000000005121f2b3744505b6576828f9ca9b5b8ab9e9285787a8796a1adaea398887b75818e9ba8b4a79b8e81747d8a97a9b3beb3a9978a7e7164574b3e2e23180c0000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000040a0f1315191d202123252526272626252321211e1a13120f0b0600000000000000000000000000000000000000000000000000040a0f12181c1f20232628292a2a2a29272521211e1a14100c07000000000000000000000000000000000000000000000003090e12141520202020202020202020181715110c060000000000000000000000000000000000000000000000000000000000000009121b242d353d444c52575f61666c6f7274757677767674726f6d66625f58524d443e362e251c140a00000000000000000000000000060f18222a333b424a50565d6065696e7173757777787877767572706d6764605c54504a423b332a21180f050000000000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c69665e54493e32232e3942525c64676c6c6c6c6c6c6c6c6c6c6c6260584e43372b1f130600000000000000000000000007121d273039434b51575e6165666663605c544f473e362c20170d020000000000000000000000000000000000000000000000070f171d262d333a4145474c5254575a5b5c5d5d5c5a5855534d4746413a352f281f1a11090100000000000000000000000000000000000000000002080e151a1b22272b2d2f3234353637363533312d2c29241f1c17110a02000000000000000000000000000000000000000000000000000000000000000000000000000814202c37414b53595b5e5e5e5e5e5e5e5e5d5b554c43342a20150a000000000001070d141a1b22272b2d2f313334343433322f2d2c28231c1b150d08020000000000000000000000000000040c13191d202123232323232323232322211f1a150e0600000000000000000000000000000000040d1a232d373f49515960676d72797d80838586878787868582807c77716c655f574f473d342b20170d00000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100005121f2b3744505b656c6d666c6b696764615e57535049413c342c231a10070000000000000713202c3945525d686d6f6f6e6d6667626058554f45403931271f150b0100000000000000000000000000000000000f1c2835424f5b6875828e9ba1a1a1a1a19a8d8074685e55514b5157606d7985929facb8b9ac9f9286786c605346392d2013060004111d2935414c56606b707d848a8d8d8c8780786d665b5042382d22170b00000000000000000000000000000000000000000000000613202d394653606c7985929fabb8b5a99c8f82767884919eabb4aa978b7e7784919daab2a5988b7f727b8897a2adbab3a79a8d807467544b4034281c100400000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000040b10151b1f2224292c2d3031323333333332302e2d2a25201f1b17110a0200000000000000000000000000000000000000000002080e151b1d23292c2d303335363737363534312e2d2a251f1c18120b030000000000000000000000000000000000000000060d141a1e21222d2d2d2d2d2d2d2d2d2d2524211d181109000000000000000000000000000000000000000000000000000000000007111b242d363f474f565e61696e74797c7f818283838382817f7c79746f6a615e56504840372e261c12090000000000000000000000030c18212a343c454d545c60686d72777b7e8082838485848483817f7c7975716d66605b544d453c332a21170d030000000000111d2a3743505c6872787979797979797979797670665a4e42352834404b54646e747979797979797979797979766a6054473b2e2215080000000000000000000000000c18232e39434b555c60696e717373706d66605950483e32291f14080000000000000000000000000000000000000000000007111921292f383f444b5154565e61646668696a69696764625f5754524c45413a312c231b130a0100000000000000000000000000000000000000050d141920262b2d3337393b3e414243444342403d3a39352f2b28221c140b080200000000000000000000000000000000000000000000000000000000000000000000000c1825313d48535d65686b6b6b6b6b6b6b6b6a665e55463c32261b0f03000000040c13181f262a2d3337393c3e40414141403e3c3a38342e2b262019130d05000000000000000000000000000002080d1113141616161616161616161514120f0a0300000000000000000000000000000000000008111b252d373f474f555d60666d707376787a7a7b7a797876736f6a64605b534d453d352b22190e0500000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000613202d394653606c77797979777674716e6964605b534e463e352c22190d0300000000000714212d3a4754606d7a7c7c7b7976736f6a636159514b433931271d12070000000000000000000000000000000000101d2a3643505d69768390949494949494948a7d7064564c454045515c667784919daab7bbaea399877a6d6054473a2d21140700010d19242f3a444f59606b70797d80807f7b746d665c544a3f2f261c110600000000000000000000000000000000000000000000000815222f3b4855626e7b8897a2adbab3a6998d807375828f9ba8b3a69a8d807986929facb2a896897c707885929fabb8b6a99d908376665c5145382c1f130600000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000001070c161b20272b2e2f35393a3d3e3f4040403f3e3d3b3a36312d2b27221b140b0800000000000000000000000000000000000000050d141920272b2f34383a3d40414343444342413e3b3a36312c28231d150c06000000000000000000000000000000000000060f181f262a2d2e3939393939393939393932312e29221b1209000000000000000000000000000000000000000000000000000000040e19232d363f48515960686d747b8084888b8d8f9090908f8e8c8985817c746e68615a524a40382e241b0f06000000000000000000000b151e29333c464e575e666d727a7f83878a8d8f9091919191908e8c8986827d79716c665e574e463c33291f150b0100000000121e2b3845515e6b78848686868686868686868276695c5043362c3845515c66748086868686868686868686867c6f6255493c2f221609000000000000000000000004101c2834404b555c676d747b7e807f7d79706b615a50443b3025190e020000000000000000000000000000000000000000071119232b333b424a50555d6065686d7073757677767574716e6966615e56514b433d352d251c130a000000000000000000000000000000000000080e171e252a3137383f4446484b4e4f5050504f4d4a4745413a38332d261d19140d05000000000000000000000000000000000000000000000000000000000000000000010e1b2734404d59656f757878787878787878767166584e43372b1f13060000060d161d24293136383f4446484b4d4e4e4e4d4b4946443f3837322a251e170e07000000000000000000000000000000010407070909090909090909090808060200000000000000000000000000000000000000000009131b252d353d434b51545c6063676a676d6e6e6d6d666966626058535049413c332b231910070000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000815212e3b4854616e7b8686858483817e7b76716c655f584f473e342b1f150b01000000000a1723303d4a5663707d8988878683807c77706b605c554b43392f23180c0500000000000000000000000000000000111e2a3744515d6a77838787878787878787877c6f6255493c404a54606a7884919eabb7baaea398877a6d6054473a2d211407000008131e28323d474f5960676d717374726e69605c544a42382d1d140a0000000000000000000000000000000000000000000000000b1825313e4b5864717e8b97a9b3beb4aa978a7e7173808c99a6b3a99c8f827c8999a3afaca096877a6d76838f9ca9b6b9ac9f9286796d6053463a2d20130700000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000030b121821272c32373b3c414547494b4c4c4d4d4c4b4a4846423d3937332d261d19110a0200000000000000000000000000000000070e171e252a3237394045474a4c4e505050504f4d4b4846423b38342e271e17110a02000000000000000000000000000000030d18212931363a3b464646464646464646463e3d3a342d241b110600000000000000000000000000000000000000000000000000020c16202b353f48515b626b707a81878d9197989a9c9c9d9d9c9a9897928e87817b716c635c524a40362d21180e03000000000000000007121c27303b454e585f696e787f858b9095979a9b9d9e9e9e9d9c9b9998928f8a847e786e695f584e453b31271d120700000000121e2b3845515e6b788491939393939393938f8376695c5043362d3a4653606d79859293939393939393939083776a6054473b2e221508000000000000000000000006131f2c3845515c676d7980868b8c8c8a847d706c61564d41362a1e110500000000000000000000000000000000000000060f19232b353d454d545b60676d72777a7d808182838382807e7b77736d68605d554f473f372e251c1208000000000000000000000000000000020a121a202930363c434749505355585a5c5d5d5c5b595754524c46443f382f2a251f170e060000000000000000000000000000000000000000000000000000000000000000020f1b2835424e5b687581848484848484848483766a5f53473b2e21150900060f181f282f353b42464950535558595a5b5a5a585653504a47433c36302920191007000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000109131b232b313940454a5053565a555d60616161605c545955544e46443f382f2a21191107000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000815212e3b4854616e7b879392918f8d8a87837e786f6a61594f463d31271d1207000000000a1723303d4a5663707d89959892908d89837d746d675c554b40342921160b000000000000000000000000000000000814212e3b4754616e7b7b7b7b7b7b7b7b7b7b786d605346424b515b666f7c8896a1adb9b8ac9f928579675d5145392c2013060000010c16202c353d474f555c6064676765615f57514a42392f261c0b02000000000000000000000000000000000000000000000004101d2935404b556774818d9aa7b4baaea298887b6e707d8a97a9b3ab9f92857e8b98abb5aa9e9184776873808d9aa6b3baaea398897c6f6256493c2f23160800000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000030d151d232932383d4347494c5254565858595a5959585654534d4a46443f382f2b231c140b020000000000000000000000000000081119202930363c43474b515356595b5c5d5d5d5c5a5854534d464540393027221b140b02000000000000000000000000000009141f29333b424648535353535353535353534b4a453f362d22180c0100000000000000000000000000000000000000000000000008131e28323d47505a626d727d858e93999ea1a9a7a8a9aaa9a9a7a9a29f9a938e857e736e645c52483f332a20150900000000000000000c18232e39424d575f6a6f7b838c92979da0a7a6a8aaaaababaaa9a8aaa29f9c96918b827b6e6a5f574d43392f23180c03000000121e2b3845515e6b7884919e9f9f9f9f9f9c8f8376695c50433636414c5664707d8a97a19f9f9f9f9fa2988b7e7165584e43372b1f13060000000000000000000004111d2935414c55606d79828d929999999691877e70685e5246392d201407000000000000000000000000000000000000020c18212b353d474f575e666c727a7f83878a8d8e8f90908f8d8b88847f7a736d67605951493f372e241a0e0500000000000000000000000000020b141c242c323b41464e53535b6062656768696a69686664605d5653504a423e3630292018100600000000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c91919191919191887c6f6255493c31261a0e060f18212a313a41454d53535b60626466676767666562605c54534e46413a322b221910070000000000000000000000000000000000010407070b0e0e0c080705020000000000000000000000000000000000000000000000010911191f272f35383f44464a4d4b515354545453514a4d4947433c37332d261d180f0700000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000815212e3b4854616e7b87949f9e9c9a9a93908a837c706b61584e43392f24180c000000000a1723303d4a5663707d8996a39f9d9a95908981796d675c51453d33271c10040000000000000000000000000000000714202d3a46525e696e6e6e6e6e6e6e6e6e6e6d665c51444d545c606c7882909ca8b2bdb7aa9d9084776a554c4135291d1104000000040d1a232c353d434b5153575a5a5955534d44403930271d140a00000000000000000000000000000000000000000000000006131f2c3945515d677783909daab7b8ab9f9285796c6e7b8797a1adada2978f828f9ca9b5a89b8f827568717e8a97a9b3beb4aa988b7f7265584c3f3025190d01000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000030c151f272f343d44484e5456565d60636465666666666563615e5757535049413d352e261d140b00000000000000000000000000081119232b323b41464e54555c60636668696a6a69686764615e5753514b433e332d261d140b02000000000000000000000000020e1a26313b454d535560606060606060606060585650483f34291d11050000000000000000000000000000000000000000000000010d1924303a444f59626c727f8792979fa4abadb2b4b5b6b6b6b5b4b3adaca49f97928a80736e645a50453c31261a0e0500000000000004101c2834404a545f696f7c8590959fa2a9acb1b3b5b6b7b8b7b7b6b4b4aeaca8a19e948f847c6e695e554b4034291f1409000000121e2b3845515e6b7884919eabacacaca99c8f8376695c5043363946525e6875828f9ba9b3acacacab9f92857a6d6053473c32271b0f03000000000000000000000613202c3945515d6773808d949fa3aba8a09992867b6e6154473b2e2114080000000000000000000000000000000000000a141e2a333d474f5960696e787f858c909597999b9c9d9c9c9a9795918c868079706b625b51493f362c20170d020000000000000000000000010b141d262e363e444c52585f62656c6e7174757677767573706d6864605b545046413b322a22181006000000000000000000000000000000000000000000000000000000000000000815222f3b4855626e7b88969e9e9e9e9e998c807366574d42372b1e120d18212a333c434b51575f61656c6f717374747473716f6d66625f58524c443d342b23190e05000000000000000000000000000002080d111314181a1b191514120e09030000000000000000000000000000000000000000000000070d151d24292e34383a3d40404547474847464440403c3b37322b27221b140b060000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000815212e3b4854616e7b8794a1aaa9aca49f9c9590867d706a60554b4035291d12070000000a1723303d4a5663707d8996a3aca9a7a09d938e82796d60594f44382c21160b00000000000000000000000000000005111e2a36424d565e61616161616161616161605c544a50575e666d75808d949fabbabcb1a79a8d8073675a4d402f24190d010000000008111a232b31394045474a4d4d4c4846423b342e271e150b020000000000000000000000000000000000000000000000000714202d3a4753606d7a86929facb9b6a99c90837665697885929eabb3a99f9386939facb2a6998c7f73666e7b8897a2adbab4a89b8e817568564c41362a1e1105000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000a151e27313940454f5458606267686d7071727373737271706e696863605b534f4740382f261d12080000000000000000000000061019232b353d444c52586062676d707374767677767574716e6965605c554f443f382f261d140a00000000000000000000000005121e2a36424d575f6c6c6c6c6c6c6c6c6c6c6c65625a50453a2e211509000000000000000000000000000000000000000000000005111d2935414c56606b717e8b9399a1a9afb5b9bec0bfbdbdbdbfc1bebab6afa9a29f928c80736d62574e42372b21160b00000000000006121f2c3844515c666e7b8591979fa7adb3b8bcc0bebab8b7b7b8babebfbab8b2ada69f9691857b6e675c51453b31261a0e000000121e2b3845515e6b7884919eabb7b9b6a99c8f8376695c5043363a4754616d7a86929facb9b9bcb1a79a8d8174675d5145392b20150a00000000000000000000000714212d3a4754606d7a86929fa6afb5b2aba2988c807366594d4033261a0d000000000000000000000000000000000006111c26303c454f59606b6f7b838b92979da0a7a6a8a9aaa9a8a7a7a09d98928d847d726d635b51483e32291f140800000000000000000000000a131d262f38404850565e616a6e74787b7e818283838382807d7a76716c66615a524d443c342a22180e050000000000000000000000000000000000000000000000000000000000000814212e3a47535f6a7784919eaaababaa9d918477695f53473a2e2114151f2a333c454d555d60696e74787b7e80818181807e7c79746f6a615e564e463d352b20170b02000000000000000000000000040c13191d20212527272521201e1a140b060000000000000000000000000000000000000000000000030b12181c23282c2d302f35393a3b3b3a3a38342e2f2e2b271f1b17110a02000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000815212e3b4854616e7b8794a1aeb6b6afaca7a09892867c6f675d5145392e23180c0000000a1723303d4a5663707d8996a3b0b6b1aba59d948e81746b6054483d32271b10040000000000000000000000000000020e1925303b444d525454545454545454545453514c525a61696e78818d929da6b0bcb8aca095897c6f6356493c302316080000000000000811191f272f34383a3e40413f3b3a363128231c150c03000000000000000000000000000000000000000000000000000a1623303d495663707c8999a3afbbb3a79a8d8074676976828f9ca9b5afa4999399a4afb3a9968a7d70636c7985929fabb8b7aa9e918477685e5246392d201307000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000006111c263039434b515960636a6f74777a7c7e7f7f80807f7e7d7b7875706c656059524a41382f241a0d04000000000000000000030c18222b353d474f565e616a6f75797d7f818383838382807e7b77716d676159504941382f261b110600000000000000000000000714212d3a46535f697679797979797979797979716c62564a3d3124170a00000000000000000000000000000000000000000000000713202d3946525d68707d87929fa4abb3bbc0bcb8b7b3b1b0b1b2b6b8bcc0bbb3ada49c928b7e716a5f53473d33271c10020000000004111d2935414c56606d78839097a1a9b1babebfbbb9b3adabaaaaabadb3b9bbbfbdb9b0a8a1979083796d60574d42362a1c11060000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504337434e5865727f8b99a3aebbc4b8ab9f95887c6f62554b403529190f0400000000000000000000000a1723303d4a5663707d8998a3aebbc0bdb4aa9c908376695d5043362a1d1003000000000000000000000000000000000b17232e38424d57606b707d8590959ea1a9acb1b3b4b5b6b6b5b3b1acaaa29f9691877f726d635a50443b3025190e0400000000000000000007101c252f38414a525a61686e757b8085888b8d8f90908f8e8c8a86827d78716c615e564e463c342a20160c02000000000000000000000000000000000000000000000000000000000006121f2b37434e586773808d9aa9b3b7aca095887b6e6255483b31251a1d27313c454d575f676d747b8085888b8c8d8e8d8d8b8985817c756d6860584f473d32291d140a0000000000000000000000090e161e24292c2d323434322e2d2a251f17110a020000000000000000000000000000000000000000000001070c11171c1f202324292c2d2e2e2e2d2c282322221f1b150f0b060000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10000815212e3b4854616e7b8794a1aeb7b9bbb9b1aaa2989184796d60554b4034281c100400000a1723303d4a5663707d8996a3b5babcb8afa69d93897d7063594f44382c20130700000000000000000000000000000009141f29323b424647484848484848484848464f565d606c717b838e939da4aeb8b9afa59d9083776b6054483b2f22150900000000000000070d151d23292c2d313434322e2d2a261f18120b0300000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c99abb5bfb4aa978b7e71646673808d99a6b3b5aba49fa4abb5ada197877b6e616576838f9ca9b6b9aca096877a6d6154473a2e211406000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000c17232e38424b555c606b70777c818486898b8b8c8d8c8c8b898785817d78706b645c524a41362c1f160c0100000000000000000b151e2a343d474f5960686e757c8185898c8e8f9090908f8d8b87837e79706b605b534941382d22170b02000000000000000000000815222e3b4855616e7b868686868686868686867e7165584b3e31261b0f0300000000000000000000000000000000000000000005121e2a36424d57616d7a849199a3afb5bdbfbab1acaaa6a4a3a4a5aaabb1b9bdbebaaea49f92867b6e62594f44382c1e1308000000000613202c3945525d68727f8c959fa9b3bbc3bdb5aeaca9a29f9d9e9fa2a9acaeb5bdc2bab2a9a0958d8073695f5346382e23170c0000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433a47535f6a7783909dabb5bfbeb3a99d9083766a5f53433a2f2418070000000000000000000000000b1824313e4b5764717e8a97aab4bfcac4b7aa9d9184776a5e5144372b1e110400000000000000000000000000000003101c28343f4a545f69707d8692979fa7adb3b8bcc0c1bfbebec0c0bcb8b4aea8a199938b7f726c61564d41362a20150a0000000000000000020b19222d37414a535c636c717a81878d9297989a9b9c9d9c9b9999928f8a847e756e685f584e463c32281e13080000000000000000000000000000000000000000000000000000000000020f1a26313c4956636f7c8997a1adb9b1a7998c7f7266574d42362a1e232f39434d575f696e7980878d919797999a9a9a999897928e88817a6f6a60594f443b2f261b11060000000000000000010a121b20283035393a3e41413f3b3a363028221c140b02000000000000000000000000000000000000000000000000060c10121317181d1f20212121201f1c181615130f0a0300000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0b9b6a99c908376695d5043362a1d10000815212e3b4854616e7b8794aba5aaacb2babcb4aaa1968c8073675c5145382c1f130600000a1723303d4a5663707d8996a3abaeb4bcb8afa59d9083776b6054483b2f221609000000000000000000000000000000020d17202930363a3b3b3b3b3b3b3b3d434b515961686d757e8590959ea5aeb6bab1a79d93897d7063594f44382c2013070000000000000000030b12181c1f202427272622211e1a140c0700000000000000000000000000000000000000000000000000000005121e2a36424d576875828f9ba8b5baaea398887b6f6264717d8a97aab3bdb5afacafb5b8ab9e928578695e6773808d9aa6b3bdb2a8968a7d7063574a3d2d22170b000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000003101c28343f4a545c676d747d83898d91939a979899999999989697918e8a847d736e645c52483e31281d13070000000000000007121c27303c464f59606b6f7a81888e9298999b9c9d9d9c9b9a9795908b847d736c655b53493f33271d140a000000000000000000000714212d3a46535f69778491939393939393938e817568584e43372b1f12060000000000000000000000000000000000000000000714212d3a46535e6974808d96a1abb5c0bcb4aea7a09d99979697999d9fa7acb2babfbaaea2988f82766b6054483a3024190d010000000714212d3a4754606d7a85929fa7b1bbc4bcb4aba39f9a9792919192979a9fa3abb4bcc4bbb1a79f92877b6e61544a3f34281c100300121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433f4a54626f7b8895a0abbdc6baada2978b7e7165584e4331281d13070000000000000000000000000a1623303d495663707c8998a2aebac0bdb3a99c8f8376695c504336291d100300000000000000000000000000000006121f2b3844505c666e7b859298a1a9b1b9bebfbab8b4b2b1b2b3b7b9bdbfbab2aba49f93887e70685e52463c32261b0f01000000000000000a141d2b343f49535c646e737e858e93999ea1a9a7a8a9aaa9a8aba39f9c96918a827a6f6a5f584e443a3025190d0500000000000000000000000000000000000000000000000000000000000a13202d3a4653606d7985929eabb8b6aa9d908377695e53463a2d212934404b555f696e7b848d92999ea1a9a6a7a7a7a6a9a29f9a938e847c6f6b60564c41382d22170b00000000000000000a131c242d323a4145474b4d4e4c4846423b332d261d140a0000000000000000000000000000000000000000000000000000030607070c1013141415141312100c07080603000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3adadada99c908376695d5043362a1d10000815212e3b4854616e7b879995999ea0a8b0b8bcb2a89e9285796d6053463a2d20130700000a1723303d4a5663707d8992999fa3aab4bfb8aca095897c706356493d31261a0e02000000000000000000000000000000050e171f252a2d2e2e2e2e2f383f444f555d606b707a818a92979fa7afb7b9b1a8a0958e81746b6054473d32271b0f0300000000000000000001070c101314171a1a191514120e0903000000000000000000000000000000000000000000000000000000000714212d3a46535e697885919eabb8b8ac9f9286796d60616e7b8898a2aebac0bbb9bbc0b5a99c8f8276695764717e8a97aab3beb3a6998d807366544a3f33281c0f030000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000030e18212c3844505c666d79818890959a9e9fa4aca5a6a6a6a5a4a9a19e9b96918980746e645a50433a2f24180d010000000000000c18232e39424e58606b707d858e939b9fa2aaa7a9a9aaa9a8a7a79f9d96918a80776c655b50443d2f261c110600000000000000000005121e2a36424d576774818e9a9f9f9f9f9f9e9185786a5f53473a2e2115060000000000000000000000000000000000000000030f1b27333f4953616e7b86929fa9b2bdbdb4aaa29f95908c8a8a8a8c90959ea1a8b2bcbfb4aa9f94897d7063564c4135291d1105000005111e2a36414d5665727f8b98a2aeb9c3bfb4aaa299928d8885848485888d9299a2aab4bfc3bbafa3998d8174665c5044382c1f120600121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504344505c6673808d9aa7b1bcc5b8ab9f9285796d6053473c3220160c010000000000000000000000000714202d3a4753606d7985929fa6afb5b2aba2978c7f7266594c3f3326190c00000000000000000000000000000004101c2934404b55606d78839097a2aab3bbc0bcb4aeaca8a6a4a5a7aaacb2babfbdb5afa49a92867b6e61584e43372b1e130800000000000006111c262f3d46515b646e74808a92979fa4abadb3b4b5b6b6b6b5b4aeaca8a09e948f847c6f6a5f564c41362a21160b000000000000000000000000000000000000000000000000000000000006121f2b3844505c6674818e9baab4b8ab9f95877b6e6154483b30252c3845515c676e7b8591969fa3abadb3b3b4b4b4b3b3adaba59e9691867d6f685e53493f33271b110600000000000007101c252e363f444c5254585a5a5854524d443f382f261c11060000000000000000000000000000000000000000000000000000000000000406070808070706040000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a0a0a0a0a09c908376695d5043362a1d10000815212e3b4854616e7b8786888c91969fa6b0bdb9ada2978a7e7164574a3e2f23180c00000916232f3c4956626f7c84868b9298a3aebabcb1a79a8e817467574d42372b1e120600000000000000000000000000000000050d14191e20212129313a424a505960676d747d848e939fa2a9b1b9bbb0a7a0969083796d60594f44352b21160b000000000000000000000000000406070b0d0e0c080705020000000000000000000000000000000000000000000000000000000000000815212e3b4854616e7b8796a1adb9b6a99d908376665c606c7985929fabb8c5c7c6c7c0b3a6998d8073665a626e7b8898a2aebab6a99c8f8376665b5044382b1f12060000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000009151f2c38434f59606d78828d939aa0a7aaacafb6b2b2b1b2b2b1b2adaba8a09d928d80746c61554b4035291d1104000000000004101c2834404a545f6a707d8691979ea5acaeb4b4b6b6b6b6b5b3b1aba8a09e928d81776c60594f42382d22170b000000000000000000020e1a26313e4b5764717e8a9aa4afacacada197887b6f6255483c2e23170b000000000000000000000000000000000000000005121f2b3744505b6573808d99a3afbbc0b5aba298928a83807e7d7e7f83899196a1a9b3bebcb0a69c8f8275685d5246392d20130700000714202d3946525e687783909daab3bec6baaea2989287807c787777787c80879298a2aebac5c0b5ab9e9285796d6053463a2d20130700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50434653606d7984919eabb8c3bcb1a79a8d8074675d5145392c1f13040000000000000000000000000006131f2c3845515c6773808c949fa3aba8a19992857a6d6154473a2e21140700000000000000000000000000000006131f2c3845515c67727f8b95a0a9b3bcbeb6aeaaa29f9b9998989a9ea0a8aeb4bcc0b6aca2988e81756a5f53473a2f24190d0100000000000b17222d38424e58636d74808d929fa2a9afb5b9bec0c0bebebfc1bfbab9b2aca69e9691857c6f685e52463e33281c10050000000000000000000000000000000000000000000000000000000003101c28343f4a5464707d8a98a2aebab1a7988b7f7265564c41362b37434e58606d79839097a0a8afb5b9b7b6b2b1b2b5b9bab8afa9a19892857a6e655b5044382d22170b0000000000040f19222e373f4850565d6065676765615e57504a42382d22170b0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a93939393939393908376695d5043362a1d10000714212d3a46535e696e797a7c7f848f949fabb5beb3a99a8e817467554b4034291c1004000815222e3b4754606a6f777a7f86929fa7b1bcb8ab9e928578695f53473a2d211408000000000000000000000000000000000002090e11172129323b434c545b606b6f79818a91969ea5adb3bbb5afa69e9590847b6e675d51473d3323190f040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313e4a5764717d8a97a9b2bdb4a79a8e817467545b657683909ca9b6c3cfd2cabfb4aa978a7e716457606c7985929fabb8b8ab9f9285796c605346392d2013060000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000020e1a26313b4854606b74818e949fa4acb1b7b2adaba7a5a4a5a7abadb3b8b2aca49d928a7e71675d5145392c201409000000000006121f2c3844515c666f7c869298a1a9afb8bab9b7b3b0b0b1b5b9bbb8b2aca49c938c80736b60544a3f33281c0f030000000000000000000914212e3a4754616d7a87939facb9beb3a9988b7f7265544a3f34281c1003000000000000000000000000000000000000000613202d394653606c7884919eabb5c0bbafa49992867e787371707172777c849197a2adbac2b9ac9f92867a6d6154473a2e21140700000814212e3b4754616e7b87959fabbcc5bdb2a89f92867d746f6a6a6b6a6f747d86929fa9b3bec7b9ada297887c6f6255493c2f22160900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50414c5663707d8997a1adb9c4b7ab9f95887c6f62554b4035291d10040000000000000000000000000004101c2934404b55606d78828d92999a9a9691877d70685d5246392d2013070000000000000000000000000000000714202d3a4753606d7985929ea7b1bcbeb5aca49d98928e8c8b8b8d91969fa2aab4bcbeb4aa9e93887c6f62554c4135291d110400000000030f1c28333f4a54606a727f8c929ca4adb3bbc0bdb8b7b3b1b1b2b5b9babfbdb8b0a8a19791847a6d61594f44382c21160b00000000000000000000000000000000000000000000000000000000000b17232e3a4753606d7985929facb8b6a99c908376685e5246392e3b4754606a74808d95a0a9b2bbbab0aba9a6a4a5a8acaeb4bbb2aaa1978f82776c6053493f33271b0f03000000000a16202b343f49515a62686d717474726e69605b544a3f332822170c01000000000000000000000000000000000000000000000000000000010507070a0b0d0d0d0d0c0b060603000000000000000000000000000000000000000000000000000a1724313d4a5764707e8686868686868686868276695d5043362a1d100005121e2a36424d575e61676d6f7279828f99a4afbbb7aa9d918477675c5145382c1f13060006131f2b37434e586062676d727e8a95a0abb8b9ada197887b6e6155483b2e221508000000000000000000000000000000000000030c162029333b444c565d666c737c848e929ea1a9afbabbb2aba39f948f837b6e695e554b40352b21110700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404a546773808d9aa6b3c0b5ab988b7e726558536774808d9aa7b3c0d0d3c6baaea298887b6e62555b657683909ca9b6baaea298887b6f6255483c2f2215070000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000006121e2b37424d57636f7c89939da6afb6b6aea9a19e9a9898989b9fa2a9afb7b8aea49e9285796d6053473b31261a0e0200000004101c2934404b55606d78839098a2aab3bbbab2acaba6a4a3a5a8acafb6beb9aea59f93887d6f665b5044382b1f14090000000000000000000713202d3946525e687783909daab7c2b5a89b8f8275665c5044382b1f1206000000000000000000000000000000000000000916232f3c4956626f7c8997a1adbdc6b9ac9f93877d716c65646364666b6f7b85929fabb4bfbbafa3998a7e7164574b3e3124180700000a1724313d4a5764707e8a97a7b1bcc5b9ada1968b7e726b625f58585f626b727f8b97a1adb9c6beb3a9988b7e7265584b3f3225180c00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5045525d6875818e9ba9b2bebeb3a99d9083766a5f5343392f24180c0000000000000000000000000000000c18232f3944505c666d7880878c8d8d8a847d706b61564c4135291d1105000000000000000000000000000005111e2a36414c5665717e8b97a1adb9c2b8aca39b928d86817f7e7f80848b9298a2aab4bfbcafa59b8e8174675d5145392c2013060000000006121f2b3844505b666f7c87929fa4aebabebfbab2acaaa6a5a4a5a8acaeb4bcc1bab2a9a1968f82756b6155483d33271c10000000000000000000000000000000000000000000000000000000000006131f2c3845515c6775828e9babb4b9ac9f93867a6d6154473a36414c56626f7c87939fa7b1bbb4aea69f9c9998989b9fa3abb2bab3a99f948b7e71655b5044372b1f1205000000030f1b27323d46515b636c717a7e80817f7b736c665b50443f34291d11020000000000000000000000000000000000000000000000000205080d1113141618191a1a19191813120f0b0600000000000000000000000000000000000000000000000713202d3a4653606d787a7a7a7a7a7a7a7a7a7a6d6053473a2d20140700020e1a25313b454d53555d6062676e7b87939facb9b9ac9f93867a6d6053473a2d20140700030f1b27323d464e54555d606c7783909daab6beb3a9978a7d7164574a3e3124170b0000000000000000000000000000000000000a151e28323b454d565e686d787f8791969da5adb2bbb6afa8a099928c827a6e695e574d43392f23190f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844515c667683909ca9b6bbafa399897c6f62565864717e8b97aab4bfcbd2c5b8ac9f9285796c6053536773808d9aa6b3beb4aa988b7e7165584b3e2f24180d0100000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000814212e3a47535f697683909ca5afbbb7aea49c97918d8b8b8c8e92979ea5afb9b9ada2978c7f7265574d42362a1e120500000006131f2c3845515c67727f8c95a0aab3bcb6aea8a19e999797989c9fa4acb2bbbbafa49a9183786c6053463b30251a0e02000000000000000005111d2a36414c566773808d9aabb5bfb8ab9f9285796d6053463a2d201307000000000000000000000000000000000000000c1926323f4c5965727f8c98a9b2bebfb4aa9a8e81746b605b535757596069727f8c99a3aebac0b5ab9a8d8073675a4d402e23180c00000d1a2633404d596673808c99a6b3bfc4b8ab9e9184786c6059534e4e5359606d7985929eabb8c5c1b4a79b8e8174685b4e4135281b0e00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504754606d7a86929facb8c4baada2978b7e7164584e4331271d120700000000000000000000000000000007121d28343f4a545c666d747b7f80807d79706b61594f443a3024190d0100000000000000000000000000000714202d3946525e687683909ca9b3bebbb0a69b918b807a7573717274787e869298a2aebac1b8ac9f92867a6d6054473a2d211407000000000613202d394653606c78839099a3afb6c0bcb4aea8a09e9a9897999b9fa3aaafb7c0bbb2a89e938a7d7063594f44382c1d12070000000000000000000000000000000000000000000000000000000004101c2934404b5564717e8a99a3aebaafa4998b7e7165564c413946525e6875818e9aa4afb9b4aaa29f94908c8b8c8e9299a0a8b2bbb0a69d9184786c605346392d20130900000006131f2b38434e58636d727e858b8d8d8b8680786c605a5045392d1f14090000000000000000000000000000000000000000000002090e1214191d20212325262727262525201f1c17110a0200000000000000000000000000000000000000000006121f2b3844505c666d6d6d6d6d6d6d6d6d6d6d675d5145382c1f1306000009141f29333b42464b5153555f697784909daab7bbafa49a887b6e6255483b2f22150800000a16202b343d43474c515a6673808d99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000006111c26303a444d575e686e7a828c9299a0a8afb9bbb2aca49f9691877f776d685e574d453b31281d1108000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7986929facb8b9ac9f9286796d605355626f7b8898a3aebac7d0c3b6a99d908376665b505764717e8a97aab4bfb4a79a8e817467554b4135291d110400000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000815222f3b4855626e7b88949fabb7baaea49c928c84817f7e7f81858e939ea6b0bcb3a99d908477695f53463a2d2114070000000714202d3a4753606d7985929ea7b1bcb6aea49c96918d8a8a8b8f939aa1a9b2bcb6aca0958a7e7164574d42362a1e12050000000000000000010d1925303d4a5763707d8a99a3aebbbaada297897c6f6256493c2e23180c000000000000000000000000000000000000000f1b2835424e5b6875818e9ba8b4c1baaea298897c6f635950494a4b4f57606d7a86929facb9c3b6a99c90837669544b4034281c1004000e1b2835414e5b6874818e9ba7b4c1c0b3a79a8d8074665b5047434347505c6674818e9aa7b4c1c2b5a99c8f8276695c4f4336291c1000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504d5765717e8b98a3aebac5b8ab9f9285796d6053473c3120150b01000000000000000000000000000000010c17232e38424b545c60696e727473716d6760594f473e32281e13080000000000000000000000000000000814212e3b4754616e7a86939facb9c5b7aa9f948b7e736d68666565666c717d86929fa8b2bdbaaea3988a7d7164574a3e2e23180c00000005121e2a36424d5764707d8a959fabb5c0bbb3aaa29f96918d8b8b8c8f92989ea5aeb6c0baafa59d9083776b605448392e23180c00000000000000000000000000000000000000000000000000000000000c18232f3a4754606d7a86929facb9b5ab9c8f8276685d52453b4754616e7a86929facb6baaea298928a837f7e7f82869196a0abb5b8aca095897d7063564a3d30251a0e0200000815222e3b4754606a727f8b92979a9a99928c81746c6256493b30251a0e020000000000000000000000000000000000000000070c141a1e20252a2d2e30323333333332322d2b28221c140b02000000000000000000000000000000000000000003101c28343f4a545c60606060606060606060605d554b4035291d10040000030d17212931363a4045474d576875818e9ba8b4c0b6ac96897d7063564a3d3023170a0000040f19222b32373a414b5865717e8b98a4b1beb4a79a8d8174675a4e4134271b0e01000000000000000000000000000000000c17232e38424c565e696e7a838f949fa3abb2bab6afa8a09a938d847c726c655d564d453b33291f160c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8898a3aebab7aa9d908477675c5153606d7986929facb8c5cdc0b4a79a8d817467544a55626e7b8898a2aebab7aa9d908477675d5145392c20130600000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000c1925323f4c5865727f8b98a6b0b4b4a99d928c807974727172747a818e949fabb7b8aca095887b6e6155483b2e221508000003101c28343f4a5464717e8a97a1adb9bbaea49c928c84807d7d7e82879196a1aab4beb1a79c908376695e52463a2d2014070000000000000000000814202d3a4753606d7a86929facb9beb3a9998c7f7266544b4034281c1004000000000000000000000000000000000000101d2a3643505d697683909ca9b6c3b8ac9f9285796c6053463f3d3e45515d677683909ca9b6c3b8ab9f928578665c5145382c1f1306000f1c2936424f5c6975828f9ca8b5c2bdb1a4978a7e7164544a3f37373f4a5465727e8b98a5b1bec3b6aa9d9083776a5d5044372a1d1100121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50535f697683909caab4bfbcb0a69a8d8074675d5145382c1f1303000000000000000000000000000000000006111c263039424b51575f6165676764605d554f473e352c20160c020000000000000000000000000000000b1724313e4a5764717e8a99a4afbbbeb3a99c8f82766c605d5658545b606b727f8b96a1adb9bfb4aa9b8e817468544b4034281c100400000714212d3a46535e697683909ca7b1bdbeb3a9a298928a84807e7e7f82868e939ca4aeb9c1b8aca095897d7063544b4034281c1004000000000000000000000000000000000000000000000000000000000713202c3945515d6775828f9cabb5b9ac9f92867a6d6054473f4b5865727e8b99a3aebeb1a79f92867d76737172757b849199a3aebbb1a79b8e817568574d42362a1e120500000916232f3c4956626f7c87939fa2a9aba39f938b7e7165574d42362a1e1105000000000000000000000000000000000000030b12181f252a2d3036393a3d3e404040403f3e3938332d261d140a0000000000000000000000000000000000000000000b17232e38424a505353535353535353535353514b43392f24180c00000000050f171f252a2f3539414e5a6774818d9aa7b4bdb0a4978a7d7164574a3e3124170b00000007101920272b2f3e4a5764717d8a97a4b0bdb5a89b8f8275685c4f4235291c0f0200000000000000000000000000000003101c28343f4a545d686e7b8490959ea6afb5bab2aca49f96918880796f6a605b534c433b332921170d0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1925323f4c5865727f8b98aab4bfb4a79b8e817468554b505c667683909da9b6c3cbc0b5ab988b7e7165584b53606c7985929facb8b9ac9f93867a6d6054473a2d21140700000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800020f1c2935424f5c6875828f9ba7a7a7a7a89a8d81746d66656565676d7883909cabb5bcb1a7978b7e7164584b3e3125180b000006121f2c3844505c6675828f9ca9b3beb3a99d928c807973717072757c849198a2aebab7ab9f94877b6e6154483b2e2115080000000000000000000613202c3945515d677683909ca9b6c2b5a99c8f8276665c5145382c1f1306000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c3b6aa9d908377655b5044372d35414c556774808d9aa7b3c0baaea29886796d6053463a2d20130700101d293643505c6976838f9ca9b6c2bbafa295887c6f6255493c2d2e3d495663707c8996a3afbcc4b7aa9e9184776b5e5144382b1e1100121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c4953616e7b88949fabbcc6b7ab9f94887b6e62554b4035291d10040000000000000000000000000000000000000a151e27303940454f5961636464605d564c433d352c231a0e04000000000000000000000000000000000e1a2734414d5a6774808d9aabb5c0b9ada297897c6f635a524c4b4a5059606d7984919eabb8c3b7aa9d908477665c5145382c1f130600000815212e3b4854616e7b87949fabb9c3baada29792867e7773727172757a818d929ca7b1bcbcb1a79b8e8275665c5145382c1f13060000000000000000000000000000000000000000000000000000000004111d2935414c5565717e8b99a3afbbaea3998a7e7164554b414c556875818e9babb4b8aca0958a7e716b6665656a6e7c87929facb9b7ab9e918478695e52463a2d20140700030f1c28333f4a546875828f9aa4adb3b4aea59e918477695e52463a2d2014070000000000000000000000000000000000040c151d232830363a3b414647494b4c4d4d4c4c4b46443f382f261c1106000000000000000000000000000000000000000006111c2630383f44464747474747474747474745403931271d12070000000000050d141a1d242934404d5a6773808d9aa6b3beb1a4978b7e7164584b3e3125180b00000000070f161b24313d4a5764707d8a97a3b0bdb5a99c8f8276695c4f4336291c10030000000000000000000000000000020d17212c3844505c666d7a849196a0a7b0bbb7afa8a19a938d847d746d6760585049413a312921170f0a040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d2935414c566875818e9ba8b4c0b6ac988b7f7265584c4a546774818d9aa7b4c0c7bbafa399887c6f625549505b667683909ca9b6bbafa499897d706356493d3023160900000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080004101d2a3743505d6a7683909a9a9a9a9a9a96877b6e615c5458555d66707d8a99a4afbbb3a69a8d8073675a4d4034271a0600000713202d3a4653606d7985929facb8b9ada2978d80736d666464656b6f7c86929facb8bcb0a6988b7e7165584b3e3225180b00000000000000000004101d2935404b5566737f8c99aab4beb8ac9f9286796d6053463a2d201307000000000000000000000000000000000000121f2c3845525f6b7885929eabb8c2b5a89b8f82756853493f33272f3f4c5966727f8c99a5b2bfbeb3aa94877a6e6154473b2e21140800101d2a3643505d697683909ca9b6c3baaea194877b6e6154483b2e2f3c4855626f7b8895a2aebbc4b7ab9e9184786b5e5145382b1e1200121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c505b6573808c99a6b0bcbeb3a99c9083766a5f5343392f24180c00000000000000000000000000000000000000030c151e2935404b55616b7071716d685d5245392c231a11080000000000000000000000000000000000101c2936434f5c6976828f9ca9b5c2b8ab9e9285796c605346413e3f44505c6674818e9ba7b4c1b9ac9f9286796d6053463a2d20130700000c1925323f4c5865727f8b98a6b0bbbeb3a99f92857c716c67656466686e75808d95a0acb8c3b8ab9f9285796d6053463a2d20130700000000000000000000000000000000000000000000000000000000010d19242f3a4754616d7a86929facb9b5ab9b8f8275675d5145515d677784919eaab7b7aa9d9083776c615958575f6a74818e9ba7b4b9ada196877b6e6154483b2e2115080006121f2b3844505b667885929facb6bebfb9aca096877b6e6154473b2e21140800000000000000000000000000000000040d161e272e343b4246484c52545658595a5a59585853504a42382d22170b0000000000000000000000000000000000000000000a141e262e34383a3a3a3a3a3a3a3a3a3a3a38352f271f150b0100000000000003090e13182734404d5a6773808d9aa6b3beb1a5988b7e7265584b3f3225180c0000000000040a1724313d4a5764707d8a97a3b0bdb6a99c8f8376695c504336291d1003000000000000000000000000000009141f2a36424d57606d78828f96a0a8b1b9b6ada59e9691888079706b605d554e443f382f2823221f1b150f070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3946525e687784919eaab7bbafa49a897c6f6356494b5865727e8b98abb5c0c5b9ac9f9286796d6053474a546774808d9aa7b3c0b5ab998c7f7266594c3f31261a0e02000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080005111e2b3844515e6b77848d8d8d8d8d8d8d8d8477695e524a4b4c54606d7a86939facb9b5a99c8f8276695c4f432d22170b00000915222f3c4855626f7b8898a2aebab8ab9e9285796d605c545759606a73808d9aa6b3c0b4a79a8e8174675b4e4134281b06000000000000000000010d18242f3c4956636f7c8998a2aebabaaea298897c706356493d2f24180d010000000000000000000000000000000000121f2c3945525f6c7885929fabb8c1b4a79b8e8174685b4e412d22323f4b5865727e8b98a5b1bebbaea195887b6e6255483b2f22150800101d2a3643505d697683909ca9b6c3baada094877a6d6154473a2e2e3b4854616e7b8794a1aebac4b7ab9e9184786b5e5145382b1e1200121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c53606c7884919eaab7c2b9ada2978a7e7164584e4331271d120700000000000000000000000000000000000000000613202c3945515d67707d7e7e7a6d6054473a2d211407000000000000000000000000000000000000111e2b3744515e6a7784919daab7c2b5a99c8f8276665b5044382f343f4a5465727f8c98a5b2bfbbaea399877b6e6154483b2e2115080005111d2a36414c566975828f9ca8b5c2b9ada1978c7f726a615a5858565e616d7883909daab7c3baaea298897d7063564a3d3023170a00000000000000000000000000000000000000000000000000000000000813202d3946525e6876838f9cacb6b8ac9f9286796d60534754606d7a8796a0acb9b3a6998c8073665a504b4e5764707d8a97a3b0bdb2a8978a7d7064574a3d3124170a000613202d394653606c798697a1adb9c7c8bcb1a795887b6f6255483c2f221509000000000000000000000000000000020b161f28303940454d5254565e616365666666666565605b544a3f33281c0f030000000000000000000000000000000000000000020c141c23282b2d2d2d2d2d2d2d2d2d2d2d2c29241d150d0300000000000000000001071a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000020e1a25303a46535f69737f8c949fa8b2bab5ada49c938e847d746d676059514b433d332d30302f2e2b272019100700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212e3a4754616d7a8796a0acb9b9ac9f93867a6d6054474956626f7c8999a3afbbc3b7aa9d908477675c51454b5764717e8a97aab4bfb5a89c8f827569574d42362a1e1205000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800010d1a2734404d5a67738081818181818181817f7266574d423e45515d677885929fabb8b7aa9d9084776a53493f33271b0f03000b1824313e4b5764717e8a97aab4bfb4a89b8e8175675d514a4a4f58636f7c8996abb5c0b6a99d9083766a5d50432d22170b000000000000000000000713202d3a4653606d7985929fabb8bfb4aa998c807366554b4035291d11040000000000000000000000000000000000121f2c3945525f6c7885929fabb8c1b4a79a8e8174675b4e413428313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800101c2936434f5c6976828f9ca9b5c2baada093877a6d6054473a2d2e3b4754616e7a8794a1adbac4b7aa9d9184776a5e5144372b1e1100121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5563707c8996a0acb9c5b8ab9e9285796d6053473c3120150b0100000000000000000000000000000000000000000714202d3a4753606d79878a887c6f6255493c2f221609000000000000000000000000000000000000121f2c3845525f6b7885929eabb8c1b4a79b8e817468544a3f33282e3e4a5764717d8a97a4b0bdbfb5ab95887c6f6255483c2f221509000713202d3946525e687885929eabb8c5b8ab9e9285796d6058504b4b4c525c66717e8b97a8b2bdbeb4aa998c7f7266594c3f3326190c000000000000000000000000000000000000000000000000000000000005111d2a36414c5665727f8b9aa4afbaaea2988a7d7064544b55616e7b8894a8b2bdb0a3978a7d7064574a3e4854616e7b8794aab4bfb1a4988b7e7165584b3e3225180b0006121f2b3844505b667885929eabb5bebfb8aca095877a6d6154473a2e2114070000000000000000000000000000000a141d28313a434b51575e6166686d70717373737372716c665b5044382b1f1206000000000000000000000000000000000000000000020a11171c1f20202020202020202020201f1d18120b0300000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000005121e2a36424d57616e7b86929fa6b0bab7ada39c928c817a706b605d554f45403d3d3d3d3d3d3c3b37322b22190f04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724303d4a5763707d8a96a8b2bdb7aa9e918477675d51454653606d7986929facb9bfb4a79b8e817468554b404855626e7b8898a2aebab8ab9e928578695f53463a2d211407000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000d1926333f4c58646e737474747474747474726d63574d4a47464b556b7885919eabb8b8ab9e928578655b5044372b1f1205000c1926323f4c5965727f8c98a5b2bfb2a5998c7f7266554b403d4754606d7a8799a4afbbb7ab9e9184786b5e493f33271b0f0300000000000000000006121f2c3844505c6675828f9ca8b5c2b6a99c908376675d5145392c2013060000000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000f1c2935424f5c6875828f9ba8b5c2baada194877a6e6154473b2e2f3b4855626e7b8895a1aebbc3b6a99d9083766a5d5043372a1d1000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5d6774818e9ba8b2bdbbb0a69a8d8073675c5145382c1f13030000000000000000000000000000000000000000000a1724303d4a5763707d8a99897c706356493d30231608000000000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e412d22303d4a5763707d8a96a3b0b5b5afa296897c6f6356493c30231609000714212e3a4754616d7a8797a1adb9c1b5a89b8e8275675c51463f3e414a54616e7a8796a0acb9c1b4a89b8e8175685b4e4235281b0f0000000000000000000000000000000000000000000000000000000000010d1925303b4754616e7b87939facb9b4aa9b8e8175665c5155626f7c8895a2afbbafa295897c6f6256493c4653606d798698a2aebab2a5998c7f7266594c3f3326190c00030f1c28333f4a546875818e99a3adb3b4aea49d908377685e5246392d201307000000000000000000000000000006111b262f3a434c555c60696e73777a7d7e7f80807f7f7e786c605346392d2013060000000000000000000000000000000000000000000000060b1012131414141414141414141413100c07010000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000714202d3a46525e6975828e98a3aeb8bbafa59c918c7f756d686059514b4a4a4a4a4a4a4a4a4a4947433d342b20150a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27333f49536673808c99a6b2b2b2a89b8e827568554b4145515c677784909daab2b2b2a5988c7f7265594c3f4653606c7985929facb2b2ada197887b6e6155483b2e221508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000b1723303b47525c6467676767676767676766635b5a595754524c5e6b7885919eabb8b9ac9f9386796c605346392d201306000d1a2733404d5a6673808d99a6b3beb1a5988b7e7265584b3f3945525d687986939facb9b8ac9f928579655b5044372b1f120500000000000000000003101c28343f4a5465727f8b98a9b3beb9ac9f92867a6d6053473a2d2014080000000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000e1b2734414e5a6774818d9aa7b4c0bbaea194887b6e6155483b2e2f3c4955626f7c8895a2afbbc2b5a89b8f8275685c4f4235291c0f00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c606d7985929fabb8c4b7ab9f94887b6e62554b4034291c10040000000000000000000000000000000000000000000d1a2633404d596673808c978a7d7164574a3e3024190d010000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3a8a8a8a8a296897c6f6356493c30231609000916232f3c4956626f7c8995a9b3bebeb2a5988b7f7265554b4034303846525e687784919eaab7c3b6a99c908376695d5043362a1d100000000000000000000000000000000000000000000000000000000000000814202d3a46525e697683909da9b6b8ab9f9285796d60535663707c8996a3afbbaea195887b6e6255483b44505c667985929facb8b3a69a8d8073675a4d4034271a0d00000b17222d3c4855626f7c87929ea1a9aaa29f928a7d7064564c41362a1d110500000000000000000000000000000b17222d38414c555d676d737b7f8486898b8c8d8d8c8b86796d6053473a2d201407000000000000000000000000000000000000000000000000000306070707070707070707070706040000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000815212e3b4854616e7b86929faab4beb3a99e938c7f736d605d564f515356565656565656565656544e463d32271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6576828f9ca6a6a6a6a5998c7f7266594c3f404b556874818e9ba6a6a6a6a896897c706356493d44505b667683909ca6a6a6a6a9978a7e7164574b3e3124180b000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3844505b667986929facb9baada194877a6e6154473b2e211408000007131f2b36404a52585a5a5a5a5a535b6062656667676664615e565e6b7885919eabb8bbafa49986796d6053463a2d201307000e1a2734414d5a6774808d9aa7b3beb1a5988b7e7265584b3f35414c566c7986929facb9b9ac9f9386796c605346392d201306000000000000000000000c17232e3c4855626f7b8897a1adb9bbaea3998a7d7063574a3d3025190d0100000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000c1925323f4c5865727f8b98aab3bebcb0a396897d7063564a3d302f3e4a5764717d8a97a4b0bdbfb5ab998d8073665a4d4033271a0d00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695764717e8a98a2aebabeb3a99c8f83766a5f5343392f23180c000000000000000000000000000000000000000000020f1c2935424f5c6875828f998c7f7366564c4135291e13080000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a969b9b9b9b9b9b96897c6f6356493c30231609000a1723303d4a5663707d8996a3b0bcbdb0a3978a7d7064574a3d2e2a36414d566976838f9ca9b6c2b7aa9d9084776a5d5144372a1e1100000000000000000000000000000000000000000000000000000000000005111e2a36424d5765727f8c98a7b1baada2978a7d7063545763707d8a96a3b0bbaea195887b6e6255483b3f4a5f6c7985929facb8b3a79a8d8074675a4d4134271a0e00000615212e3a47535f6a727f8a92979a9a98928c80746c6155443a3025190d0100000000000000000000000000030f1b27333f49535d676d7980868c90939a989999999993867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000c1825323f4b5865727e8b99a3afbcb9ada2978e81756d635b524c545c606363636363636363636260584e43372b1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c78859299999999999996897d7063564a3d3f4c5865727f8b98999999999996877a6d6054473a3f4a546774808d999999999999998d8074675a4d4134271a0e000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f394653606c7986939facb9baada194877a6e6154473b2e2114080000030e19242e3840474c4d4e50565d61656c6f7273747473716d6862606b7885919eabb8c0b5a093877a6d6054473a2d211407000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f2f46535f6c7986929facb9bbafa49a86796d6053463a2d201307000000000000000000000615212e3a47535f6a7885919eabb8bfb5ab9a8d807367564c4135291d110500000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800091623303c4956636f7c8998a2aebabeb1a5988b7e7265564c413d3e424d5766727f8c99a5b2bfbbaea3998a7d7064574a3d3124170a00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695e6976828f9caab4beb9ada1978a7e7164574e4231271d120700000000000000000000000000000000000000000004111e2a3744515d6a7784909c8f8276685d52453a2f24190f0600000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a8f8f8f8f8f8f8f8f897c6f6356493c30231609000a1724313d4a5764707d8a97a3b0bdbcafa296897c6f6356493c302530424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11000000000000000000000000000000000000000000000000000000000000020e1a25303b4854616e7b8795a0abb8b3a99a8e8174665c5763707d8a96a3b0bbaea195887b6e6255483b46525f6c7985929facb8b4a79a8d8174675a4e4134271b0e000006121f2b37434e58626d727e858a8d8d8b867f746e645a504432291e1308000000000000000000000000000005121f2b3744505b656d79828d92999d9fa4aca6a6a6a093867a6d6053473a2d2014070000000000000002070a0c0d1313131313131313130d0c0a060200000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000020e1b2835414e5b6874818e9babb5c0b8ab9e92857a6d605b5245515c666d7070707070707070706f6a6054473b2e22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222f3b4855626e7c888c8c8c8c8c8c8c8c877a6d6154473a3c4956636f7c898c8c8c8c8c8c8c8478685d5245393e4b5864717e8b8c8c8c8c8c8c8c8c83766a5d5043372a1d10000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366544a3f3b4754616d7a879aa4afbbbbafa399867a6d6053473a2d20140700000008121c262e363b4049515a62686d73787c7e808181807e7a756f6a6b7885919eabb8baada094877a6d6154473a2e211407000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9c0b6a09386796d6053463a2d2013070000000000000000000006121f2b37434e586875818e9ba8b4c1b6aa9d908377685e5246392d20130700000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f221508000713202d3a4653606d7985929fabb8c2b5a89b8f8275685d524c4a4a4b535e6976838f9ca9b6c2b9ac9f92867a6d6054473a2d21140700121e2b3845515e6b7884919eabb7c2b6a99c8f837669616e7b87939facb9c0b6ac9e9285796d6053463c3120150b0100000000000000000000000000000000000000000005121f2b3845525e6b7885919e92867a6d60564c41352921180f05000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272f3c4955626f7c828282828282828282827c6e6255483b2f221508000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000000000000000000000003050605030914212d3a46535e697783909daab6b8ab9e9285796d605763707d8a96a3b0bbaea195887b6e6255483b46525f6c7985929facb8b4a79a8d8174675a4e4134271b0e0000030f1b26313c46515b626c717a7e80807e7a726d645c52483e3320170c020000000000000000000000000004111d2935404b55606c77828f949fa3abacafb6b2b3ada093867a6d6053473a2d201407000000000000070d1316191a202020202020202020191916120d07000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000003101d2a3643505d697683909ca9b6c0b3a79a8d8074685d52494653606d787d7d7d7d7d7d7d7d7d7c6f6256493c2f23160900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222f3b4855626e7c7f7f7f7f7f7f7f7f7f7f72685e5246393a4753606d797f7f7f7f7f7f7f7f7e7164564c41353b4754616e7b7f7f7f7f7f7f7f7f7f7f7265594c3f3226190c000e1b2734414e5a6774818d9aa7b4c0b4a89b8e8175665c5048474c56636f7c8996acb6c0b9ac9f928679675d5145392c2013060000000009151f2a333f49515b636c717a8084888b8c8d8d8c8a86827c746d7885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000000000000000030f1b26313e4b5865717e8b98a8b2bdb9ac9f93867a6d6154473a2e21140900000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f2215080006121f2c3844515c6675818e9ba6b0bcb8ac9f92867a6d615d555757555d616e7b86929facb9bdb1a79c8f8275675d5145392c20130600121e2b3845515e6b7884919eabb7c2b6a99c8f83766966727f8c99a4afbbbbafa49a8d8073665c5145382c1f13030000000000000000000000000000000000000000000006121f2c3945525f6c7885929f998c7f72685d52453e332a21170f050000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272e3b4754606a6f757575757575757575756e6a5f53473a2e211408000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000000000000000000000020507080c060b0f1213120f0b121e2a36424d5766727f8c99a7b1b9ada197897c70635663707d8996a3b0bbaea195887b6e6255483b44505c667985929facb8b3a69a8d8073675a4d4034271a0d0000000a15202a343f48515a61676d717374726e68635b524a40362c220e0500000000000000000000000000000613202c3945515d67727f8b949ea6aeb4b9bbbbb9b6ada093867a6d6053473a2d20140700000000010a12191e2325262d2d2d2d2d2d2d2d2d2625231e19120a0100000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000004111e2a3744515d6a7784909daab7beb1a4978b7e7164564c414854616e7b8789898989898989898276695c4f4336291c1003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3a47535f6a6e737373737373737373726d62564c41363945515d676d7373737373737373716c6155443a2f3a46525e696e737373737373737373726d63574a3e3125180c000e1b2734414e5a6774818d9aa7b4c0b8ab9e9185796d60595454565e6873808d99a6b3c0b8ab9f9285786c554b4035291d1104000000020e1a26313c45515b636d737e858d919798999a9a9999928f8780787885919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000000000000000000a15212e3b4854616e7b8796a0acb8bbafa4998a7d7164574a3e30251a0e02000000000000000000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f2215080004101c2834404a54626f7c89949faab4baaea2988e81746d6765646465676d75818e99a3aebbb5ab9f958a7d7063554c4135291d110400121e2b3845515e6b7884919eabb7c2b6a99c8f8376696a7784919dabb5c0b9ac9f93877b6e61544b4034281c10040000000000000000000000000000000000000000000005121f2c3845525f6b7885929e9e92857a6d60594f453c332921170f0600000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272b37434e58606268686868686868686868625f584e43372b1f1206000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000000002080e111414181b171b1f201f1b171a1a25313b4855616e7b8895a0acb8b3a99a8d80746758626f7c8895a2afbbafa295887c6f6255493c4653606d798698a2aebab2a5998c7f7266594c3f3326190c000000030e18222d363f4850555d6064676765615e56514940382f241a100000000000000000000000000000000714202d3a4753606d7985929ea6b0babfbeb6afaca9a7a093867a6d6053473a2d201407000000000a131c242a2f323339393939393939393933322f2a231c130a00000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000004101d2a3743505d6a7683909da9b6bdb0a4978a7d7164564d4c4e5763707c89969696969696968e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121e2b37424e575f6266666666666666666665625b51443a3035404b555d60666666666666666664615a5045322a36424d575e6166666666666666666665635b51463a2e221609000e1b2734414e5a6774818d9aa7b4c0b9ada1978b7e716b63616162686e7a85929eabb8c4b7aa9d9184776a5e51442f24180d0100000006121e2b37424d57626d737f8b92979ea1a9a6a7a7aba39f9a938d827884919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000000000000000000714212d3a46535e697784919eaab7c0b5ab9a8d817467574d42362a1e1105000000000000000000000000000000121f2b3845525e6b7885919eabb8c0b4a79a8d8174675a4e413427313e4b5864717e8b97a4b1bebbaea195887b6e6255483b2f22150800000c18232e394754606a76828f98a2abb4b4aa9d938d807a74727071727479808d939eabb5b4aea3999083786c6053463a2f24190d0100121e2b3845515e6b7884919eabb7c2b6a99c8f837673737c8995a0acbdbeb3a99c8f8276695f5342392e23180c000000000000000000000000000000000000000000000005111e2b3844515e6b7784919ea1978d80746b61574e453b332921180f06000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342727323c464e54555c5c5c5c5c5c5c5c5c5c55534e463c31261a0f02000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000000000040a0f14191e2021252822272b2d2b27222623202d3a47535f697784909daab7b7ab9e9184786a60616e7b8894a8b2bdb0a3968a7d7063574a3f4754616e7b8794aab4bfb1a5988b7e7265584b3f3225180c0000000006101b242d363e434d565e616464625f574e443f372f261d1208000000000000000000000000000004101d2935404b5565727f8b97a1adb8c2b9b1aca49f9d9a9993867a6d6053473a2d20140700000007121c252e353b3f40464646464646464646403e3b352e251c1207000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000030f1c2936424f5c6975828f9ca8b5bfb3a6998c8073685e5659585f6973808d99a3a3a3a3a39a8d8074675a4d4134271a0e0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a26313c454e5355595959595959595959595751493f32282f39434b51535959595959595959575550483e3425303b454d5254595959595959595959595751493f352a1e1206000e1b2734414e5a6774818d9aa7b4c0beb3a99f92867d74706e6e6f737a829097a2adb9c1b4a89b8e8175685b4e4235281b07000000000814212d3a47535f69727f8b919fa2a9adb2b3b4b4b5afaca49f948d8084919eabb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000000000000000005121e2a36424d576774818d9aabb5c0b7aa9d918477695e52463a2d201407000000000000000000000000000000111e2b3744515e6a7784919daab7c1b4a79a8e8174675b4e413025323e4b5865717e8b98a4b1bebfb4aa94877b6e6154473b2e211408000007121c2b37434e58616e7b869299a3aab1afa59d928d85817e7d7d7e81858d929da5afb1aaa29f92877c6f655b504437281e13080000121e2b3845515e6b7884919eabb7c4b7ab9e918480808082909ca7b1bcb9ada1978a7d7164574d4230271d1207000000000000000000000000000000000000000000000003101d293643505c6976838f9ca99d928a7d706a5f574d453b332a21180f060000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427202b343c4347494f4f4f4f4f4f4f4f4f4f4847433c332a20150900000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000000000070c151b1f252a2d2e32352d33373937332d33302d2b37424d5766737f8c99a7b1b9ada196897c6f62606d7a8796a0acb9b2a6998c7f73665a504c4f5964707d8a97a3b0bdb2a8978a7d7164574a3e3124170b000000000009121b242d3946525e686e71716e6a5f53473a2e251d140b00000000000000000000000000000006131f2c3945515d677683909ca9b3bebbb1a79f9a93908d8c8c86796d6053473a2d2014070000020d19242e3740474b4d5353535353535353534c4b4640372e23190d020000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000010e1b2834414e5b6774818e9aacb6c0b8ab9e91847a6e696666676a6f7b85929fabb0b0b2a8988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915202a333c4247484c4c4c4c4c4c4c4c4c4c4a463f372d202831394045474c4c4c4c4c4c4c4c4b49453e362c2229333b4246474c4c4c4c4c4c4c4c4c4c4a463f372d23180d01000e1b2734414e5a6774818d9aa7b4c0c4baaea2989287817d7b7a7c7f8590959fa9b3bebdb2a8988c7f7265594c3f3226190c00000005121e2a36424d57616e7b86929fa4adb3b9bebebab8b3b1b6afa69f928686929facb8baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000000000000000000020e1a25313e4a5764717d8a99a4afbbb8aca096877b6e6154473b2e211409000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b5a89c8f827569574d42362e303f4c5965727f8c98a5b2bfbaaea39886796d6053473a2d2014070000000f1b27323d46535f69707e8792989fa7aeaea49d97928e8b8a8a8b8e92979da4aeafa79f98928a7e716a6053493f3327160c010000121e2b3845515e6b7884919eabb7c4b9ada196918d8d8d90949fabb9c0b6ac9e9285796d6053463c3120150b000000000000000000000000000000000000000000000000010e1b2734414e5a6774818d9aaba49f92857c6e695e574d453b332a2118100600000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342719222b32373b3c424242424242424242423b3a37312a21180e0300000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000000000030b121820272b3036393b3f42443f4446443f43403c3937333c4855626f7b8895a0acb8b2a8998d8073665d687784919eaab7b7aa9d9083776c615a5959616b75818e9ba8b5b9ada196887b6e6155483b2e2215080000000000000814212e3b4754616e7a7e7e7c6e6255483b2f221508020000000000000000000000000000000714202d3a4753606d7a86929facb9beb3a99f95908783807f7f80786d6053463a2d201307000007131e2a3540495257596060606060606060605957514940352a1e12060000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000b1825313e4b5864717e8b9aa4afbbb9ada19790827b75737273767c849197a2adbab9ada196887c6f6255493c2f221609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030e18212a31373a3b4040404040404040403f3e3a352d251b1f282f35393a40404040404040403e3d39342c241a202930363a3b4040404040404040403f3e3a352d251c110700000e1b2734414e5a6774818d9aa7b4c0c4bdb4aaa299928e898787888c92979fa7b1bbc5b8aca096897c6f6356493c302316090000000714212d3a46535e6975828f98a2aebabec2bbb3adaba7a4a3a5a8a399929298a3aebabaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000000000000000000000914212d3a4754606d7a86939facb9bdb2a8978b7e7164584b3e31261a0e020000000000000000000000000000101c2936434f5c6976828f9ca9b5c2b7aa9d918477695e52463c3b3b424f596774818e9aa7b4c1b9ac9f928679675d5145392c1f13060000000a16202a36424d57616c717e8690959da4aeaea9a19e9b989797989b9ea1a9aeafa59d9590867e716c62584e41382d221704000000121e2b3845515e6b7884919eabb7c4bdb2a8a19e9a9a9a9c9fa6b0bcbbafa49a8d8073665c5144382c1f1203000000000000000000000000000000000000000000000000000b1824313e4b5764717e8a99a3ada29791847b6e695e574d453c332a22181006000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b1920272b2e2f353535353535353535352f2e2b2620180f060000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000000040c151d232832373b4146474b4e5149505350494f4d4946443f3847535f6a7784919daab7b7aa9d9184776a5f6875818e9baab4b8aca0958a7e716c6766676b707d87939facb9b8ab9e918478695f53463a2d2114070000000000000b1825313e4b5864717e8a8a8073675a4d4034271a0800000000000000000000000000000000091623303c4956636f7c8999a3afbbbaada29790837c76747373746d665c5144382c1f120600000a16232f3b47525b63666c6c6c6c6c6c6c6c6c66635b51463b2f23160a0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000814212e3b4754616e7a87939facb9beb2a99f949086827f7f8083889196a0a9b3beb4aa9e9184786c605346392d20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f1820262b2e2f33333333333333333332312e29231b13161d24292c2d333333333333333331302d28221a12171f252a2d2e33333333333333333332312e2a231c130a0000000e1b2734414e5a6774818d9aa7b4c0bab2acababa39f9b96949495999ea1a9b1b9c2bdb2a89e9184776b6054483b2f2215090000000815212e3b4854616e7b87939faab4bfc2b8b0a9a29f9a9797989c9fa39f9fa3aab4bfbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000000000000000000000713202c3945525d687783909daab6c1b4a79b8e817468574d42372b1e120500000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8aca095877b6e61574e4947484c54606b7784919daab7c4b7ab9e9184786b554b4035291d1004000000040e1a26313b45505a616c717c838d929da9b5b3adaba7a5a3a4a5a7abadb3b5a99d928e837c716c625a50463d2f261b1106000000121e2b3845515e6b7884919eabb7c4c4bab2adaba6a6a6a9abb0b8c2b9ac9f93877b6e61544a4034281c1004000000000000000000000000000000000000000000000000000714212e3a4754616d7a86929faca9a19691847b6e695f574e463c342a22180f060000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0f151b1f22222929292929292929292922211f1a150e06000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000000040d161e272e343c43474d5254585b5d5f5b605b5e5c595653504944434e586673808c99a8b2b8aca096887b6f6265727e8b98a3aebab1a79f92867e77747273767d859299a4afbbb1a89b8e817568574d42362a1e12050000000000000d1a2633404d596673808c8e8275685b4f422f24190d010000000000000000000000000000000b1825323e4b5865717e8b98abb5c0b8ab9f92857a6e6a67666667605c544a4034281c100400000c1925323f4b57636d73797979797979797979736d63574b3e3225190c0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000714202d3946525e6876828f9ca5afb9bbb0a69f98928e8c8c8d90949da0a8b2bbbaaea2988c8073655b5044372b1f12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e151a1e21222626262626262626262625221e18110a0c12181d202026262626262626262423211d1710080d141a1e20212626262626262626262625221e18110a010000000e1b2734414e5a6774818d9aa7b4bdb2a8a19e9d9fa7a7a3a1a1a2a6abadb3bbc2c0b9ada1968c7f7265594f43382c1f1307000003101c28343f4a5466737f8c99a4afbcc4bab0a69f97928d8a8a8b8f9399a2aaaeb4bcc6baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000000000000000000004111d2935414c566673808d99aab4bfb7ab9e918478695f53463a2d21140600000000000000000000000000000c1825323f4b5865727e8b98a5b1bebdb1a8998c7f73696058565455565d666f7c8995a0acb8c1b5a89b8e8275685b4f422f24180c000000000009141f29333e48505a616a6f77808d9aa7b3beb9b8b4b1b0b0b1b4b8b9beb4a79a8e81776f6a615a50483f342b1d140a00000000121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b3b3b3b6b7bcc2c2b5a99c8f8276695f5342392e23180c00000000000000000000000000000000000000000000000000000713202d3946525e6875828f9ba6b0a8a09691847b6e695f584e463c342a21180e0400000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e0a0f1315161c1c1c1c1c1c1c1c1c1c1514120f090300000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000000030c161f28303940454e54565e6165686a6c656c656b696663605b53504a4855626f7c8896a0acb8b2a8998c7f7366616d7a86929facb6baaea398928a83807f80838a9297a2abb5b8aca0958a7d7063574a3d31261a0e020000000000020f1b2835424e5b6875818e9083776a564c4135291d11040000000000000000000000000000000d1a2733404d5a6673808d99a6b3c0b4a79a8d8174685f5859595a53514a42392e23180c0000000d1a2633404d596673808686868686868686867f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000005111e2a36414c56626f7c89939ea7b1b9b8b0aaa39f9b99999a9c9fa6acb2babaafa59f92857a6e6153493f33271b0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e121415191919191919191919191816120d070001070d1013141919191919191919181715110c060002090e111414191919191919191919191816120d0700000000000e1b2734414e5a6774818d9aa7b4b9aca1969190959fa7b0aeadafb2b8b9bec1bdb5afa39e91847a6d6054473d32271b0f03000006121f2b3844505c667683909dabb5c0bdb2a89f949085807e7d7e82879298a2aebac5cebaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000000000000000000010d1924303d4a5663707d8998a3aebab9ada196887b6e6155483b2d22170b00000000000000000000000000000a1623303d495663707c8996a8b2bdc3b8ac9f92867b6f6a6462616263686d7883909da7b1bcbcb1a7988c7f7265594c3f3226190700000000000c17232e38424e575f6a6f7a828d929da9b5bbb7b5b1aeadadaeb1b5b7bbb5a99d928e827a6f6a5f574d42382d22170b00000000121e2b3845515e6b7884919eabb7c4cec6bfbab8b7b7b7b8b9bec5c0b3a79a8d8074675d5145382c1f150a000000000000000000000000000000000000000000000000000005111d2935414c56636f7c89949eaab2a8a09691847b6e6a5f584e463c332920160b02000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e00030608090f0f0f0f0f0f0f0f0f0f08080602000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000000000a151e28313a424b51586062686e727577787979797876736f6c65605c544d535f6a7784919eaab7b7aa9d908377695f6874818e9aa4afbbb4aaa39f95908d8c8d90959fa2a9b3bbb0a69d9184786c605346392d20130900000000000004101d2935404b5569768390928578685d5245392c2013070000000000000000000000000000020e1b2835414e5b6874818e9ba7b4bdb1a4978a7e7164564e4c4c4e4644403930271c12070000000d1a2633404d596673808c939393939393938c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000010d1925303b4754606a75818e95a0a7afb7bcb4aeaca8a6a5a6a9abb0b8b9b3aea59e938b7f72685e5241382d22170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020608080d0d0d0d0d0d0d0d0d0c0b09060100000000010406070d0d0d0d0d0d0d0d0b0a08050000000000020507080d0d0d0d0d0d0d0d0d0c0c0906010000000000000e1b2734414e5a6774818d9aa7b2b2ab9e91848390959ea6acb2b7b8bab8b7b6b0aba39f91897d70685d5245392b21160a0000000713202d3a4653606d7985929facb8c5b9aca19690827a74717072757d86929fa9b3bec9baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000000000000000000000814202d3a4753606d7986929facb8bdb2a8988b7e716553493f33271b0f03000000000000000000000000000714212e3a4754616d7a8796a0acb8c5baaea29891847c75716f6e6e70737a828f95a0acb9c3b8aca095897c6f6256493c2f2316090000000003101c28343f4a545f6a6f7c848f949da4aebab0aba9a4a1a0a0a1a4a9abb0bbafa59d948f847c6f695f544a3f33281c0f03000000121e2b3845515e6b7884919eabb7c4c6bcb4aeacaaaaaaabadb3bbc5b8ab9f9285796d6053473d32271b0f0200000000000000000000000000000000000000000000000000010d1925303a4854606b75828f98a3aeb2a8a09691857c6f6a5f584e453b32281d140a000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e01000000000202020202020202020200000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000000006111c26303a434c545c606a6f757b7e8184858686858482807c78716d665f574f586673808d99a8b2b8aca095887b6e61626f7c87939fa7b1bab4aea7a09d9a999a9d9fa7adb3bcb3a99f948b7e71655b5044372b1f120500000000000006131f2c3945515d6778859197877a6d6054473a2d2114070000000000000000000000000000030f1c2936424f5c6975828f9ca8b5bcafa295897c6f6256494040413a38342e271e150b000000000d1a2633404d596673808c999f9f9f9f9f998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000008141e2b37434e58606d798390959ea5abb0b5b8b8b5b2b2b3b6b8b6b3adaaa29f938e81756d62564c412f261b1106000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa6a6a6a69e91847a838f949ea0a8aaabadacaaa9a69e99928b7f726b60564c413529190f040000000915222f3c4855626f7b8898a2aebabfb4ab9e9184796d686464656b727f8b97a1adb9c6baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000000000000000000000006131f2c3845515c6776838f9ca9b6c1b5a89b8e8275655b5044372b1f1205000000000000000000000000000713202d3946525e687784919daab7c4bfb4aaa1969187827e7c7a7b7d80858f949fa7b1bcbeb3a99d9184776a6054473b2e2215080000000006121f2c3844505c666e7c8591969ea6aeb4aea69f9c9794939394979c9fa6aeb5afa69f9691857b6e665b5044382b1f160b000000121e2b3845515e6b7884919eabb7c4bfb4aaa29f9d9d9d9ea1a9b3bebaada2978b7e7165584e43372b1e1308000000000000000000000000000000000000000000000000000008131e2c38434f59616e7b86929fa6b0b2a8a19791857c6f6a5f574d443a2f261c11060000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e01000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000000000c17232e38424c555d666d747c82878b8e9092929892918f8c89847e786e69605955626f7c8896a0acb9b1a7988c7f72655f6a73808d95a0a8b1bbbab1acaaa7a5a6a9abb1babbb3aaa1978f82776c6053493f33271b0f030000000000000714202d3a4753606d7a869795887c6f6255493c2f221609000000000000000000000000000003101d2a3643505d697683909ca9b6bbaea195887b6e6255483b33342d2c28231c150c03000000000d1a2633404d596673808c99a6acacaca6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000020f1b27323d45515d676e7b838e939c9fa6a8abadb3aeaeb4aeaca9a9a19e98928b81786d605b51443b301d140a00000000000000000002070b0d0d131313131313131313131313131313131313131313131313131313130808060200000000000000000000000000000000000000000000000001070b0f1112131313131313131313130706030000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9999999999999184777a828b91969a9d9fa29f9e9c98948f877e726d63594f433a2f241907000000000a1724313d4a5764707d8a97aab4bfbaaea3998b7e71675e565759606d7985929eabb8c5baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d2013070000000000000000000000000004101c2934404b5566727f8c99a9b3beb8ab9e9285786c605346392d2013060000000000000000000000000005111e2a36414c566774818d9aabb5c0c6bcb2a9a199938f8a898788898d92979fa6b0b9c2b9ada1978b7e7265584e43372b1f1306000000030f1b27333f4953606d78839097a1a8b0b4aba39f948f8a878686878a8f949fa3abb5b0a8a1979083786c6053463d32271b0f030000121e2b3845515e6b7884919eabb7c4baaea298929090909297a1adb9beb3a99d9083776a6054473a3025190d0000000000000000000000000000000000000000000000000000020f1b27323d47535f69727f8c949fa9b3b2a9a19792857c6f695f564c42382d22170b0200000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e00020507080c0c0c0c0c0c0c0c0c0c08070502000000000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000003101c28343f4a545d676d7880878f93999b9d9f9fa39f9e9c9996918b837b706b60585f6a7784919eaab7b6a99d908376695e606d79839096a0a7afb5b9b8b7b3b2b3b6b8bab8afa9a19892857a6e655b5041382d22170b000000000000000915222f3c4855626f7b8895978a7d7064574a3d3124170a000000000000000000000000000004111e2a3744515d6a7784909daab7baaea194877b6e6154483b2e27201f1c18120b0300000000000d1a2633404d596673808c99a6b3b9b2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000a16202935404b555e696e79818a8f94999c9fa2a9a2a1aaa29f9c9a97928d857e756d665c51493f32291e0b020000000000000000080e1317191a202020202020202020202020202020202020202020202020202020201514120e0903000000000000000000000000000000000000000000050c12171b1e1e2020202020202020201f1312100c06000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818c8c8c8c8c8c8c8c84776d757e848a8d90929792918f8c88827c716c635b51473d31281e1308000000000b1825313e4b5864717e8b97a4b1beb9ac9f92867a6d60554c4a515c6674818d9aa7b4c0baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000000000000000000000000c18232f3c4956626f7c8997a2adbab9ada197887c6f6255483c2e23170b00000000000000000000000000010d1925303d4a5764707d8a99a3afbbc7c4bbb2aba49f9c9795949596999fa2a9b0b8c1b8afa59e9285796d6053473d32271b0f0300000005121f2b3744505b65727e8b95a0a9b2baaea399928a827e7b7a7a7b7e828a9299a3aebbb2a99f958b7e7164594f44382c2013070000121e2b3845515e6b7884919eabb7c4b8ac9f928683848385929ea9b3beb8ab9f95897c6f62564c4135291c110600000000000000000000000000000000000000000000000000000a16212b37424d57606c78829097a1abb5b2a9a19791857b6e685d544a3f33281f140900000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0e090e121415191919191919191919191414110e090200000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000000030e18222c3844505c666d79828d93999fa4abaaabacaeacaba9a8a09e9590867d706a60586673808d99a8b2b9ac9f93877b6e615c666e7b8490959fa3abadb2b3b4b4b4b3b3aeaba59e9791867d6f685e53493f2f261b1106000000000000000a1724303d4a5763707d8a96988c7f7265594c3f3226190c000000000000000000000000000004111e2b3744515e6a7784919daab7baaea194877b6e6154483b2e211512100c07000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000000040d18242f39434d575e676d757d82888c8f9297949595949892908d8a85807b716c605c544a40372d20170d00000000000000020a12191f2326272d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d22211e1a150e0600000000000000000000000000000000000000060f171d23272a2b2d2d2d2d2d2d2d2d2d2c201f1c17110a0300000000000000000000000000000000000000000000000000000000000000000a1724303d4a5763707d7f7f7f7f7f7f7f7f7f72656c71787d808485868584827f7b756e6a625a514940352b1f160c01000000000c1825323f4b5865727e8b98a5b1beb6aa9d908377675d5143404a5464717e8b97a4b1bebaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d20130700000000000000000000000000000713202d3a4653606d7985929fabb8beb3a9988b7f7265544a3f34281c1003000000000000000000000000000814212d3a4754606d7a86929facb9c5cdc4bdb5afaca8a4a2a1a1a3a6abadb3bbbebab0a69d938a7d70675d5145392b20150a000000000613202d394653606c7884919ea7b1bbb2a99f92877e76716e6d6d6e71767e87929fa9b3bbb1a79d9184776b6054483b2f2215070000121e2b3845515e6b7884919eabb7c2b6a99c8f827777777d8a97a1adb9bcb1a79b8e8174685e5246382d22170b0000000000000000000000000000000000000000000000000000040e1a26313c44505b666e7b859199a3afbbb3a9a19791847a6d665b50443b3025190e03000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b0d141a1e21222525252525252525252521201e19140d05000000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000000a15202c38434e58606d788290949fa4abafb5b7b8b9bab8b7b5b2aca79f9892867c6f675d626f7c8896a1acb9afa49a8b7e7265565f696e7b838d92999ea1a9a6a7a7a7a6aaa29f9b938e857d6f6b60564d41382d1d140a00000000000000000c1925323f4c5865727f8b989a8d8074675a4d4134271a08000000000000000000000000000005111e2b3844515e6b7784919eaab7baaea194877b6e6154483b2e211508040000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000007121d28313b454d555d606b70767c7f82858687888887868583807d79736e69625a514a42392e251b0e05000000000000000a141c242a2f3334393939393939393939393939393939393939393939393939393939392f2e2b2620180f060000000000000000000000000000000000000f1821282f343738393939393939393939392d2c28231c150c03000000000000000000000000000000000000000000000000000000000000000916232f3c4855616b707373737373737373726d6262666c7074777879797776726f6a625f58504840372e231a0d0400000000000c1926333f4c5966727f8c99a5b2bfb5a89b8e827568554b403c4955626f7c8895abb5c0baada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000000000000000000000006121f2b3844505c6675828f9ba8b5c2b5a89c8f8275665c5044382b1f1206000000000000000000000000000613202c3945525d6875828f9ca9b3becad0c7c0bbb9b5b1afadaeb0b3b8babdb9b4aea69e948e81746c61554b403529190f0400000000091623303c4956636f7c8996a0acb9b9ada1968c7f726c6461606061646c727f8c97a1adb9b8aca096897c6f6356493c2f24180c0000121e2b3845515e6b7884919eabb7c2b6a99c8f83766a6d7985919eabb8c2b8ac9f92867a6d61544a3f33281c0f0300000000000000000000000000000000020608080a0a0a0a0a0a09151f28333f4a545e69707d87929fa5afb9b2a9a0968f82786c60564d42362a1f1409000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271b171f262a2d2e323232323232323232322e2d2a251f170e050000000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000000030f1a26313b4854606a73808c949fa6afb5bbb7b6b0aeadafb3b8bab9b1aaa29891847a6d60606a7884919eabb7b6ac9c8f8276685e575f696e7980878d919697999a9b9a9a9898928e88817a6f6a60594f443b2f261b0b0200000000000000010d1a2734404d5a6773808d9a9c8f8275695c4f423025190d010000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000010c161f29333b434b515961636a6f7275787a7a7b7b7a7a797673706d67615e575044403930271c13090000000000000008121c262e363b3f40464646464646464646464646464646464646464646464646464646463b3a37312a21180e0300000000000000000000000000000000060f212a333a404345464646464646464646463a38342e261e150a000000000000000000000000000000000000000000000000000000000000000714202c38444f596163666666666666666665625b545b6063676a666c666b6965625f58534e463f362e251c11080000000000000d192633404c5966737f8c99a6b2bfb4a79b8e8174685b4e413a4754616d7a8799a3afbbbaada194877a6e6154473b2e211408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9b9aca09386796d6053463a2d201307000000000000000000000000000003101c28343f4a5465727e8b98a8b2bdb8ab9f9285796d6053463a2d2013070000000000000000000000000004111d2935414c5664717e8a97a2adbac6d3d2ccc0b9b5b3b1b4b4b5b5b5b3b2acaaa29f938f82796d605a5043392f24180700000000000d192633404c5966737f8c99a8b2bdb8ab9e9184786d605a545353545a606d7985929eabb8bdb2a89a8d807467554b4035291d100400121e2b3845515e6b7884919eabb7c2b6a99c8f8376696673808d9aa7b1bcbaaea3988c7f72665b5044382b1f14090000000000000000000000000000030a0f121415171717171717171717222d38424d56606b727f8b939ea7b1bbb2a89f948c7f72695e52463b30251a0e020000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342717212931363a3b3f3f3f3f3f3f3f3f3f3f3b3a36302920170d0200000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000006121f2b37434e58626f7c87929fa6b0bbb8b0aba9a4a1a1a2a6acaeb4bcb3aaa1968e81756a5f6773808d9aa8b2b9ac9f92867a6d6154575f676d737b8084888b8c8d8e8e8d8b8985817c756e6860584f473d32291d140a0000000000000000020f1c2935424f5c6875828f9b9d9084776a564c41362a1d11050000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000000040d172029313940454f55585f626669676d6e6f6e6e6d67696764605c55524d453e342e271e150b01000000000000020e19242e3840474b4d535353535353535353535353535353535353535353535353535353534847423c332a201509000000000000000000000000000000030e1821333c454b50515353535353535353535246443f3830261c110600000000000000000000000000000000000000000000000000000000000004101c28333e474f555759595959595959595856514a5053575a545b605b545c5955534e47433c332d241c130a000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e41394653606c7986929facb9baada194877a6e6154473b2e211408000e1a2734414d5a6774808d9aa7b3beb1a5988b7e7265584b3f3946535f6c7986929facb9bbaea39986796d6053463a2d2013070000000000000000000000000000000b17232e3b4855626e7b8896a1adb9baaea298897c6f6256493c2e23180c00000000000000000000000000010d19242f3a4653606d7985929fabb8c2cccac0b6aea8a6a5a7a8a8a8a8a6a8a09e98928b82796d675d51473e31271d12070000000004101d2935404b556975828f9ca8b5c0b3a79a8d8074665c5048474748515c6674818e9aa7b4c1b7aa9d908477675d5145392c1f130600121e2b3845515e6b7884919eabb7c2b6a99c8f837669626e7b88959fabb7bfb4aa9e9184786c6053463b31261a0e00000000000000000000000000060e151a1f212224242424242424242423262f3b444f59626d74818e95a0aab4bab0a69f92867b6e61574d42362a1e12050000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134271f29333b4246484c4c4c4c4c4c4c4c4c4c4746423b32291f140900000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000815212e3a47535f6a76828f99a3afb8b6aea69f9c97949495999fa2aab3bbb2a89e93887c6f62626f7c8996a1adb9afa3998b7e7164554d555d60696e73787b7e80818181807e7c79746f6a615e564e463d352b20170b02000000000000000004111d2935414c566a7783909d9f928579685e5246392d2013070000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000000000000050e171f282f353e44484e535559555d6061626261605d555a5753514b46423b3328231c150c030000000000000007131f2a36404a52585a6060606060606060606060606060606060606060606060606060606055534e453c31261a0e02000000000000000000000000000009141f2a33454e565c5e6060606060606060605f53504a42382e23170c000000000000000000000000000000000000000000000000000000000000000b16212c353e44484a4c4c4c4c4c4c4c4c4b4a463f44464a4d4a5053504a504c4847433c37312a211b120a01000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413744505b657885929fabb8baada194877a6e6154473b2e211408000d1a2734404d5a6773808d9aa6b3beb1a5988b7e7265584b3f3845515c677986929facb9b9ac9f928679665c5044382b1f12060000000000000000000000000000000614212e3a47535f6a7884919eabb8beb3aa998c7f7266554b4034281c10040000000000000000000000000008131f2c3845515c6774818e9aa6b0bbc7c5b9aea49d9a989a9b9c9c9b9a9896918c857f776d675d554b40352c1f150b010000000006131f2c3845515d677885929eabb8bdb1a4978a7e7164544a3f3a3a404a5465717e8b98a4b1beb9ac9f92867a6d6053473a2d20140700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695f6a7683909daab4bfb9aca0968a7d7063574d42362a1d12070000000000000000000000060f1820262b2e2f303030303030303030302f2c323d47515b606d79839098a2aebabaaea2988e8174695e52463a2d2014090000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e41342726313b454d53555858585858585858585854524d443b3025190e02000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e1200000000000915222f3c4855626f7c88949fabb5b9aea49c948f8a8887898d9298a1a9b3baafa59b8e817468606c7884919eabb7b5ab9c8f8275675d514b51575e61656c6f717374747473726f6d66625f58524c443d342b23190e050000000000000000000713202c3945525d687885929fa298877a6d6154473a2e2114070000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000050d161d242933383c4347494c4b51535455555453514b4d4a464540393630292018120b0300000000000000000b17232f3b47525c64676c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c5f574e42372b1e120600000000000000000000000000020e1a26313b455660686b6c6c6c6c6c6c6c6c6c6c605c544a3f34281c100300000000000000000000000000000000000000000000000000000000000005101a232c33383c3d40404040404040403f3d3a3338393d413f4446443f433f3c3a37312b2620180f090000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e41333f495f6b7885929eabb8baada194877a6e6154473b2e211408000d192633404c5966737f8c99a6b2bfb2a5988c7f7265594c3f3a4753606d7a8699a3afbbb8ab9f9285786c5f4a3f34281c100300000000000000000000000000000006121e2b37424e576874818e9ba7b4c1b6a99c8f8276675c5145382c1f13060000000000000000000000000004101c2834404b55626f7c88949fabb7c3c1b5a89d928d8b8d8e8f8f8e8d8b88847f7a726c655d554b43392f231a0d0300000000000714202d3a4753606d7a8697a1adb9bbaea295887b6f6255483c2e2e3c4956636f7c8996a2afbcbbafa399887b6f6255483c2f22150900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695765717e8b98a2aebabdb2a89c8f8275695f5346392e23180c00000000000000000000030e18222a31373a3b3d3d3d3d3d3d3d3d3d3c3b3832353f45515d676e7c86929fa9b2beb4aa9f92877b6e6154483b3025190e0200131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272a36424d575f6165656565656565656565615e564d42362a1e1105000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e120000000005111e2a36414c566774818d9aa6b0bdb1a79c928d827d7b7a7c80869197a1adb9b9ac9f92867a6e616574808d9aa9b2b9ac9f92867a6d605447454d53535b60626466676867676562605c54544e46413b322b22191107000000000000000000000714212d3a4754606d7a8797a2aa95897c6f6256493c2f2316090000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000000000000040c121821282c32373b3c3f40454747484847474540403d3a38342e2a251f170e07000000000000000000000d1926333f4b58646e7379797979797979797979797979797979797979797979797979797979766a5f53473a2e2114080000000000000000000000000005121e2a36424d57687278797979797979797979796d665c5044382c1f12060000000000000000000000000000000000000000000000000000000000000008111a21282c2f30333333333333333332312e282b2d302d33383938332d322f2e2b26201a150e06000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e412d45525e6b7885919eabb8baada194877a6e6154473b2e211408000b1825323e4b5865717e8b98acb6c0b3a79a8d8074675a5047464b55626e7b8895abb5c0b7aa9d9084776a5d51442e23170b00000000000000000000000000000000020e1a26313e4b5864717e8b97a7b1bcb8ac9f9286796d6053463a2d20130700000000000000000000000000000c18232e3947535f6a76828f9ca7b1bcc0b3a69a8d807f8181828282807e7b77736d68605b534b433a31271d11080000000000000814212e3b4754616e7a8794a9b3bebaaea194877b6e6154483b2e2f3b4855626e7b8895a1aebbc0b5ab96897d7063564a3d3023170a00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c606d7a86929facb8c4b9ac9f93877b6e61554b4034281c10040000000000000000000a15202a343c4347484a4a4a4a4a4a4a4a4a4948443d3535404b555f6a727f8c97a1adb9bbafa3998c7f7366564d42362a1e110500131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272d3a46535f696e727272727272727272726e695e52463a2d201407000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000714202d3946525e687784919eaab7b8ab9f958d8076716e6e6f737c85919ea7b1baaea3998a7e7164636f7c8996a1adb9aea3988a7e7164554b4042464950535558595a5b5b5a585653514b47433c3630292019100700000000000000000000000916222f3c4955626f7c8895a9a4978a7d7164574a3e3124170b0000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000000001070d161c20262b2e2f2f35383a3b3c3b3b3a38352f312d2c28231d1a140d0500000000000000000000000d1a2734404d5a677380868686868686868686868686868686868686868686868686868686867c6e6255483b2f221508000000000000000000000000000714212d3a46535f69788486868686868686868686786d6053463a2d20130600000000000000000000000000000000000000000000000000000000000000000810161c20232426262626262626262524221c1f202422282b2d2b28222622211f1a150f090300000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000a1623303d495663707c899aa4afbbb7aa9d9184776c61595353555d67727f8b98a5b1beb5a89b8f8275685c4f4235291c0600000000000000000000000000000000000914212e3b4754616e7a8795a0acb8baaea398897c706356493d2f24180d010000000000000000000000000007121d2b37434e5863707d8995a0acb8c3b6a99d908376747575757573716e6a66615d565049413a31281f150b000000000000000915222f3c4855626f7b8895a2aebbbaada093877a6d6054473a2d2e3b4854616e7b8794a1aebabdb0a3978a7d7064574a3d3124170a00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5d6774818e9ba8b2bdbbafa4998d8073675c5145382c1f150a0000000000000000020f1a26313c464e535557575757575757575756544f473d3239434e57606d7984919eabb8c0b5ab9e918477695e52463a2d20140700131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e4134272e3b4855616e7b7f7f7f7f7f7f7f7f7f7f7b6e6154473b2e211408000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000814212e3b4754616e7a8796a0acb9b6a99d9083786c646161626a707d8a95a0acb8b4ab9a8d817467606c7884919eabb8b4aa9b8e8275675c514538383f4446484b4d4e4e4e4d4b494645403937322a251e170e070000000000000000000000000a1724313d4a5764707d8a97a3a5988c7f7265594c3f3226190c0000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000000000000000000050b10151b1f212224292c2d2e2f2f2e2d2c292424201f1c18120e09020000000000000000000000000815222f3b4855626e7b889593939393939393939393939393939393939393939393939393887b6e6255483b2f221508000000000000000000000000000815222e3b4855616e7b88969393939393939398897c6f6256493c2e23170b000000000000000000000000000000000000000000000000000000000000000000050b1014161719191919191919191818150f121317171c1f201f1c17191515120f0a03000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000714212d3a4754606d7a86939facb9b8aca0958a7e716b62606061676d7984919eaab7bdb2a8998c7f7266594c3f3326190c00000000000000000000000000000000000714202d3946525e687784919daab7bfb4aa998c807366554b4135291d110400000000000000000000000000000f1b26323c4855616b7783909da9b2bdb8ab9f95897c70686969686765625f5854524c443f382f281f160d03000000000000000916232f3c4956626f7c8995a2afbcbaada094877a6d6154473a2e2e3b4854616e7b8794a1aebabdb0a4978a7d7164574a3e3124170b00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5563707c8996a0acb9c0b5ab9e9285796d6053463c32261b0f020000000000000006121f2b37434e585f626363636363636363636360594f4438313c45515c6773808c99abb5c0b9aca096877b6e6154473b2e21140800131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a8b8b8b8b8b8b8b8b897d6f6356493c30231609000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000a1724313d4a5764707d8a97a8b2bdb2a8978a7e71655b555458616b7783909daab7b7aa9d9084776a5b6574808d9aa9b3b8ac9f9285796d6053473a2e3337393c3e40414141403f3c3a38342e2b262019140d05000000000000000000000000000c1926323f4c5965727f8c98a5a79a8d8174675a4e4134271b080000000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000000000000000040a0f131516181d1f2021222221201f1d18171313100c070000000000000000000000000000000814212e3a47535f6a7683909d9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f95887b6e6255483b2f221508000000000000000000000000000b1825323e4b5865717e8b98a89f9f9f9f9faa998c7f7266544a3f34281c1003000000000000000000000000000000000000000000000000000000000000000000000407090a0d0d0d0d0d0d0d0d0c0b09030606060b0f1213120f0b06090806030000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000613202c3945515d677683909dabb4bdb1a89f92867d746f6d6c6e7179818f96a0acb9b9aca196897c6f6256493c2f231609000000000000000000000000000000000005111e2a36414d566774808d9aabb5c0b6a99d908376675d5145392c20130600000000000000000000000000000a15202c38444f5964717e8b96a1adb9bcb1a79c8f82756a5f5c5b5a5855534e4746413a332d261d160d0400000000000000000916232f3c4956626f7c8995a2afbcbaaea194877b6e6154483b2e2f3c4855626f7b8895a2aebbbdb1a4978a7e7164574b3e3124180b00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c54606b7784919eabb5c0b9ada1978b7e7164584e43372b1e1308000000000000000814212e3a47535f6a6e7070707070707070706f6b605448382d34404b55626f7c8899a3afbbbdb2a8978a7d7064574a3d3124170a00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a9698989898989896897c6f6356493c30231609000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000c1926333f4c5966727f8c99a5b2b9ada196877a6d605349474f596673808d99a6b3b9ac9f928679675d63707c8997a1adb9aea2988a7d7063544a3f34282b2d2f313334353434322f2d2c28231d1b150d080200000000000000000000000000010e1a2734414d5a6774808d9aa7a89c8f8275695c4f423024190d0100000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000000000000000000000000000000030608070c101314141515141413100c07070604000000000000000000000000000000000006121f2b37434e5865717e8b98a2aeacacacacacacacacacacacacacacacacacacacaca195887b6e6255483b2f22150800000000000000000000000005121e2a36424d576874818e9ba7acacacacaca89c8f8275665c5044382b1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003060606030000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080004111d2935414c5566727f8c99a3aebabaaea2989287817c7a797a7e848f939ea8b2bdb3a99e9184786c605346392d2013060000000000000000000000000000000000020e1925303d4a5764707d8a99a3afbbb9ac9f92867a6d6054473a2d211408000000000000000000000000000004101c27333d4653606d7984919eaab4bfb7aa9e94887c6f62574d4d4b4847433c39353027221b140b040000000000000000000916222f3c4955626f7c8895a2afbbbbaea295887b6f6255483c2d303c4956636f7c8996a2afbcbdb0a4978a7d7164574a3e3124170b00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c4f5966737f8c99a4afbbbeb3a99d9083766a5f54473a3024190d000000000000000815222f3b4855626e7b7d7d7d7d7d7d7d7d7d7d6f6353493f332f394653606c7986929facb9bfb2a5998c7f7266594c3f3326190c00131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3a5a5a5a5a296897c6f6356493c30231609000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000d1a2733404d5a6673808d99a6b3b7ab9e918478685d52413e4b5764717e8a97a4b1bbafa399867a6d60606c7985919eabb8b4aa9b8e8174665c5044382c1f20222526272828272523201f1c18120f0a04000000000000000000000000000000020f1c2935424f5c6875828f9ba8aa9d9084776a564c4135291d110400000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000000000000000000000000000000406070809080807060400000000000000000000000000000000000000000000020f1a26313c4754606d7a86929facb8b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9aea195887b6e6255483b2f2215080000000000000000000000000714212d3a46535f697884919eabb7b9b9b9b8ab9f9285796d6053463a2d20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800010d19242f3a4754616d7a86929fa9b3bdb3aaa299928d898686878b91959ea5afbab9ada1978c7f72655b5044372b1f12050000000000000000000000000000000000000814212d3a4754606d7a86929facb9bbafa3998a7d7063574a3d3025190d0100000000000000000000000000000b161f2c3845515c66727f8c98a2aebabbb0a69b8e8174695e53463e3b3a37312d29241e17110a02000000000000000000000815212e3b4854616e7b8794a8b2bdbdb0a4978a7d7164544a3f3b3b3f4a5465717e8b98a4b1bebcb0a396897d7063564a3d3023170a00121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5054616e7b87939facb9c5b8ab9f95887c6f62564c4135291b11060000000000000d1a2733404d5a6673808a8a8a8a8a8a8a8a8a8477655b5044372d3844505b667885929eabb8c0b3a69a8d8073675a4d4034271a0d00121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413025313d4a5764707d8a97a3b0b2b2afa295887c6f6255493c2f221609000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000e1b2734414e5a6774818d9aa7b4b7aa9d9084776a564c413d4a5663707d8996a3b0c0b5ab94877b6e615b6674818d9aa9b3b8ab9e9285796d6053463a2d221715181a1b1b1b1a18161313100c0700000000000000000000000000000000000004111d2935414c556a7784909daaab9f928578685d5245392c20130700000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915202c3945515d6775818e9ba8b2bdc9d0c7c0bbb9aeacacacacacacacacacacaca195887b6e6255483b2f2215080000000000000000000000000815222e3b4855616e7b8896a1acb9c5c6c6baaea298887c6f6255493c2d22170b0000000000000000000000000000000001070b0f1112131313131313131313100f0d0a0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000813202d3946525e6874808d97a1abb5bcb3aba39f9a95999399979da0a8afb7b9afa59e92857a6d6053493f33271b0f030000000000000000000000000404040404040613202c3945515d677683909da9b6c0b5ab9a8d807367564c41362a1d1105000000000000000000000000000004101c2834404b54606d7a85929fabb5c0b9ac9f92867b6e61564c41352e2b26201d19130b060000000000000000000000000714202d3a4753606d7a8696a1acb9c0b3a69a8d8073665b5049484849505c6674818d9aa7b4c0bdb2a895887c6f6255493c2f22160900121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50525e6976828f9ca9b3bebcb1a79a8e8174685d5245382d22170b0000000000000d192633404c5966737f8c969696969696969285796c6053463b3a3a45525d687885929fabb8c1b4a79a8e8174675b4e4134281b0e00121e2b3845515e6b7884919eabb7c2b5a89b8f827568564d41362c303e4b5864717e8b97a4b1bebdb2a894887b6e6155483b2e221508000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000f1b2835424e5b6875818e9ba8b4b6a99d9083766a5d50433c4956636f7c8996a2afbbaea295887b6f625463707d8997a1adb9ada297897d706353493f33271b0f0b0d0e0e0e0d0c0907060400000000000000000000000000000000000000000613202c3945515d677885929fabaea298877a6d6054473a2d21140700000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000000000000000030608090a0a0a0a0a0a0a0a0a0a070705010000000000000000000000000000000000000000000004111d2935414c5563707d8996a0acb9c7c7beb6afaca19f9f9f9f9f9f9f9f9f9f9f9f95887b6e6255483b2f2215080000000000000000000000000b1825313e4b5864717e8b97a8b2bdc9d5cabeb3aa988c7f7265544a3f33281c0f030000000000000000000000000000050c12171b1d1e2020202020202020201d1c1916100a030000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000005111e2a36414c56616d7a859299a4afb5bdb5aeaca7aba49fa4abaaacb1babab0a79e938b7e71685d5241382d22170b0000000000000000000004060711111111111111111d2935414c556673808c99aab4bfb7aa9d908377685e5246392d2013070000000000000000000000000000000c18232e3945525d6874808d99a3afbbbbafa3998d8074685d5245392f231a15110d08020000000000000000000000000006131f2c3845515d677884919eabb7c4b7ab9e9184786c605a565455565a606d7885919eabb8c4b9aca096877a6d6054473a2d21140700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504d5764717e8a97a2adb9c2b8ac9f92867a6d6053493f33271b0f0300000000000c1825323f4b5865727e8b98a3a3a3a3a3a297887b6e62574d4746474b54606d7a8798a2aebac1b4a79a8e8174675b4e4134281b0e00111d2a3744505d6a7783909daab6c3b7aa9d908477685e52463c393a424d576673808c99a6b3bfb9ada196877a6d6054473a2d211407000a1724313d4a5764707d8a97a3b0bdbcafa295897c6f6256493c2f2835424f5b6875828e9ba8b5c1b7ab9e9184786b5e5145382b1e12000000000f1c2835424f5b6875828e9ba8b5b6a99d9083766a5d50433c4956636f7c8996a2afbbafa295887c6f6255606d7985929eabb8b3a99a8d8174655b5044372b1f12050001020101000000000000000000000000000000000000000000000000000714212d3a4754606d7a8797a2adb4aa95887c6f6255493c2f22160900000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000000000000000000040a0f131516171717171717171717171413110d08020000000000000000000000000000000000000000010d19242f3a4653606c7884919eabb5c0c0b6aca49f9493939393939393939393939393887b6e6255483b2f221508000000000000000000000005121e2a36424d576874818e9ba7b4c1cedad0c2b5a89c8f8275665b5044382b1f120600000000000000000000000000060f161d23272a2b2d2d2d2d2d2d2d2d2d292926211c150d0400000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000010d1925303a46525e68707d87939fa3abb2b8bbb9b4b5afacafb5b7b8bab4aea69f958f81756c62564c412f261b11060000000000000000070c1013131e1e1e1e1e1e1e1e19242f3d495663707c8998a2aebab9ac9f93877a6d6154473a2e21140900000000000000000000000000000007121d2935414c56616e7b87929facb9c0b5ab9f92857a6d60554b4034291c11060100000000000000000000000000000004101d2935404b556875828e9ba8b5c1b9aca1968b7f726c6562616162656c727f8c97a1adb9c4b7aa9e918477685d5245392c20130700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504653606d7985929eabb8c3baaea2988c7f72655b5044372b1f140900000000000a1724303d4a5763707d8a96a8b2b0b0b3a9998c8073695e57545354555d66717e8a97aab3bec0b3a79a8d8074675a4d4134271a0e000f1c2835424f5b6875828e9ba8b5c1b8aca095877b6e61564d4745474b545f6976828f9ca9b6c2b8ab9e918478685d5245392c201306000a1724303d4a5763707d8a96a3b0bdbcafa396897c706356493d302834404b546975828f9ca8b5c2b7aa9d9184776a5e5144372b1e11000000000f1c2835424f5b6875828e9ba8b5b6a99d9083766a5d50433c4956636f7c8996a2afbbafa295887c6f62555c6674818e9ba9b3b8ab9e9184786c605346392d20130a0000000000000000000000000000000000000000000000000000000000000915222f3c4855626f7b8895a9b3b0a3978a7d7064574a3d3124170a00000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508000000000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000000000070f161b1f22232323232323232323232321201d19130c05000000000000000000000000000000000000000008131f2b3744505b65737f8c99a4afbbbbafa49a938886868686868686868686868686867b6e6255483b2f22150800000000000000000000000714212d3a46535e697884919eabb7c4d1ded2c5b8ab9f9285796c605346392d201306000000000000000000000000050f1820282f3337383939393939393939393635322d261f160d03000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000008131e2935414c56616b727f8b9299a0a8acb2b5b7b8b9b9b9b8b6b4aeaaa39f948f83796d605a50433a2f1d140a00000000000000030b12181c1f202a2a2a2a2a2a2a2a2a2a2d3a4653606d7985929facb8bbafa49a8a7d7164574a3e30251a0e020000000000000000000000000000000d19242f3a46535e6975818e9ba6b0bbbaaea2988c7f73675c5145382d22170b00000000000000000000000000000000000c18242f3f4c5965727f8c98a6b0bbbdb2a89f92867e76726f6e6e6f72767e86929fa9b3bebdb2a89a8e817467564c4135291d110400121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5045515c6774808d9aa7b1bcbfb4aa9e9184786c6053463b30251a0e00000000000814212e3b4754616e7b8796a1adb9bdb8ab9f92857b6e696361606062676d7883909daab6c3bfb5ab988c7f7265594c3f3226190c000c1926333f4c5966727f8c99a9b3bebcb1a7998c7f72685f57535153555d666e7b87939facb9c2b5a89c8f827569564c4135291d1104000a1623303d495663707d8996a3afbcbdb1a4978a7e7164574b3e312c3845515c667783909daab6c3b6a99d9083766a5d5043372a1d10000000000f1c2835424f5b6875828e9ba8b5b6a99d9083766a5d50433c4956636f7c8996a2afbbafa295887c6f62555463707d8a97a2adb9ada197897c6f6356493c32261b0f0300000000000000000000000000000000000000000000000000000000000a1724303d4a5763707d8a96a3b0b2a5988b7f7265584c3f3225190c00000000000000000000000005121e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211508050100000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000000007101920272b2e2f303030303030303030302e2d2a251e170e0500000000000000000000000000000000000000030f1b27333f4953616e7b87939facb9b9ac9f93877b7979797979797979797979797979766a5f53473a2e21140800000000000000000000000815212e3b4854616e7b8796a1acb9c5d2d2d3c6baada297887c6f6255493c2d22170b0000000000000000000000010c16202a323a3f434546464646464646464643423e3831281f150a000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e211408000000020d1925303a444f59626d727f8791969ea0a8a8aaacacafacaba9aaa29f98928c82796d675d51483f31281e0b02000000000000030c151d23282c2d37373737373737373737373845515c6676828f9ca9b5c0b6ac9a8d817467574d42362a1e120500000000000000000000000000000008131e2a36424d57626f7c88949fabb7bfb4aa9e9285796d60544a3f33281c0f03000000000000000000000000000000000715222e3b4855616e7b88949fabb7c1baaea398928a837e7c7b7b7c7f838b9298a3aebbc4b9aca1968a7d7063574a3d2f24190d0100121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50404b55626f7c8895a0acb8c6b8aca096897d7063574d42362a1d1207000000000714202d3a46525e697884919eabb8c3baaea29891837b736f6d6d6d6f7279818e95a0abb8c4bbaea399897d7063564a3d3023170a00091623303c4956636f7c8997a1adb9c3b8ab9f92867a6e6962605d5f61676d78828f99a4afbbbcb1a7988c7f7265594c3f2f24190d01000815222f3b4855626e7c8895a8b2bdc0b3a6998d807366574d4238383d4653606d7985929facb8c2b5a89c8f8275695c4f4236291c0f000000000e1b2835414e5b6874818e9ba7b4b6aa9d9083776a544a3f3d495663707c8996a3afbbaea195887b6e625553606d7985929fabb8b2a99a8d807367584e43372b1f130600000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1b3a69a8d8073675a4d4034271a0600000000000000000000000000061e2b3845515e6b7884919eabb7baaea194877b6e6154483b2e211515110c06000000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000000000000061019222b32383b3c3d3d3d3d3d3d3d3d3d3d3a3936302920170c02000000000000000000000000000000000000000b17222d3846535e6976828f9ca9b3bbafa49a8c8073656c6c6c6c6c6c6c6c6c6c6c6c6c5f574e42372b1e120600000000000000000000000b1825313e4b5864717e8b97a8b2bdc9c6c5c6cabeb3a9988c7f7265544a3f33281c0f030000000000000000000007121d28323c444b5051535353535353535353504e49423a31261c10050000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e2114080000000008131e28323e47515b626d727d848b9196999c9d9f9fa39f9e9c9a98928d867f786d675d554b40362d1f160c000000000000000b151e272e34383a444444444444444444444444404b5465727f8c98a9b3beb7aa9e918477695e52463a2d201407000000000000000000000000000000010e1a25313b4754606a7683909ca8b1bdb9ada1978b7e72665b5044382b1f160b000000000000000000000000000000000714212d3a46535f697683909ca5afbabfb4aaa39f94908b898788898b90959fa3aab4bfbcb1a79e9184786d6053463a2d2013080000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504347535f6a7783909daab4bfbdb2a89b8f8275695e5246392e23180c0000000005111e2a36424d576774818e9aa7b1bcbeb3aaa0959186807c7a797a7c7f848e939ea7b1bcc5b9ac9f92867a6d6053473a2d201407000713202d3a4653606d7985929eacb6c0baaea29891847b746f6d67696e7279818e949fabb5c0b8ab9f95887b6e6155483b2e22150800000714202d3a4753606d798696a0acb8c3b6a99c908376695e534a4645464f5863707c8998a2aebac0b3a69a8d8073675a4d4034271a0d000000000d1a2734404d5a6773808d9aa6b3b7aa9d918477665c50443d4a5764707d8a97a3b0beb3a994877a6d6154515c6675818e9baab4b7aa9e9184776a5f53473b2e21150900000000000000000000000000000000000000000000000000000000000d1a2733404d5a6673808d99a6b3b4a89b8e8175685b4e422d22170b0000000000000000000000020a11172b3845515e6b7884919eabb7baaea194877b6e6154483b2e2524211d1811090000000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000020d1a2734404d5a6773808d9aa6b3beb2a5988b7f7265584c3f3225190c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000000040e18222b343d4347494a4a4a4a4a4a4a4a4a4a4746413a32291e13080000000000000000000000000000000000000006111b2a36424d5764717e8a97a2adbab6ac9e9184786c60606060606060606060606055534e453c31261a0e020000000000000000000005121e2a36424d576874818e9ba7b4c1bfbab8babfc2b5a89b8f8275665b5044382b1f1206000000000000000000000b17232f3a444e565c5e6060606060606060605c5a544c42382d21160a0000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845525e6b7885919eabb8baada194877a6e6154473b2e21140800000000020c16202c353f49515b626b6f787f84888c8f919293999291908d8a86817b736c665d554b43392f241b0d0400000000000007121d273039404546515151515151515151515151515155626f7c8897a1adb9b8aca096877b6e6154483b2e2115090000000000000000000000000000000009141f2b37434e5864707d8a95a0acb8beb3a99e9184786c6053463d32271c100400000000000000000000000000000005121e2b37424d5763707d89939ea8b2bbbcb4aea69f9c9895949495989d9fa7aeb4bcbdb4aaa0958b7e72665c5044382b1f12060000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043434e5865727f8b98a3aebac3b9ac9f92877b6e61544b4034281c1004000000020e1a25303d495663707d8995a0acb8c2bcb1a7a098928d89878687888c91969ea5afb9c3bdb1a79c8f8275675d5145392c2013060006121f2b3844505c6674818d9aa4afbbbeb4aaa0969186817c7a78797b7f848e939ea6b0bdbdb2a89d908376695f53463a2d211407000006131f2c3945515d677784919eaab7c4b9ac9f92877b6e615c5452515359606a75818e9baab4bfbcb1a7978b7e7164584b3e3125180b000000000d192633404c5966737f8c99a6b2b9ac9f9286796d605346434d5765727f8c98a5b2b9ada19786796d60534b5464707d8a98a2aeb9aca096887c6f6255493c31261a0e02000000000000000000000000000000000000000000000000000000020f1b2835424e5b6875818e9ba8b4b6a99c90837669544a3f33281c0f03000000000000000000020b141b22273845515e6b7884919eabb7baaea194877b6e6154483b3232312e29221b120900000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000002090e121a2734404d5a6773808d9aa6b3beb1a5988b7e7265584b3f3225180c0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000000000000000a15202a343d464e54565656565656565656565654524c443a3025190d01000000000000000000000000000000000000000e1a25313b4753606d7985929fabb8b9aca196897d7063564c5353535353535353534847423c332a20150900000000000000000000000714202d3a46525e697784919eaab7bcb4aeacaeb4bcb8ab9f9285796c605346392d201306000000000000000000000f1b27333f4b5660686b6c6c6c6c6c6c6c6c6c69665e54493e3226190d0100000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e4134404b556b7885929eabb8baada194877a6e6154473b2e2114080000000000040e1a232d373f49515960666d72777c7f8284858686868583807d7a746e69605b544b433a31281d1209000000000000000c18232e39424b51535d5d5d5d5d5d5d5d5d5d5d5d5d5d5d606c7885929eabb8bdb2a8978b7e7164584b3e31261a0e02000000000000000000000000000000030f1b27323c4653606c7884919da9b3beb9aca0968a7e7164594f44382c20150a000000000000000000000000000000020e1a26313c4855606b75828f96a1a9b2bbbfbab0aba9a5a2a1a1a2a5a9abb1babfbcb4aba2989083786d60544a3f34281c10030000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433c4754616d7a86929facb9c4bbafa3998c8073665c5145382c1f150a000000000916222f3b4854606b7784919da6b0bac3b9b1aaa29f9a9694939395999ea1a8afb7c1bfb5ab9f958a7d7063554b4035291d11040003101c28343f4a54626e7b87939faab4bebcb2a8a098928d88868586888c91969ea5afb8c2b8aca0968a7e7164574d42372b1e1205000004101d2935404b556874818e9ba9b3bebbafa3998e81756d66615e5c60636b707c88939facb9c6b8aca095877b6e6154483b2e211508000000000b1825323e4b5865717e8b98a9b3baaea398897c6f6258514e555e6975828f9ba8b5b8ab9e918578665c504753606d7986929facb8b2a8998c807366574d42372b1e1206000000000000000000000000000000000000000000000000000000030f1c28333f4a54697683909ca9b6b7ab9e918478665b5044382b1f12060000000000000000000a141d262d333745515e6b7884919eabb7baaea194877b6e6154483f3f3e3d3a342d241b1106000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000000050d141a1e202534404d5a6773808d9aa6b3beb1a4978b7e7164584b3e3125180b0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000000000000030f1b26313c464e58606263636363636363636363615e564c41362a1d11050000000000000000000000000000000000000009141f2c3845515c6774818d9aa7b1bcb2a89b8e8175685d524546464646464646463b3a37312a21180e0300000000000000000000000815212e3b4854616e7b8796a0acb9b4aaa29fa2aab4baada297887c6f6255493c2d22170b00000000000000000000111d2a3743505c6872787979797979797979797670665a4e4235291c0f0300000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8d8174675a4e413845515c677985929facb8baada194877a6e6154473b2e21140800000000000008111b252d373f474f545c60656a6f73757779797979787674716d67615e57504a423a31281f160c0000000000000004101c2834404b545c606a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6575828e9ba8b5c1b4a79b8e817468574d42372b1e1206000000000000000000000000000000000a151f2b3744505b65717e8b97a1adb9bdb2a89d9083776b6054483c31261b0f0300000000000000000000000000000009141f2c38444f59616d7a849197a1a9b0b9bdbbb7b6b1afaeaeafb2b6b8bcbebab2aaa29992867c6e665c5042382e23170b000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433946525d6875828e9ba8b2bdc0b5ab9e9285796d6053463c31261b0f010000000713202c38444f5964707d8a949ea8b2bbc3bcb4aeaca6a2a0a0a0a2a5abacb2bac1c0bbaea3999083766b6155433a2f24180d0100000b17232e3847535f6a75818e98a2aebac0bab2aaa29f9a9597929299989ea1a9afb7c1b9afa59e9184796d6053463c31261a0e020000000c18242f3e4a5764717d8a97a2adbac0b5ab9e938d8078716e68676d6f747d85929aa4afbbbfb4aa9d908377695e52463a2d201407000000000815222f3b4855626e7b8897a2adb9b4aa9a8d81746a605c585f676e7b87929facb9b5a89b8f827568544a45515d6775828e9baab4b7aa9d918477695f53473a2e21140900000000000000000000000000000000000000000000000000000006121f2b3844505b667884919eabb7b9ac9f9286796c605346392d201306000000000000000006111b262f383f4446515e6b7884919eabb7baaea194877b6e61544c4c4c4b4a453f362d22180c010000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000000050f171f252a2d3036414d5a6774808d9aa7b3bdb1a4978a7e7164574b3e3124180b0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000006121f2b37434e58606a6f707070707070707070706d685e5246392d2013070000000000000000000000000000000000000004101c2934404b55626f7c8895a0acb8b8ac9f92867a6d6054473c313939393939392f2e2b2620180f060000000000000000000000000b1824313e4b5764717e8a97a8b2baaea2989298a2aebab3a9988b7f726553493f33271b0f03000000000000000000121e2b3845515e6b78848686868686868686868276695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a79a8e8174675b4e413a4653606d7986939facb9baada194877a6e6154473b2e2114080000000000000009131b252d353d424a515358606266696a656c6d666b696764605d55534d443f382f281f160d040000000000000006131f2c3845515c666d7777777777777777777777777777777777777e8b98a5b1beb8ab9e918478695f53473a2e21140600000000000000000000000000000000030f1b27333f4953606d7985929eaab4bfb8ab9f95897d7063584e43372b1f140900000000000000000000000000000003101c27333d46525e686f7c8591969ea6acb2b9babfbebcbabbbcbec0bbb9b4aea8a09892877d706a5f544a3f30261c1106000000121e2b3845515e6b7884919eabb7bfb6a99c8f8376695c504335414c5663707d8a96a1adb9bfb9ada1978a7e7164584e43372b1e130800000004101c27323d4955616c76828f96a1a9b2bac1bfbab8b3afadacadafb2b7b9bdc4beb6afa49f92877c6f62594f4431281d130700000006111c2b37434e58616e7b86929fa4aebbc0bcb4aeaca7a9a29f9fa3ababadb2bbc1b9b1a79e938a7d70665c5144382a1f1409000000000714202d3a4753606d7985929faab4bfbdafa59d928d837e7a7978797c81879297a2acb6c0baaea2988c7f7266574d42362a1e1205000000000613202d394653606c7985929eabb8b9ac9f92877c716d67696a6f79828f99a3afbbb0a6988c7f7265594c404b5564717e8a98a3aeb8aca095887b6e6255483b31251a0e0200000000000000000000000000000000000000000000000000000613202d394653606c7986929facb9bbafa399877a6e6154473b2e21140800000000000000000b17222d3841495053585e6b7884919eabb7baaea194877b6e6158585858585650483f34291d11050000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000020d17212930363a3b42464d576875818e9ba8b4bdb0a3968a7d7063574a3d3024170a0000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000000020b1a232e3a47535f6a6f7c7d7d7d7d7d7d7d7d7d7d7a6d6154473a2e21140700000000000000000000000000000000000000000c18232f394754606a7783909dabb5baaea2988b7e7265584e43372b2d2d2d2d2d22211e1a150e0600000000000000000000000005111e2a36424d576774818e9aa7b4b8ac9f9285929faab4b5a89b8f8275655b5044372b1f1205000000000000000000121e2b3845515e6b788491939393939393938f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb4a89b8e817568544a3f3b4855616e7b889aa4afbbbaada194877a6e6154473b2e211408000000000000000109131b232b30394044464e5455595c535b60605c545d5a5753514b46423b332d261d160d0400000000000000000713202d3a4653606d7983848484848484848484848484848484848384919eaab7c4b9ada196887b6e6255483b2d22170b00000000000000000000000000000000000b17222d3845515c67737f8c98a2aeb2b2b1a79c8f82766a5f53473b31251a0e020000000000000000000000000000000b16212a36414c565f6a6f7c848f949ea0a8acaeb4b3b4b5b5b5b3b5afacaaa29f9691867e706b61574e42382e1e140a00000000121e2b3845515e6b7884919eabb2b2b2a99c8f8376695c5043303a4653606c7884919eabb2b2b2b3a99c9083766a5f53473a2f24190d010000000b16212d3944505a616e7a849197a1a8afb7bbc2c5c0bcbab9babbbfc4c4beb9b2aca49f928b7f726a5f53473e331f160c01000000000f1a26313c46535e69717e8b929da4afb5bdbfbab8b4b3adabacaeb5b8b9bdbebab0a7a0958e81756b61544a403428180e030000000006131f2c3945515d6773808d98a2aebac1b7aea49d95908b87858586898e9299a2a9b3bebeb3a99f92867a6d6154473b30251a0e020000000005121f2b3744505b6575828f9ba7b1bbafa39992867e797776787c828f949fabb5b7ab9f94887c6f6255483c4754606d7a86929facb9b1a7998c7f7266574d42362a1e120500000000000000000000000000000000000000000000000000000814212e3b4754616e7a8799a3afbbc0b5ab95897c6f6256493c2f23160900000000000000030f1b27333f49535b6065656b7884919eabb7baaea194877b6e656565656565625a50453a2e2115090000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000009141f29333b4246484d52545f697784909daab7bdb2a895887b6f6255483c2f2215090000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000000000000000a141d2c38434e58626f7c87898989898989898989847a6d6053473a2d201407000000000000000000000000000000000000000007121d2b37434e5865727f8c99a3aebbb4aa9d9083766a5f5347382e23172020201514120e0903000000000000000000000000000714202d3a46525e697784919eaab7b5ab9a8e818e98a3aeb8ab9e9285796c605346392d201306000000000000000000121e2b3845515e6b7884919e9f9f9f9f9f9c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000c1926323f4c5965727f8c98a5b2bfb6a99c8f8376665b50443d4a5663707d8996acb6c0baada194877a6e6154473b2e2114080000000000000000000910191e272e34383c4347494c4f49505353504a504d4a47454039363128221c140b040000000000000000000714202d3a4753606d7a8690909090909090909090909090909090909196a0acb9c5bdb2a8988b7e726553493f33271b0f030000000000000000000000000000000006111b2934404b55616d7a86929faba5a5a5a59f94887c6f62574d42362a1e1205000000000000000000000000000000050d1925303a444e58606a6f7a828a91969c9fa3aba7a8a8a8a8a7aba49f9d98928c847c706c61594f453c30261c0c0200000000121e2b3845515e6b7884919ea5a5a5a5a59c8f8376695c5043363844505b6673808d99a6a5a5a5a5a59f94887c6f62554c4135291d110400000005101c28333e46525e686f7c8591969ea5abb0b6b8babfbdbdbdc0bbb9b7b2ada8a19a938c80736d62584e43352c210d0400000000000915202a36424d57616c73808d929fa3abb1b8bdc3c0bebab8b9bbbfc3beb9b3ada69e959083796d60594f42392e231806000000000004101d2935404b55616e7b86929fa7b1bac0b6aea7a09d9798929292999a9fa3abb3bbc1b9ada1978d8074685d524639291f14090000000000030f1b27333f495363707d8995a0acb8b5aba298928b858383848890949fa6b0bcb1a79c9083766a5f53473b45515d6775828f9cabb5b6aa9d908377695e53463a2d21140800000000000000000000000000000000000000000000000000000916232f3c4956626f7c8995abb5c0bdb0a3978a7d7064574a3d3124170a0000000000000005121f2b3744505b656c7272727884919eabb7baaea194877b727272727272716c62564a3d3124170b0000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000020e1a25303b454d5254575e61666e7b8895a0acb8b9aca196877a6d6054473a2d2114070000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000000000000006111b262f384854606a75828f99969696969696948a7e71675d5145392c2013060000000000000000000000000000000000000000010f1b27323c4754616d7a86929facb9b8ab9f95887b6e62544a3f34281c101313080806020000000000000000000000000000000814212e3b4754616e7b8796a0acb9aea399897c86929facb8ada297887c6f6255483c2d22170b000000000000000000121e2b3845515e6b7884919eabacacaca99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e8b98a4b1beb8ab9f9285796c605347464f596673808c99a6b3bfbaada194877a6e6154473b2e21140800000000000000000000070c151c23282c32373b3c40423f444646443f43413e3a39352f2a251f17110a02000000000000000000000714202d3a4753606d7a86939d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9ea0a8b2bdc8c1b5a89b8e8275655b5044372b1f120500000000000000000000000000000000000c18232f3946525e6874818d99989898989898988e8175695e53463a2d2114070000000000000000000000000000000008131e29323c464e5860686e767e848a8f9299989a9b9c9c9b9a989993908b857f796f6a615a50473e332a1e140a0000000000121e2b3845515e6b788491989898989898988f8376695c504336333f4a54616e7b889498989898989898988d8174675d5145392c201306000000000b17222a36414c565f6a6f7c848e939c9fa6a9acaeb4b0b0b0b6afacaaa9a19e9691887f736e635b51463c32231a10000000000000030e1a25313b45505a606c77808c9299a0a7acb2b7b9bbc0bcc0bbb9b7b3ada9a29f948f837a6e675d51473e30271c12070000000000000c18242f3946525e68737f8c959fa8b2bac0b9b1acaaaaa29f9e9fa3abacafb5bdc0bbaea49e92857a6d60564c413529170d030000000000000b17222d384854606b7783909da5afbab3aaa29f9892909091969c9fa6b0b8b4aaa0958a7d7064584e4337414c5565717e8b99a3afb8ab9f95877b6e6154483b3025190d01000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdbeb1a5988b7e7265584b3f3225180c000000000000000613202d394653606c777f7f7f7f85929eabb8bfb2a6998c7f7f7f7f7f7f7f7e7165584b3e3225180b0000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000005121e2a36424d575e616b696e7178828f9ca7b1bcb7ab9e918478675d5145392c2013060000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d1003000000000000000000000000000003090e17222d38414f59626f7c89949eaba3a3a3a3998f82766c61554b4035291d10040000000000000000000000000000000000000000000a15202d3946525e6875828f9ba9b2bcb1a79a8d8073665c5044382c1f130800000000000000000000000000000000000000000b1824313e4b5764717e8a97a8b2b9ac9f92867983909da9b6b3a9988b7f726553493f33271b0f030000000000000000121e2b3845515e6b7884919eabb7b9b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000b1724313e4a5764717d8a97a4b0bdbaada297897d70635c535356606b7783909daab6c3baada194877a6e6154473b2e2114080000000000000000000000030b12181c1f272b2e2f332d3337393a38342e34312d2c29241d1a140b060000000000000000000000000714202d3a4753606d7a8693a0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacb2bac3cec5b8ab9e9285786c605346392d201306000000000000000000000000000000000007121d2935414c56616e7b878c8c8c8c8c8c8c8c8c867b6e6154483b2e21150800000000000000000000000000000000020d17202a343c464e565e616c71787d8286898b8d8e8f8f8e8d8c8986837f7a736d675f5850473e352c21180c020000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8376695c5043362d3846535f6976828c8c8c8c8c8c8c8c8c8c857a6d6054473a2d21140700000000050e1925303b444e585f6a6e7a81898f94999c9fa2aaa3a4a3aca49f9d9a97918c847d726d635c52493f342a2011080000000000000009141f29333e44505b656c747f8790959ea0a8aaacafb5afb5afacaaa9a19e97928b82796e685e554b40352c1e150b0000000000000007121d2a36414d56606d78839096a1a8b1bbc0bcb8b7b4aeacabacafb5b9bbc0beb6afa59d928a7e71685d52443a302419050000000000000006111b2c38444f5964717e8a939ea8b2bab3aeaaa29f9d9c9ea1a8abb0b8baaea2989083786c6053463c323a4754616d7a86929facb9b1a7988b7f7265564c41362a1e1105000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1bebfb3a6998c807366594d4033261a0d000000000000000713202d3a4653606d79868b8b8b9297a2adb9c0b4a89c918c8b8b8b8b8b8b85786c5f5245392c1f120600000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000714202d3a46525e696e78797b7e838f949fabb9bfb4aa9b8e817568554b4135291d11040000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d100300000000000000000000000002090e141a1e27333f4953606b76828f9ca6b0b0b2a89f92867b6e615a5043392f24180d0100000000000000000000000000000000000000000005111d2a36414c5663707d8a97a1adb9b8ab9e9185796d6053463a3025190d0100000000000000000000000000000000000005111e2a36414d566774818e9aa7b4b6aa9d908377818d9aa7b4b5a89b8f8275655b5044372b1f12050000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100300000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707c8996a8b2bdbeb3a99c9082766e63606061686f7c89959fabb8c4baada194877a6e6154473b2e21140800000000000000000000000000070c10151b1f22222622272b2d2d2c2823272420201d18120e0903000000000000000000000000000714202d3a4753606d7a8693a0adb7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b9bdc3cccbc6b9ada197887c6f6255493c2e23170c0000000000000000000000000000000000010d1925303a47535f69717e7f7f7f7f7f7f7f7f7f7f7c6f6255493c2f2216090000000000000000000000000000000000050e18222b343c444d525a61666d71767a7d7f8081828282807f7d7a76726d68605d554e463e352c231a0f060000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7e7164574a3e312a36424d57626f7c7f7f7f7f7f7f7f7f7f7f7f7b6e6155483b2e221508000000000008141e29323c464e585f686d757c82888c8f929896969797969a93918e8a847f79706b635b524a40372d22180e0000000000000000030d172127333f49535b606d727d838b91969a9d9fa3aba3aba39f9d9a97928c857e756d675e564d43392f231a0c0300000000000000010e1925303b44505c666e7b849196a0a7afb5bbc0c3bfbab8b8b9bbc0c3bdb8b2aca49f938d80736c61564c4132281e13080000000000000000101c27333d4955616c75818e96a0a8b0b9bab4aeacaaa9abacb2b7bbb4aea39f92867b6e665b5044382d3946525e6876838f9ca9b6b6a99c908376685e5246392d201308000000000000000000000000000000000000000000000000000d1a2633404d596673808c99a6b3bfc1b4a79a8e8174675b4e4134281b0e010000000000000713202d3a4653606d79869398989ea2a9b3bec4b8ada39c9998989898989285786c5f5245392c1f120600000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b8585878b90959fa6b0bbbaaea2988b7e7165584b3e2f24180d010000000000000a1724313d4a5764707d8a97a3b0bdb6a99c908376695d5043362a1d10030000000000000000000000050d14191f262a2d3744505b65707d89949fabb8b9aca1968d8073695f53483e31281d120700000000000000000000000000000000000000000000010d1925303a4653606d7984919eabb8b9ada1978a7d7063564c41362a1d11050000000000000000000000000000000000000714202d3946525e687784919daab7b4a79a8d81747e8b98aab4b8ab9e9285796c605346392d2013060000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d100603000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a8796a0acb9c5b7ab9f948d8076706d6c6e717a84919ea7b1bcc8baada194877a6e6154473b2e211408000000000000000000000000000000040a0f13151619171b1f20201f1c171a171413100d07010000000000000000000000000000000714202d3a4753606d7a8693a0adb9bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbeb3a9988c7f7265544a3f34281c1003000000000000000000000000000000000008131e2b37424d57616c71727272727272727272726f6a6054473b2e221508000000000000000000000000000000000000071019222b323b414650545c6064676d707274757575757472706d6865605d56514b433c342c231a1108000000000000000b1724313d4a56626c71727272727272727272716c6155493d3026313b4754606a6f72727272727272727272726e695f53463a2d2114070000000000020d17202a343c464e565d606b6f767b7f838587898a8a8a89888684817d79726d676059514940382e251b1007000000000000000000050f17222d384149505b636b6f787e84898d9092999596959992908e89857f7a716c605d554d443b31271d110800000000000000000008141f28343f4a545e696e7c8490959fa3abafb5b8babfbdbdc0bbb9b7b2aca8a09a938c81786d605a50443a3020160c0200000000000000000b16212d3945505a606d7a8491969fa6adb2b7b9b8b6b6b7b9b8b5afaaa29f918b7e71695f544a3f332a36414c5665727f8b98a7b1b9ac9f93867a6d6154473a2f24190d010000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4c1c2b5a89c8f8275695c4f4236291c0f030000000000000713202d3a4653606d798693a0a5abadb3bbc5cabfb5ada8a6a5a5a5a59f9285786c5f5245392c1f120600000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b879298979da0a7b0b8bdb3a99f92867a6d6054473a2d211407000000000000000a1724313d4a5764707d8a97a3b0b2b2a99c908376695d5043362a1d100300000000000000000000080e171f252a31363a3f4a54606c7883909da6b0bcb0a69e9184796d60574d42362c1f160c01000000000000000000000000000000000000000000000008131f2b3844505c6673808d99a6b0bcb3a99b8f8275685e5246392d20150a0000000000000000000000000000000000000814212e3b4754616e7a8796a0acb8b4aa988b7e717b8898a2aeb9ada197887b6f6255483c2f22150a0000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336291d1312100b0607050200000000000000000000000000000000000000000000000000000000000000000713202c3945525d687784919eaab7c4bbb0a69c928d827d7a797a7e849196a0acb9c3cdbaada194877a6e6154473b2e211408000000000000000000000000000000000003060809060b0f12131312100c060b0706040100000000000000000000000000000000000714202d3a4753606d7a8693a0adb2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a89c8f8275665c5044382c1f12060000000000000000000000000000000000020e1a26313c45505a6164656565656565656565656260584e43372b1f130600000000000000000000000000000000000000071019202930363e424a5053555d6063656768696968676563615e5654524c454039312a221a110800000000000000000915212e3a45505a626565656565656565656564615a5045392d1f2b37434e5860626565656565656565656565615f574d42372b1e1205000000000000050e18222a343c444c52596063696e7276797b7c7d7d7d7d7b7a7774706d66605d554f4740372e261c1309000000000000000000000006111b262f383f44515960666d71787c80838688898989888684817d79726d68625a514c433b32291f150b00000000000000000000020c17232e38424d565f6a6e7b838d92999fa4abacaeb4b0b0b5afacaaa8a09d96918880746d665c50483e32281e0e0400000000000000000005111d28333e45515d676e7b8490949ea1a8abacb2afafb4aeacaba39f98928a7f726c62574d42382d25303b4854616e7b8795a0acb8afa4998b7e7165564c4135291d11040000000000000000000000000000000000000000000000020f1c2935424f5c6875828f9ba8b5c2c3b6a99d9083766a5d5043372a1d07000000000000000713202d3a4653606d798693a0acb8b9bec5cdd1c8bfb8b4b2b2b2b2ab9f9285786c5f5245392c1f120600000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b8794a2aaaaacb1b9bdb5aba2978d8174685d5245392c201306000000000000000a1724313d4a5764707d8a97a3a6a6a6a69c908376695d5043362a1d100300000000000000000109111a202930363b424648505c66717e8a95a0abb8b4aa9e948a7d70675d51453c31241a0d0400000000000000000000000000000000000000000000000003101c28343f4a54626e7b88949fabb7b9ac9f92867a6d6154473c32271b0f0000000000000000000000000000000000000b1824313e4b5764717e8a97a8b2baaea298887b6f7985929facb8b3a9988b7e7265584b3f31261a0f0200000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362921201f1c171414110e090200000000000000000000000000000000000000000000000000000000000004111d2935414c566875818e9ba8b2bdc2b8aea49c948f898686878b9196a0a8b2bbc1cabaada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000305060706030000000000000000000000000000000000000000000000000714202d3a4753606d798693a0a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a59f9285796d6053463a2d20130700000000000000000000000000000000000009151f2a333e485056585959595959595959595955544e463c32271b0f030000000000000000000000000000000000000000070e171f252a30383f44464b515356585a5b5c5c5b5a595654524c4745413a352f271f19100800000000000000000005111d29343f48505658595959595959595959575550483e33281d27323d464e5456595959595959595959595955534d453c31261a0e0200000000000000061018222a323a41454f54575f6266666c6e6f707170706f6d676763605c54514b433d352e251c140a010000000000000000000000000a141d262d333f474f545c60656c6f7477797b7c7c7c7b7a7774706d66605d565045413a312920170d03000000000000000000000006111c26303b444e575f696e7980878e93999c9fa2aaa3a3aba49f9d9a96918b847d736e605c544a3f362c20160c00000000000000000000000c17222935414c555f696e7a828b91969b9ea1a8a2a3aaa39f9c99928e867e726d635a50453c2f26212d3a46535e697783909daab6b5ab9c8f8276685d5245392c201307000000000000000000000000000000000000000000000004101d2a3743505d6a7683909da9b6c3c4b7aa9e9184776b5e51442e23180c000000000000000713202d3a4653606d798693a0b4b7b9bdc4ccd2c8c0b9b5b3b2b2b2ab9f9285786c5f5245392c1f120600000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b8794a1b4b7b8bcb9b3aba49992857a6d61564c4135291d1104000000000000000a1724313d4a5764707d8a97999999999999908376695d5043362a1d1003000000000000000009131b232b323b42464d535558606d7884919da7b1baaea3988f82756c61554b403328221c140b020000000000000000000000000000000000000000000000000b17232e3847535f697683909caab4bbaea3998b7f7265584e43372b1d12070000000000000000000000000000000005111e2a36414c566774818d9aa7b4b8ac9f9285796d7683909da9b6b5a89b8e827568584e43372b1f120600000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362e2e2d2b282321201e1a140f0a0400000000000000000000000000000000000000000000000000000000010d19242f3d4a5663707d8996a1adb9c2c0b6aea69f9c96999399989ea1a9a8aab0b8c1baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a869398989898989898989898989898989898989898989898989898989898897c6f6356493c30231609000000000000000000000000000000000000030e18212d363e45494b4c4c4c4c4c4c4c4c4c4c4947433c342b20150a00000000000000000000000000000000000000000000050d14191e262e34383a4045474a4c4d4e4f4f4f4d4c4a4746413a39352f29241d150d0700000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4a49453e362c2217202b343d4347494c4c4c4c4c4c4c4c4c4c4c4846423c332a1f1409000000000000000000060f1820282f353d44484d5355545b6061636364646362605d555753504a454039312b231c130a0200000000000000000000000000020b141b2227353d424a50535b606367666d6e6f706f6e6d676763605c54524c443f352f281f170e05000000000000000000000000000a151e29323c454e575e676d737c81878c8f9298969797969993918d89847e796f6b635c504a42382e241a0e040000000000000000000000050d19242f3a434d575f686e777e848a8e9196959696959892908c87817b716c635b51483f332a1d1e2a36424d5766737f8c99a8b2b9ac9f92867a6d6054473a2f24180c000000000000000000000000000000000000000000000004111e2b3744515e6a7784919daab7c4c5b8ab9f9285786c5f4a4034281c10040000000000000713202d3a4653606d798693a2aaabacb2bac2cac0b6aea8a6a6a6a6a69f9285786c5f5245392c1f120600000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b8794a1aeb8b6b3ada9a19993877e70685e52433a2f24190d01000000000000000a1724313d4a5764707d8a8c8c8c8c8c8c8c8c8376695d5043362a1d10030000000000000009121b252d353d444d52575f61676a717e8b95a0acb9b9ac9f92867b6e615a534e453f332d261d140a00000000000000000000000000000000000000000000000006111c2b37424d5765717e8b98a2aebab5ab9d9083776a605447392e23180c000000000000000000000000000000000714202d3946525e687784919daab7b6a99c9083766674818d9aa7b4b8ab9e9285786a5f53473a2e21140800000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433b3b3a3a38342e2e2d2a251f1b150d08020000000000000000000000000000000000000000000000000000000813202d394653606c7884919ea6b0b9c2c0b8b0aba9aba49fa4ababa69e9c9ea6b0bbbaada194877a6e6154473b2e2114080000000000000000000000000000000000000005080a0b1212121212120f0e0c0804000000000000000000000000000000000000000714202d3a4753606d79868c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c7f7366594c403326190d00000000000000000000000000000000000000060f1b242d34393d3e3f3f3f3f3f3f3f3f3f3f3c3b37322b22190e04000000000000000000000000000000000000000000000002080c151c23282c2f35393a3d3f4142424242413f3d3a3935302c29241e18120b0300000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3e3d39332c241a1019222b32373b3c3f3f3f3f3f3f3f3f3f3f3f3b3a37312a21180e0300000000000000000000060d161e242932383c4247484a50535456575757565553514b4a46443f38352f271f19110a01000000000000000000000000000000020a1117232b30383f4449505356545c606162636261605c555653514a45413a3229241e160d050000000000000000000000000000030c17202a333c454d555c606a6f757b7f838588898a8a89888684807c78716d66605952443f3830261c12080000000000000000000000000008131e28313b454d565e656c71797d818487888989898786837f7b756e69615a51493f362d21181a25313c4855626f7c8896a1acb9aea3998a7e7164554b4035291d10040000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c4c6b9ac9f938679665c5144382c1f12060000000000000713202d3a4653606d79869298989ea1a8b0b8c2b9aea49c9a99999999999285786c5f5245392c1f120600000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b8794a1acaba9a9a19e9792877f726c61564c4131281e130800000000000000000815222f3b4855626e7b7f7f7f7f7f7f7f7f7f7e7164584b3e3125180b0000000000000008111b242d373f474f565e61696e74787c84919ea8b1bdb3a6998d80756f6b625f5751443f382f261c11060000000000000000000000000000000000000000000000000e1a26313c4754606d7a85929facb8b8aca095887c6f62554b4034281c10040000000000000000000000000000000814212e3b4754616e7a8795a0acb8b3a69a8d807367717e8b97aab4b9ada197887b6e6255483b2f22150900000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504848484746443f3f3b3a36302b272019130c04000000000000000000000000000000000000000000000000000006121f2b3844505b66717e8b949ea7b0b9bec2bbb7b5b5afacafaea49d948f949eaab7baada194877a6e6154473b2e2114080000000000000000000000000000000000060c111517181e1e1e1e1e1e1b1b18140f090200000000000000000000000000000000000713202d3a4653606d787f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7064574a3d3124170a000000000000000000000000000000000000000009121b22282d3031323232323232323232322f2e2b27201910070000000000000000000000000000000000000000000000000000030a11171c1f24292c2d303234353636353432302e2d2925201d19130c0701000000000000000000000000000009121b22292e313232323232323232323231302d28221a1208101920272b2e2f32323232323232323232322e2d2b261f180f06000000000000000000000000040c131921272c31373a3b3f444648494a4a4a4a484745403d3a38342e29241d150d08000000000000000000000000000000000000000610191e262e34383f4446494a5153555656565553514b4a46444039352f282019130c0400000000000000000000000000000000050e18212a333b434b51585f62696e7276797b7c7d7d7c7c7a77746f6c66605c544f4740342e261e140a0000000000000000000000000000010c161f29333b444c535b60666d7075787a7b7c7c7c7b7976726e69615e5750483f372e241b0f15212e3b47535f6a7884919eabafb5ab9b8f8275675d5145392c1f13060000000000000000000000000000000000000000000006121f2c3945525f6c7885929fabb8c5c7baaea39886796d6053463a2d2013070000000000000713202d3a4653606d788485888b91969ea6b0bbb5a89c928d8c8c8c8c8c8c85786c5f5245392c1f120600000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b8794a49f9e9c9997918c857d726d625a50443a301f160c0100000000000000000814212e3a47535f696e737373737373737373716c6156493d3024170a000000000000040d1a232d363f49515960696e747b8084889196a1acbac3b8ac9f9286817c766e6a625b504a42382d2217100700000000000000000000000000000000000000000000000915202c3945515d6774818e9ba8b2bcb1a79a8d8074675c5145382c1f14090000000000000000000000000000000b1724313e4a5764717d8a97a8b1bdb3a9978a7e71646f7b8898a2aebab3a9988b7e7265584b3f31261a0e02000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c555555545453504a4b4746423b373229241e160e0700000000000000000000000000000000000000000000000000030f1c28333f4a54626c76828f959fa6adb3b6b7b8b7b6b4aeaaa29f928d828f9ca8b2b2ada194877a6e6154473b2e211408000000000000000000000000000000000910171d2124252b2b2b2b2b2b282725201a130b030000000000000000000000000000000006121f2b3844505c666d72727272727272727272727272727272727272727272727272727272727272706c6155493c3023160a0000000000000000000000000000000000000000000910171d2124252626262626262626262622221f1b150e070000000000000000000000000000000000000000000000000000000000060c1012181d1f202325272829292827262321201d1913110d080100000000000000000000000000000000000911181d2124252626262626262626262423211d17100800070f161b1f2223262626262626262626262622211e1a140e06000000000000000000000000000001080d161b20262b2e2d3338393b3c3d3e3d3d3c3a39352f2d2c28231c18120b03000000000000000000000000000000000000000000070c151c23282d3337393c40444648494949484745403d3a38342e29241e160d0801000000000000000000000000000000000000060f182129313940454e53575e6165666d6e707070706f6d676763605b54514b423d3528231c140c02000000000000000000000000000000040d182129323b414950545c606468676d6f6f706f6e6d6666615e57524d453e362e251c1209121f2b37434e586774808d9aaaa2a2a29f9286796d6053473a2d2014070000000000000000000000000000000000000000000005111e2b3844515e6b7784919eaab7c2c4b8ac9f928579665c5144382c1f120600000000000006121f2b3844505c666d78797b7e848f949ea9b3b3a69a8d807f7f7f7f7f7f7f7265594c3f3226190c0000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b87949a93918f8d89858079706b625b51483e32291e0d0400000000000000000006121e2b37424d575f6266666666666666666664615a5045392d2115080000000000010c161f2c353f48515b626b707b81878d91969ea1a8b2bdc6baaea298928e89827b726d605b544a3f332822190b020000000000000000000000000000000000000000000004111d2935414b55636f7c8996a0acb9b8ab9f9285796d6053463b30251a0e020000000000000000000000000005111d2a36414c566774818d9aa7b4b9ada197887b6e616d7985929facb8b5a89b8e827568574d42372b1e1206000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f837669626262626161605c545854524d47433d35302820191008000000000000000000000000000000000000000000000000000b17222d3842505a616e7a8390949ea1a9a9aaabaaa9aaa29f98928b807d8996a3a6a6a6a194877a6e6154473b2e21140800000000000000000000000000000009121b22292d30313838383838383534312c251d150b0200000000000000000000000000000003101c28343f4a545c60656565656565656565656565656565656565656565656565656565656565656461594f44392d20140800000000000000000000000000000000000000000000060c11151718191919191919191919191615130f0a04000000000000000000000000000000000000000000000000000000000000000003070c10131417191a1b1c1c1c1a19171413110d0804010000000000000000000000000000000000000000060c11151718191919191919191919171714110c05000000040a0f13151619191919191919191919191514120e09030000000000000000000000000000000000040a0f151a1e2122282b2d2e30303131302f2d2c2924201f1c17110c07010000000000000000000000000000000000000000000000030a11171b22272b2d2e34383a3b3c3d3c3b3a38342f2d2c28231c19130c04000000000000000000000000000000000000000000060f171f272f343c43474d5254545c60616364646362605d555653504a454039302b2317110a020000000000000000000000000000000000060f1820292f383f444a515357555d606263636261605c5454534d46423b332c241c130a030f1b26323d4a5663707d89989595959595988a7d7064574a3d3124170a00000000000000000000000000000000000000000000020f1c2935424f5c6875828f9ba6b0b8b8b2a89d9083776a544a4034281c100400000000000003101c28343f4a545c606b696e7279828f97a2adaea194877b737373737373726d62574a3e3125180b0000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000815212e3b4854616e7b878887868583807d79736d67615951493f362c20170c00000000000000000000020e1a26313c454d5355555d60646565625f58585650483e34281d1101000000000007131d28313d47505a626d727d858e92999ea1a8acb2bac4cabfb4aaa29f9b948f867f746c665b50443f342b1d140a00000000000000000000000000000000000000000000010d18242f3a4854606b7784919eabb5baada2978a7e7164574d42362a1e1205000000000000000000000000000713202d3946525e687784919daab7b8ab9e928578695f667683909ca9b6b8ab9e918578695f53473a2e211408000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f83766e6e6e6e6e6e6d6d666865615e57544e45413a322b221a110800000000000000000000000000000000000000000000000006111c262f3f46525e686e7a828b91979a9c9d9e9e9d9a98928e867e737d8996999999999994877a6e6154473b2e211408000000000000000000000002060808101b242d34393d3e45454545454542403d372f271d1308070604000000000000000000000000000b17232e38424a50535959595959595959595959595959595959595959595959595959595959595957554f473e33281c100400000000000000000000000000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c09080603000000000000000000000000000000000000000000000000000000000000000000000000000406070a0c0e0f0f0f0f0e0c0a070705010000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0b0a080500000000000000030608090c0c0c0c0c0c0c0c0c0c0c0807050200000000000000000000000000000000000000000003090e1214171c1f202123242424232220201d181312100c0600000000000000000000000000000000000000000000000000000000060c11171b1f2023282c2d2e2f302f2e2d2c2923201f1c18120d08010000000000000000000000000000000000000000000000050d151d232931373b4246474a505355565757565553514b4946443f38342e271e1911060000000000000000000000000000000000000000060e171d262d33394044464a4c5154555656565453504a4846423b363029211a120a01000a13202d3a4653606d798689898989898989898175685b4e4235281b0f02000000000000000000000000000000000000000000000a1724313d4a5764707d8a949ea6ababa8a0968c7f7266594c3f2e23180c00000000000000000b17232e38424a5053575f61676d7a85929eabaea194877b6e666666666665625b51463a2e2216090000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000713202d3a4653606d787c7b7b79787673706d66605d554f473f372d241a0e0500000000000000000000000b17222d384149535b60676d7072716f6a625f584e463d31281d130700000000010d18242f3a434f59626c727f8792979fa3abadb2b9bdc4ccd0c6bcb4aeaca69f98928b80786c605b51463c2f261b11060000000000000000000000000000000000000000000007131d2c38444f5966737f8c99a4afbbb3a99c8f8276695e52463a2d20160a000000000000000000000000000714212e3a4754616d7a8795a0acb8b5a99c8f827669576774808d9aa7b3b9ada197887b6e6255483b2f221509000000000000121e2b3845515e6b7884919eabb7c3b6a99d90837c7b7b7b7b7b7b7a797775726e69626058524c443d342b231a10070000000000000000000000000000000000000000000000000a141d2a36414c565e686d787e85898d8f919291908d8a86817b72707d898c8c8c8c8c8c8c877a6e6154473b2e21140800000000000000000003090e12141517222d363e45494b5151515151514e4d4841392f251a151313100c07000000000000000000000006111c2630383f44464c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a49443e352c21170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000206060b0f1213151617171717151413110d0706030000000000000000000000000000000000000000000000000000000000000000060b0f1213181c1f202223232322201f1c181312100c07000000000000000000000000000000000000000000000000000000030b121820262b30363a3b3f444648494a4a49494745403c3938332d28231d150c0700000000000000000000000000000000000000000000050b141b22272e34383a3d414547484949494846443f3b3a36312a251f170f0800000006121f2c3844515c666f7c7c7c7c7c7c7c7c7c7c6f6255483c2f22150900000000000000000000000000000000000000000000000613202d394653606c77828f949c9e9f9d969184796d6053473a2d201407000000000000000006111c2630383f44464d53555d6873808d99acb6a194877b6e6159595959595751493f35291e12060000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000006131f2c3845515c666d6f6e6e6d66696663605c54514b433e352d251b11080000000000000000000000030f1b27333f49535b656c727a7d7f7e7c766f6a60584e433a2f24180d0100000004111d2935414b55606b717e8b9399a1a9afb5b9bdc3bfbcbcbcbec3bfbab8b0aaa39f928d80746d63584e41382d22170b00000000000000000000000000000000000000000000010f1b27323d4754616e7b87939facb9b9ac9f93877b6e6154483d32271b0f010000000000000000000000000b1724313e4a5764717d8a97a7b1bcb3a6998c8073665964717e8b97aab4beb3a9988b7e7265584b3f31261a0e020000000000121e2b3845515e6b7884919eabb7c4b8ab9f959088888888888887878684827e7b756f6a605d564e463d352b22190d040000000000000000000000000000000000000000000000020b1925303b444c565d666c71797d808384858483817e7a746e696e7b7f7f7f7f7f7f7f7f7f796d6053473a2d2014070000000000000000060e151a1e21222129343e485056585e5e5e5e5e5e5b59534b41372c2122201f1c18120b03000000000000000000000a141e262e34383a3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3d3c39332c231a1005000000000000000000000000000000000000000003070909131313131313131313130f0e0c0904000000000004080c0e0f131313131313131313130b0a080400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003060608090a0b0a0a0907060401000000000000000000000000000000000000000000000000000000000000000000000000000305070c10121315161616151413100c07060400000000000000000000000000000000000000000000000000000000000001070c151a1f252a2d2e34383a3b3d3d3d3d3c3a39352f2d2b28221c18120b03000000000000000000000000000000000000000000000000020a11171c23282c2d2f35393a3c3c3d3c3b3a38342e2d2a251f1a140d050000000004101c2834404a545f6a6f6f6f6f6f6f6f6f6f6f6a5f53473b2e211508000000000000000000000000000000000000000000000005121f2b3744505b656d7a828b909292908c847c6e675d5145392c2013060000000000000000000a141e262e34383b42464c56636f7c899aa4afa194877b6e61544c4c4c4c4a463f372d23180d010000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d000000000000000000000000000000000004101c2834404b545c60626261605c545a5653504a45413a312c231b130900000000000000000000000005121f2b3744505b656c777f868a8c8b88837c6f6a60554b4035291d11040000000613202c3945515d67707d87929fa4abb3bbc0bcb7b6b2b0afafb2b6b7bcc2bcb4aea49d928c7f726a6053493f33271b0f03000000000000000000000000000000000000000000000b16202d3a46525e6976828f9ca9b3bbafa4998c7f7266594f43382c1d1307000000000000000000000005111d2935414c566774808d9aa7b3bdb2a8968a7d706357626f7b8898a2aebab4a89b8e817568574d42372b1e12060000000000121e2b3845515e6b7884919eabb7c4bcb1a79f9d959595959595949992918e8b86827c746d6860584f473d342b1f160c01000000000000000000000000000000000000000000000008141e29323b444c545b60676d7074767778777674716d68615e696e7373737373737373736d675d5145392c20130600000000000000090f1820262b2e2f2e2d3945505a62646b6b6b6b6b6b68655d53483d312d2e2d2c28231d150c03000000000000000000020c141c23282b2d3232323232323232323232323232323232323232323232323232323232323231302d28211a110800000000000000000000000000000000000000040a0f131516202020202020202020201c1b18150f09020002090f14181b1b20202020202020202020171714110c05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004060708090a0908070604000000000000000000000000000000000000000000000000000000000000000000000000030a0f141a1e2023282b2d2e303131302f2d2c2924201f1c17110c0700000000000000000000000000000000000000000000000000000000060b12181c1f2024292c2d2f30302f2e2d2b2823211e1a140e09020000000000000c18232e39424e585f626262626262626262625f584e43372b1f12060000000000000000000000000000000000000000000000030f1b27333f49535d686d787e83858584807a6e6a5f554b4035291d1104000000000000000000020c141c23282b31363a4753606d7a86939faca194877b6e61544840403f3e3a352d251b1107000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d0000000000000000000000000000000000000c18232e39424b515355555453514b4d4a46443f38352f281f1a110901000000000000000000000003101c28343f4a54606c77818c929898989590867c6f675d5145392c201306000005121e2a36424d57606d79849199a3afb5bdbfbab0aba9a5a3a2a3a5a9abb0b9bebfbaaea59f92877c6f655b5044372b1f1409000000000000000000000000000000000000010407070d111e2a36424d5764717e8a97a2adb9b5ab9e9184776b6054483a2f24180d01000000000000000000000713202d3946525e687784909daab7b9ada196877a6e6154606c7985929facb8b8ab9e918478695f53473a2d2114080000000000121e2b3845515e6b7884919eabb7c4c2b9b1aba9a1a1a1a1a1a1aba39f9d9b99928f87817a6f6a60594f463c31281e13080000000000000000000000000000000000000000000000020d172029323a424a50555c606367696a6b6b6a6764605d56575e61666666666666666666605d554b4035291d100400000000000009121a212a31373a3b3a373d4956626c71787878787878756f65594d40363a3b3a38342e271e150b00000000000000000000020a11171c1f20262626262626262626262626262626262626262626262626262626262626262423201c17100800000000000000000000000000000000000000070f161b1f22232d2d2d2d2d2d2d2d2d2d282725201b140c030b131a202527282d2d2d2d2d2d2d2d2d2d2423211c171008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002090e1114171c1f20222324242322201f1d1813120f0b060000000000000000000000000000000000000000000000000000000000000000070c101213191d20212223232321201f1c1714120e0903000000000000000007121c27303c464e5355565656565656565655534e463c32261b0f030000000000000000000000000000000000000000000000000b17222d38414c565d666d7176787877736d685f584e433a2f24180d0100000000000000000000020a11171c1f262c3945515d677885919ea5a194877b6e6154483b3332312e29231b130a00000000000d1a2633404d596673808c99a6b3bfb2a6998c7f7366594c403326190d00000000000000000000000000000000000007121d273039404546494848464540403d3a38342e29241d160d080000000000000000000000000006121f2b3844505c66727f8b939fa2aaa79f989184796d6053473a2d20140700000714212d3a46535e6974808d96a1abb5c0bcb4aea69f9c98969596989c9fa6adb3bbc0bbafa3999083786c6053463b31251a0e0200000000000000000000000000000001080d1113141a1a1a25303b4653606d7985929eabb8b9aca096897c6f63554b4035291d1104000000000000000000000714212e3a4754616d7a86939facb9b7ab9e918478685e525b667683909ca9b6b9ada196887b6e6155483b2e2215090000000000121e2b3845515e6b7884919eabb7c4cbc2bcb8b6aeaeaeaeaeaeb5aeacaaaba39f9a938e847c706b60584e433a2f24190d040000000000000000000000000000000000000000000000050e1720282f383f444b5153565a5c5e5f5e5d5a5754524c4d535459595959595959595953514b43392f24180d010000000000040e1a242c333c42474847423e4b5864717e8484848484848175685b4e424246484645403930271d12070000000000000000000000060b10121319191919191919191919191919191919191919191919191919191919191919171614100b050000000000000000000000000000000000000007101921272c2e2f393939393939393939393534312c251e150c151d252c3134353939393939393939393931302d28221a12080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000205060b1012131516171716161413100c0706030000000000000000000000000000000000000000000000000000000000000000000000000406080d11131415161616151312100b06050200000000000000000000000b151e2a343c43474849494949494949494847433c342a20150a0000000000000000000000000000000000000000000000000006111b262f3a444c545c6065696b6c6a66605d564e463c31281d130700000000000000000000000000060b10141d2935404b556a77849098989894877b6e6154483b2e2625221e18110a0100000000000d1a2633404d596673808c99a6b2b2b2a6998c7f7366594c403326190d000000000000000000000000000000000000000b151e272e34383a3c3b3b3a38342e302d2b28231c18130c0400000000000000000000000000000713202d3a4653606d7985919ea5aeb4b1aaa1968c7f7265594c3f3226190c0003101c28343f4a54616e7b87929fa8b2bdbfb4aaa29f94908c8989898b90949ea2a9b3bcc0b5aba0958a7e7164574d42362a1e12050000000000000000000000000000040c13191d2021262626262c3845515c6674808d9aa7b1bcb2a89b8e8174675d5145392c201409000000000000000000000a1724313d4a5764707d8a9aa4afbbb5a89b8e827568564c546774808d9aa7b3bdb2a9988b7e7165584b3e31261a0e0200000000121e2b3845515e6b7884919eabb7c4d1cdc8c4c3bbbbbbbbbbbbbfbbb9b7b5afaca49f9691867d706a60554c41352920150a000000000000000000000000000000000000000000000000050e161d262d33394045464a4d50515251504e4b4745414246484c4c4c4c4c4c4c4c4c4745403931281d12070000000000020c16202c363e454e5355534e464b5865717e8b919191918f8275695c4f454d535553514b43392e23180c030000000000000000000000000306070c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0a0a08040000000000000000000000000000000000000000040f19222b32383b3c4646464646464646464642413d3730271e141d272f373d4042464646464646464646463e3c39332c241a1005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030607080a0a0a0a09070604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104060709090a0908070603000000000000000000000000000000030c18222a31373a3c3c3c3c3c3c3c3c3c3c3b37322a22180e0400000000000000000000000000000000000000000000000000000a141d28323a424a5053585d5f5f5d5954524c443c332a1f160c01000000000000000000000000000000030c18242f43505d6a76838b8b8b8b8b877b6e6154483b2e211516120d07000000000000000d1a2633404d596673808c99a6a6a6a6a6998c7f7366594c403326190d00000000000000000000000000000000000000030c151d23282c2d2f2f2e2d2c282323201f1c17110d07010000000000000000000000000000000916222f3c4955626f7c8897a1adbabfbcb2a99c8f8276695c4f4336291c100006121f2b3844505c6673808c99a3afbac4baaea298928a837f7d7c7c7f838a9297a2aab4bfbdb1a79c908376695e53463a2d21140700000000000000000000000000040d161e24292c2d333333333334404b54626f7c8895a0acb8b8ac9f92857a6d6053473b31261a0e00000000000000000005111d2935414c566774808d9aacb6c0b6ac998c7f7266594c5864717e8b97aab4bfb4a89b8e817568574d42362a1e120500000000121e2b3845515e6b7884919eabb7c4cfc7c0bbb9b8b8b8b8b8b9bbc0c1c4c0bbb6afa8a19892867c6f675d51453c31261b0f02000000000000000000000000000000000000000000000000040b141c22282e34383a3d414344454443413e3a3935363a3b4040404040404040403a39352f281f160c01000000000008131e28323e4850575f625f57524c5864717e8b979e9e9b8e8175685b4b51575f61605c554b4034281e150a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a16212b343d434849535353535353535353534f4d48413930251b252f3941484d4e535353535353535353534a49453e362c22170c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006101820262b2e2f2f2f2f2f2f2f2f2f2f2e2b2620181006000000000000000000000000000000000000000000000000000000020b16202830383f44464b505252514d4745413a322a21180d040000000000000000000000000000000000071724303d4a5763707d7e7e7e7e7e7e796d6053473a2d201407060100000000000000000d1a2633404d596673808c999999999999998c7f7366594c403326190d0000000000000000000000000000000000000000030b12181c1f20222221201f1c18171312100b060000000000000000000000000000000000000a1724303d4a5763707d8a96a9b3becac3b7aa9d9084776a5d5144372a1e11000713202d3a4653606d7984919eabb5c0baafa59f92867e7672706f7072767d859298a2aebac3b9ac9f93877b6e6154483b2e211507000000000000000000000000010c1620282f35393a4040404040404047535f6a7783909daab4baaea2988b7e7164574d42362a1c110600000000000000000713202d3946525d687783909daab7bbafa49a897c7063564955626e7b8898a2aebab7ab9e918478695f53463a2d21140700000000121e2b3845515e6b7884919eabb7c4c7bdb5afacabababababacafb5b5b9bbc0c0bbb2aaa29891847a6d60584e43372b1e130800000000000000000000000000000000000000000000000000020a11171d23282c2d3034363738383734312d2c292a2d2e3333333333333333332d2c29241d160d040000000000030c1924303a44505a616a6e6a615e565764717e8a97a4a79a8e8174675b555d60696e6d675c51453c30261c1106000000000000000000000000000000000000000000030608090a0a0a0a0a0a0a0a0707050100000000000000000000000000000000000000000000000000000000000000030f1b27323d464e5456606060606060606060605b59534b41372c202c37414b53595b60606060606060606060575550483e33281c11040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e151a1f2122232323232323232322211f1b150e060000000000000000000000000000000000000000000000000000000000040d161e262e34383a3e43454544403a39352f2820180f060000000000000000000000000000000000000a16232f3c4855616b707272727272726d675d5145392c201306000000000000000000000d1a2633404d596673808c8c8c8c8c8c8c8c8c7f7366594c403326190d00000000000000000000000000000000000000000000070c1013131615151313100c0707060300000000000000000000000000000000000000000916232f3c4956626f7c8997a2adbac1bdb3a99c8f8376695c504336291d10000916222f3c4955626f7c8896a1adbdc7b6aa9e93897d716c65636263656b707c86929fa9b3bebbafa49a8b7e7165584b3e2e23180c00000000000000000000000008131e28323a4145474d4d4d4d4d4d4d4d4e5865727f8b98a3aebab4aa9c908376695f5346382d22170b00000000000000000714212e3a4754616d7a86939facb9b9ac9f93867a6d60544753606c7985929facb8b9ada196887b6e6155483b2e22150900000000121e2b3845515e6b7884919eabb7c4c0b5aba39f9e9e9e9e9e9fa3aba8acafb5bdc3bcb4aaa1968e81746a5f53473a3024190d010000000000000000000000000000000000000000000000000000060b12181c1f202327292b2c2b2a272421201d1e212126262626262626262620201d18120c040000000000000a151e2935414c56616c717b746d68605b64707d8a97a3a79a8d8074675a61676d737b796d60584e42382e23170c03000000000000000000000000000000000000040a0f13151616161616161616161413110d0802000000000000000000000000000000000000000000000000000000000007131f2c38434e5860626c6c6c6c6c6c6c6c6c6c68655d53483d311d313d48535d65686c6c6c6c6c6c6c6c6c6c64615a5045392d211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a0f12151516161616161616161515120f0a0400000000000000000000000000000000000000000000000000000000000000040c141c23282b2d3236383937332d2c29241e160d06000000000000000000000000000000000000000714202c38444f596163656565656565605d554b4035291d100400000000000000000000091623303c4956636f7d7f7f7f7f7f7f7f7f7f7d6f6356493c30231609000000000000000000000000000000000000000000000000040607090808070604000000000000000000000000000000000000000000000000000713202d3a4653606d7985929fa6afb5b3aba2978c7f7366594c403326190d000c1925323f4c5865727f8b98a8b2bdbeb3a99b8e81756b615a56565659616a727f8b97a2adbac0b6ac9b8e817568554b4034281c100400000000000000000000010d19242f3a444c525459595959595959595959616d7a86929facb9b7ab9f94887b6e61544a3f33281c0f03000000000000000a1724313d4a5764707d8a9aa4afbbb7aa9d918477675d5145505b667683909ca9b6bdb2a8988b7e7165584b3e31261a0e02000000121e2b3845515e6b7884919eabb7c4bbafa3999292929292929299979b9fa4abb1b9c3bcb2a89f93877c6f62564c4135291d110500000000000000000000000000000000000000000000000000000000070c101313171a1d1e1f1e1d1b181413111214151919191919191919191413100d070100000000000006111c26303845525d68717e86817a726c6663707d8a96a3a6998c807366626c7179808680736a5f544a3f34282015090000000000000000000000000000000000070e151b1f2222232323232323232321201d19130c04000000000000000000000000000000000000000000000000000000000915222e3b4854606a6f79797979797979797979756f65594d392e2334404d59656f7579797979797979797979716c6155493c3023170a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306080909090909090909090908060300000000000000000000000000000000000000000000000000000000000000000000020a11171c1f20252a2c2c2a2621201d19130c04000000000000000000000000000000000000000004101c28333e474f555758585858585853514b43392f24180d01000000000000000000000915222f3b4854606b6f7373737373737373736f6b6054483b2f2215090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c6673808c949ea5a8a9a19992857a6d6154473a2e211407000f1b2835424e5b6875818e9ba8b4c1baada297897c6f6359504a49494f58606d7985929fabb8c4b7aa9e918477675c5145382c1f13060000000000000000000004111d2935414c565d6066666666666666666666666875828e9babb5bbb0a6998c8073665b5044382b1f130800000000000004111d2935414c566774808d9aacb6c0b4a79b8e817468554c414a546773808d9aa6b3c0b4a79b8e817468574d42362a1e1205000000121e2b3845515e6b7884919eabb7c4b9ac9f9287858585858586878a8e9399a0a7b1b9c3bbafa4998e8175685d5246392d2013070000000000000000000000000000000000000000000000000000000000000406070a0e10111211100e0b0706040507080d0d0d0d0d0d0d0d0d0706040100000000000000000c17232e38424f59606d7a85928e857e786f6b707c8996a3a5998c7f726a6e767e848c92877c6f665c50443c31261a0e0200000000000000000000000000000007101920272b2e2f30303030303030302e2d29251e160e040000000000000000000000000000000000000000000000000000000916232f3c4956626f7c86868686868686868686817568554b40342834404a54687581868686868686868686867e7164574a3e31241708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b101213181d1f1f1e1a1413110d0801000000000000000000000000000000000000000000000b17212c353e44484a4b4b4b4b4b4b4745403931281d120700000000000000000000000713202c38444f5960636666666666666666666360594f43382c1f13070000000000000000010406070606030000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b54606d78828e93999b9a9792877e70685e5246392d20130700101d2a3743505d6a7683909da9b6c3b8ab9f9285786b6054473e3c3e45515d6775828f9ba8b5c2b9ac9f9386796d6053463a2d201307000000000000000000000713202c3945525d686d737373737373737373737373737d8999a4afbbb7ab9e9184786c6053463a3024190d0100000000000713202c3945525d687783909daab6bfb5ab988b7f7265584c3f4b5764717e8a97aab3beb7ab9e918478695f53463a2d211407000000121e2b3845515e6b7884919eabb7c2b6a99c8f827878787878797a7d82879095a0a7b1bdc0b5ab9f92867a6d6154473a2e211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a54606b74818e9797928b837c746f7c8996a2a5988b7e72737c828a9196999083786d60574d42372b1e12060000000000000000000000000000040e19222b32373b3c3d3d3d3d3d3d3d3d3a3935302820160c0200000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b9393939393939393918477675c5145382c3844515c6677849093939393939393938d8073665a4d403025190e02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306070b101212110d0707040100000000000000000000000000000000000000000000000005101a232c33383c3d3f3f3f3f3f3f3a39352f281f160c010000000000000000000000030f1b27323d474f5456565e61646565615f5756544f473d32271b0f0300000000000001070d11131413120f0b060000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3944515c666d7981898d8e8e8b857d706c61564c41362a1d110500111e2b3744515e6a7784919daab7c3b6a99c90837669594f43352f35404b5566727f8c99a5b2bfbbafa49a887b6e6155483b2e221508000000000000000000000714212d3a4754606d7a808080808080808080808080808087939facb9b9ada196897d7063564c4135291d110400000000000714212d3a4754606d7a86939facb9bbaea399897c6f6256493c4855626e7b8898a2aebab9ada196887b6e6155483b2e221509000000121e2b3845515e6b7884919eabb7c2b6a99c8f83766b6b6b6b686e70757c839095a0abb5c0baaea3998b7e7164584b3e2f23180c00000000000000050a0e10111212121212121212120e0d0b080300000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844505c666f7c88939fa29e959087817a7c8995a2a4978b7e7a80878f949ea1a0958c7f72695f53473a2e21140800000000000000000000000000000a15202b343c43474949494949494949494746413a32281e13080000000000000000000000000000000000000000000000000004101c2834404a546774818e9a9f9f9f9f9f9f9f9286796d6053463a2d3a4653606d7986929f9f9f9f9f9f9f9c8f827569564c41362a1e110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a21282c2f303232323232322d2c29241d160d04000000000000000000000000000c18242f39434b555d60686e7172716e69615e564d453b30251a0e050000000000040c13181d2020201f1c17110d070100000000000000000000000000000000000000000000000000000000000000000000000000000007121d2834404a545d676d757c8082817e7a706b61594f443a3025190d0100121f2b3845525e6b7885919eabb8c1b4a89b8e8175685b4e4232242f3e4b5864717e8b97a4b1bec0b6ac95887c6f6255493c2f221609000000000000000000000815212e3b4854616e7b878c8c8c8c8c8c8c8c8c8c8c8c8d9399a4afbbbdb2a89b8e8175685d5245392c20150a00000000000a1724313d4a5764707d8a99a4afbbb9ac9f9286796d6053463a4653606c7985929fabb8bdb2a8978b7e7164584b3e31251a0e020000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695f5f565e61646a6f79839099a4afbbbfb4ab9b8e817468554b4034291c100400000000030b11161a1c1d1f1f1f1f1f1f1f1f1f1b1a18140f0801000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7883909aa3aba7a09a938e85818d9aa7a89b8e81858d92999fa6aba69f92867b6e6255483b2f22150800000000000000000000000000030f1b27323c464e5455565656565656565654524c443a3025190d0100000000000000000000000000000000000000000000000006121f2c3844515c667783909daaacacacacafa399887c6f6255483c2f3c4855626f7b8899a3aeacacacacab9e918578685e5246392d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810171c20232425252525252520201d18120c040000000000000000000000000004101d2935404b555d676d747a7e7f7e7b756e685e574d42362a21160b00000000040d161d24292c2d2d2b28221c18130e090300000000000000000000000000000000000000000000000000000000000000000000000000000c18232e39424b555d606a6f737574716d6761594f473e32291e13080000131f2c3946525f6c7985929facb8c1b4a79a8e8174675b4e413428313d4a5764707d8a97a3b0bdbcafa296897c6f6356493c30231609000000000000000000000815212e3b4854616e7b87949999999999999999999999999fa4abb5c0c4b8ac9f92867a6d6054473c31261b0f0000000004111d2935414c566773808d9aabb5c0b6aa9d908377675c51453844505b6576838f9ca9b6c1b4a79b8e817468574d42362a1e12050000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c524c5254585f676e7b87939facb9c3b7aa9d908477675c5145382c1f1306000000050d151c2226292a2b2b2b2b2b2b2b2b2b272724201a130b020000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707d868e92999fa4aca49f98928d929da9aa9e938e91979fa3aba79f9d9490898073665a4d4033271a0d0000000000000000000000000006131f2b37434e5860626363636363636363615e564c4135291d11050000000000000000000000000000000000000000000000000713202d3a4653606d7986929facb9b9b9c0b5ab978a7e7164574b3e313e4b5764717e8a97abb4bfb9b9b9ada197877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b101416171818181818181413100d0701000000000000000000000000000006131f2c3845515d676d7980868a8c8b88827a6e695e52463d33271c10040000010c161f282f35393a3938332d29241d1a14100b0400000000000000000000000000000000000000000000000000000000000000000000000007121c273039434b5158606266686765605d554f473e352c20170c020000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000815212e3b4854616e7b8794a1a6a6a6a6a6a6a6a6a6a6a6acafb5bdc7c7baaea3988b7e7265584e43372b1c12070000000613202c3945525d687783909daab6c0b4a79a8d817467554b40343f49536773808d9aa6b3c0b7ab9e918478695e53463a2d2114070000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504146474e555f6a75828e9ba8b5c1b9ac9f9286796d6053473a2d2014070000030d171f272d3236373838383838383838383433302b251d140b0100000000000000000000000000000000000000000000000000000000000000000000000000000916222f3b4854606b707b81878e939a9ea6aaa29f9a9da4aeafa59e9b9ea1a9a7a09d959089837d736e63574b3f3226190c000000000000000000000000000815222e3b4754606a6f70707070707070706d685e5246392d2013070000000000000000000000000000000000000000000000000916222f3c4955626f7c8899a3aebac7d1c0b3a6998d8073665a4d402f404d596673808c99a6b3bfd1c9beb3a9968a7d7063574a3d302417080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004070a0a0c0c0c0c0c0c0706040100000000000000000000000000000005111e2a36424d57606d79828d92999898938f847b6e61594f44382c201307000007131d28313a40454746443f38352f2a261f1c16100c0701000000000000000000000000000000000000000000000000000000000000000000000b151e28313940454e54565a5b5b5854514c433e352c231a0e05000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000815212e3b4854616e7b8794a1aeb3b3b3b3b3b3b3b3b3b3b9bbc0bfbfbfbfb4aa9d9083776a5f5347392e23180c0000000714212d3a4754606d7a86929facb9bfb4aa978b7e7164584b3e2e3e4b5764717e8a97a9b3beb9aca196877b6e6154483b2e2115090000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043393c434e5764717e8b97a4b1bebbafa399887c6f6255493c2f22160900000b151f2931383e424445454545454545454541403c362f261d130800000000000000000000000000000000000000000000000000000000000000000000000000000713202c38444f5960696e747b81878f949c9fa6aba7a9aeb6b7afaaa8aba8a09e95908a837d766f6b635c52473b2f23170a000000000000000000000000000916222f3c4955626f7c7c7c7c7c7c7c7c7d7a6d6154473a2e2114070000000000000000000000000000000000000000000000000b1825313e4b5864717e8b97abb4bfcbcfc2b5a89c8f827569554c4135404b556875828f9ba8b5c2cecfbfb2a5998c7f7266594c3f2f24190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a46525e6974818d959fa3aba59e969082766b6054483c2f22160900010d18242f3a434b515353504a45413a36312c271f1d18120e09020000000000000000000000000000000000000000000000000000000000000000030c161f282f353d4347494d4f4e4b4745413a312c231a110800000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000815212e3b4854616e7b8794a1aeb2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2ab9f95887c6f62544a4034281c100400000a1724303d4a5763707d8a99a3afb2b2aea298887b6f6255483c2f3b4855626e7b8897a2adb2b2b2a8978b7e7164584b3e30251a0e0200121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336313c4855616e7b8894aab4bfc0b5ab96897d7063564a3d3023170a0005111c27313b434a4f505252525252525252524e4c4841382f251a0f030000000000000000000000000000000000000000000000000000000000000000000000000003101b27323d474f575e61696e757c828990949fa9b3b5bac0c1bab6b5aba096918a837d77706b636059524a40352a1f130700000000000000000000000004111d2a3744505d6a778389898989898989897d7063574a3d3024170a0000000000000000000000000000000000000000000000030f1c28333f4a546774808d9aa7b3c0d1d1c4b7ab9e918478675d51453945515d677784919eaab7c4d1cec1b5a89b8e827568554c4135291d110400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010406070b0e0e0c08080602000000000000000000000000000000000000000000000814212e3b4754616e7b86929fa7afb5afa89f94897d706356493d3023160a0004111d2935404b555d60605b54514b46423b38332c29241d1a140f0a0400000000000000000000000000000000000000000000000000000000000000040d161d242932373b3c4042413e3a39352f281f1a11080000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000815212e3b4854616e7b8794a1a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a79a8d8073665c5144382c1f12060004111d2935414b556773808d9aaba6a6a6a69f9285796c605346392d394653606c7985929fa6a6a6a6a69b8e817468574d42362a1e120500121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4753606d7a8698a3aebabdb0a4978a7e7164574a3e3124170b000a16222d38434d555b5d5e5e5e5e5e5e5e5e5e5a58534a41362b20140800000000000000000000000000000000000000000000000000000000000000000000000000000b16212b353d454d52575f626a6f757d829097a1adb9c6cbcbc7bbafa39991847e78706c636059544f4740382e24190e0200000000000000000000000104111d2a3744505d6a7783909696969696968a7d7063574a3d3024170a010000000000000000000000000000000000000000000006121f2b3844505b667683909ca9b6c3cfd2c5b9aca196877a6d6054473a4753606d7a86939facb9c6d2d1c4b7aa9e918477675d5145392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d101314181a1b191514120f090300000000000000000000000000000000000000000b1825313e4b5864717e8b99a3afbbc0bab0a6998d8073665a4d4033271a0d000613202c3945515d676d6c66605d55534d48443d38352f2a251f1b16100c07000000000000000000000000000000000000000000000000000000000000040c121820272b2e2f333534322d2c29241e160d08000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000815212e3b4854616e7b879499999999999999999999999999999999999999999999999285796d6053463a2d201307000613202c3945515d6776839099999999999999908376665b5044382b3744505b6576838f99999999999999918477695e52463a2d20140700121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3845515c677985929facb8beb1a4988b7e7165584b3e3225180b000e1a26323e4a555f666a6b6b6b6b6b6b6b6b6b67645c53483c3024180b000000000000000000000000000000000000000000000000000000000000000000000000000009141f2a333c42464e545960636b70767d85929eabb8c5d0d1c5b9ac9f92867f79716d66605c54504a423e352c21160b0000000000000000030608090d0d111d2a3744505d6a7783909da3a3a3a3968a7d7063574a3d3024170d0d0d0c0a060200000000000000000000000000000000000613202d394653606c7985929facb8c5d2d5c9bdb2a896897c6f6356493c4956626f7c899aa4afbbc8d4d2c6b9ac9f93867a6d6054473a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c12181d20202427272622211f1a150c07010000000000000000000000000000000000000c1926333f4c5966727f8c99abb5c0cbc1b4a79b8e8174685b4e4135281b0e000714202d3a4753606d7979726d67615f57544f4745403936302c271f1c18120d08020000000000000000000000000000000000000000000000000000000001070d151b1f22232728282521201d19130c0400000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000815212e3b4854616e7b878c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8a7d7064574a3d3124170a000714212d3a4754606d7a868c8c8c8c8c8c8c8c8c807367544a3f3328333f49536773808c8c8c8c8c8c8c8c8c877b6e6154483b2e21150800121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362934404b556c7885929fabb8beb2a5988b7f7265584c3f3225190c00101c2936424f5b667177787878787878787878746e64584c4033271a0d01000000000000000000000000000000000000000000000000000000000000000000000000020e1a26313c454d535860626b6f767d838a9297a1adb9bec5c6bfbaafa399928b847e78716d66605b544f473e33281c10040000000000030a0f1215151a1a1a1d2a3744505d6a7783909daaafafa3968a7d7063574a3d30241a1a1a191916120d07000000000000000000000000000000000815222f3b4855626e7b8898a2aebac6d3dacebeb1a4988b7e7165584b3e4b5865717e8b98acb6c0ccd8d4c8bbafa49a897c6f6356493c30231607000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080d161d24292c2d313434332f2e2b262018120b0300000000000000000000000000000000000b1825323e4b5865717e8b98a5afbac1bcb1a79a8d8073675a4d4034271a0d000a1724313d4a5764707d847f7a746e6963605953514b46423b38322c28231c19130f0a0300000000000000000000000000000000000000000000000000000000040a0f1315161a1c1b181413110d08010000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000714212d3a4754606d7a7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7d7063574a3d3024170a000814212e3b4754616e7b7f7f7f7f7f7f7f7f7f7f7c6f6255493c2d222d3c4955626f7c7f7f7f7f7f7f7f7f7f7f7b6e6155483b2e22150800121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504336232f45525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00111d2a3744505d6a77838585858585858585858074675a4e4134271b0e0100000000000000000000000000000000000000000000000000000000000000000000000005121e2b37424d575f616a6f767c828990959ea1a9abaeb3bcbcb4aeacaba39f96918b847e78716c6661594f44382c20140700000000060e151a1f2122272727272a3744505d6a7783909daab6b0a3968a7d7063574a3d30272727272625231e19120a0100000000000000000000000000000b1824313e4b5764717e8a97aab4bfcad6dacdc0b3a79a8d8074675a4d414d5a6773808d9aa6b3c0d2ddd8ccc0b6ac988b7f7265584c3f2e23180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a1f282f35393a3e41413f3b3a373129241d150d03000000000000000000000000000000000815222e3b4855616e7b88939ea8b0b5b2aaa0958a7d7064574a3d3124170a000a1724313d4a5764707d8a8b85807b75706b65605d55524d48433d38342e2a251e1b150f0b0600000000000000000000000000000000000000000000000000000000030608090d0f0e0b0706040100000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000613202c3945525d686d737373737373737373737373737373737373737373737373737373706b6155483c2f231609000714202d3a46525e696e737373737373737373736f6a5f53473b2e212e3b47535f6a6f737373737373737373736e695f53473a2d21140800121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b788491919191919191918e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535f696e757c82898f949d9fa7aaa29fa2aab3b4aaa39fa3aaa8a19e96918b847e78706b6155483c2f23160900000006101820262b2e2f34343434343744505d6a7783909daab6b0a3968a7d7063574a3d343434343433322f2a231c130a00000000000000000000000000010d1a2734404d5a6773808d9aa6b3c0d0dbdccfc2b6a99c8f837669564c414c566976828f9ca9b5c2cfdcddd2c1b4a79b8e817468554b4034281c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008121a232c31394045474b4d4e4c4847433c352f271f150c030000000000000000000000000000000714212d3a46535f6975818e969fa6a8a8a0989083786d6053463a2d201307000a1724313d4a5764707d8a98928d87827d77716d67615e57544e4644403936302b261f1c17110d08010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000004111d2935414c565d606666666666666666666666666666666666666666666666666666666361594f44382c2014070005111e2a36424d575e6166666666666666666666625f584e43372b1f2b37434e585f6266666666666666666666615f574d42372b1e120600121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919e9e9e9e9e9e9b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b81898f949c9fa6aba39f989298a2aeaea39892989fa3aaa8a09e96918a837d7063574a3d3024170a0000030e18222a31373a3c40404040404044505d6a7783909daab6b0a3968a7d7063574a404040404040403e3b352e251c120700000000000000000000000005121e2a36424d576976828f9ca9b5c2cfdcded1c5b8ab9e928578685e5246525e687885919eabb8c4d1deddd0c3b7aa9d908477675c5145382c1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050e1a242c353e434b5153575a5a5955534e45403931271e150b00000000000000000000000000000005121e2a36424d57616d7a8490949a9b9a9691867c6f665c5044382b1f1206000a1724313d4a5764707d8a979f99938f89837e79736e6962605853514a46413a37312b28221c19130c04000000000000000000000000000003080b0d0e1313131313131313130b0a08050000000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000010d19242f3a434c525459595959595959595959595959595959595959595959595959595957554f473e33281c100400020e1a25303b454d52545959595959595959595955534e463c32261b26323c464e53555959595959595959595955534d453c31261a0e0200121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eababababa89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b86929c9fa6aba69f99928d85929fabac9f92868c92989ea5aca8a09d948b7e7164584b3e3125180b00000a15202a343c4347484d4d4d4d4d4d4d505d6a7783909daab6b0a3968a7d7063574d4d4d4d4d4d4d4c4b4640372e23190d0200000000000000000000000714212d3a46535e697885929eabb8c5d1dedfd2c6b9ada197877a6e61544754616d7a8797a1adb9c6d2dfdfd2c5b9ac9f9286796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d17202c363e474f555d6064676766625f58514b433930271c12070000000000000000000000000000020e1a26313b46525e686e7b83898d8e8d8a847c6f6a5f544a3f34281c1003000a1724313d4a5764707d8a97aba49f9c95908b85807b756f6a64605c54524c47433c38332d29241e160d08000000000000000000000001080f14181a1b202020202020202020181715110c06000000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000008131e28313a4145474c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a48443e352c21160b00000009141f29333b4246474c4c4c4c4c4c4c4c4c4c4947433c342a2015202a343c4347494c4c4c4c4c4c4c4c4c4c4847423c332a1f15090000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7b8b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535f69737f8c96a0a9a19e948f87807d8996a2a4978b7e80868e939da0a7a2988f82766c6256493d3024170b00030f1a26313c464e53555a5a5a5a5a5a5a5a5d6a7783909daab6b0a3968a7d70635a5a5a5a5a5a5a5a5957514940352a1e120600000000000000000000000815212e3b4854616e7b8797a1adb9c6d2dfded5c9beb3a996897d7063564a5663707c8996a9b3bec9d5dedfd3c7bbafa399887c6f6255493c2f2216060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008141e29323e48505961676d717474726e6a605d554b42392e23180c00000000000000000000000000000009141f2a36414c565e696e767d8082817e796f6a5f584e42382e23170b00000a1724313d4a5764707d8a97a3afaca7a09d97928d86817c76716d66615e56534e46443f38352f281f1a1108000000000000000000020b131a202427282d2d2d2d2d2d2d2d2d2524211d1711090000000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000010c161f282f35393a4040404040404040404040404040404040404040404040404040403d3c38332c231a1005000000020d17202930363a3b404040404040404040403c3b37322a22180e18222a32373b3c404040404040404040403b3a37312a21180e030000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d57606d7984919e9f96918a827c737c8995a2a4988b7e737b818990959f9f92867b6e615a5045392d2115080006121f2b37434e585f626767676767676767676a7783909daab6b0a3968a7d7067676767676767676766635b51463b2f23160a00000000000000000000000a1724313d4a5764707d8a97a9b3becad5d2d1d2cfbfb2a5988c7f7265594c5865727f8b98a5b2becfd2d1d2d5cbc0b5ab988b7e7165584b3e2d22170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1925303b44505a616b70797e80817f7b746d675d544a4034281c12070000000000000000000000000000030d1925303a444d565e616b70747574716d665f584e463c30261c110600000a1724313d4a5764707d8a97a3b5b9b1aca9a19e99928e89837e79736d68625f5853504a45413a312c231a100500000000000000010b141d252b30333439393939393939393931302d29221b120900000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000040d161e24292c2d333333333333333333333333333333333333333333333333333333302f2c28211a11080000000000050e171f252a2d2e333333333333333333332f2e2b2620181006101820262b2e2f333333333333333333332e2d2b261f180f06000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3945525f6c7885929fabb8beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000000000000000000020e1a26313b45515c67707d8a93928d847e766e707c8996a3a5988b7f726e757d838b92958c7f72695f53483f34291d1105000815212e3a47535f6a6f737373737373737373737783909daab6b0a3968a7d73737373737373737373736d63574b3e3225190c00000000000000000000000d1a2633404d596673808c99a6b3bfcfc9c6c5c6c9c1b4a79a8e81746753495a6774818d9aa7b4c0c9c6c5c6c9cfc0b4a79a8d817467544a3f33281c0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36414c56616c717d858a8d8d8c8781796d665c5144392e23180c00000000000000000000000000000008131e29323b444d5259606367686764605c544e463c342a1e140a0000000a1724313d4a5764707d8a97a3abacb2b8b3adaba39f9b95908a847f7a746f6a64605b54524c433e352c21160b0000000000000008131d262f363c40414646464646464646463e3d39342d241b1106000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000040c13191d20212626262626262626262626262626262626262626262626262626262423201c16100800000000000000050d141a1e20212626262626262626262622211f1b150e0600060e151b1f21222626262626262626262622211e1a150e0600000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362834404b546c7885929fabb8beb2a5988b7f7265584c3f3225190c00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000009141f2834404b55616b75828f878079716c63707d8996a3a5998c7f72666b70787f858d83786d60574d42362d22170c01000915222f3c4855626f7c808080808080808080808085919eabb8b5a89b8f81808080808080808080807f7366594c403326190d0000000000000000000005111d2a36414c566975828f9ca8b5c2c5beb9b8b9bec3b6a99d908376655b5057697683909ca9b6c3beb9b8b9bec5c3b6a99d908376665b5044382b1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3946525e68717e8791979a9a9a938e82786d60544a4034281c10040000000000000000000000000000020c172029323b42464f54565a5b5a5753514b423c342a22180c020000000a1724313d4a5764707d8a92999ea0a8acaeb4b5afaca79f9d96918c86817c76706c66605d564f473e33281c10040000000000030f1a252f3841484c4e5353535353535353534b49453e362d22170c000000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000001080d111314191919191919191919191919191919191919191919191919191919171614100b0500000000000000000002090e111414191919191919191919191615130f0a04000000040a0f131516191919191919191919191514120e09030000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362c3845515c667985929facb8beb1a5988b7e7265584b3f3225180c00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000000000000000000000000030c18232e39434f59616e7b827c736d676163707d8a96a3a6998d80736660666d727a817c6f665c50453b31241b110600000a1724313d4a5764707d8a8d8d8d8d8d8d8d8d8d8d9197a1adb9b6aa9e938f8d8d8d8d8d8d8d8d8d8d85786b5e5245382b1f12000000000000000000000713202d3946525e687884919eabb8c4bbb3adabadb3bbb8ac9f9285796c60535e697885929fabb8bbb3adabadb3bbc5b8ac9f9285796c605346392d20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3b4754616e7a869299a1a9aca49f948c7f73665c5144382c1f1206000000000000000000000000000000050e17202930363d44484a4d4f4e4b46454039302a22181006000000000815222e3b4855616e7b82868c91969b9fa2aaabb0b8b1aba9a19e98928e88827d78726d6861594f44382c20140700000000000814202b36414a53595b606060606060606060585650483e34291d11050000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000000010406070d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0a09070400000000000000000000000000020507080d0d0d0d0d0d0d0d0d0d0908060300000000000000030608090d0d0d0d0d0d0d0d0d0d0808060200000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362d3a4653606d798698a2aebabeb1a4978b7e7164584b3e3125180b00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000000000000000000000007121d27303e46535e696e766f6a605d5564717d8a97a4a79a8d807467545c60686d746f6a5f544a3f332a1f12090000000a1724313d4a5764707d8a979a9a9a9a9a9a9a9a9a9ea1a9b3bebbafa59e9b9a9a9a9a9a9a9a9a9a9185786b5e5245382b1f12000000000000000000000714212e3a4754616d7a8796a1adb9beb3a9a19ea1a9b3baaea298887b6e6155616e7b8797a2adbab3a9a19ea1a9b3bebaaea298887b6e6255483b2f22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2633404d596673808c98a2abb3b6afa69f9285786d6053463a2d20130700000000000000000000000000000000050e171f252a33383c3d4142413e3a38342e271e18100600000000000814212d3a47535f696e757b7f84898e92989c9fa6abadb2b2adaaa39f9b948f8a847f7a706b6155483c2f23160900000000000b1824303c48535d64676c6c6c6c6c6c6c6c6c64625a5045392d2115080000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5043362e3b4855616e7b8894aab4bfbdb0a3978a7d7064574a3d3124170a00121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000b151e2a36424d575e6169625f58515764717e8a97a4a79a8e8174675b50565e6167625f584e42382e21180e000000000a1724313d4a5764707d8a97a3a6a6a6a6a6a6a6a6abadb3bbc4c1b7afaaa8a6a6a6a6a6a6a6a69e9185786b5e5245382b1f12000000000000000000000a1723303d4a5663707d8996a8b2bdb9ada1979297a1adb9b4aa978a7d70645763707d8a96a9b3b9ada1979297a1adb9bfb4aa978a7e7164574b3e312418090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3643505d697683909caab4bdc0baada297887c6f6255493c2f2216090000000000000000000000000000000000050d141921272c2f30343534312d2c28231d150c0600000000000006121e2b37424d575f61696e72777c81858b9094999ea1a8acaeb4aeaca69f9c96918c867d7063574a3d3024170a00000000010d1a2733404c59646f74797979797979797979716c6256493d3024170a0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000000000000004090c0e0f13131313131313131311110e0b06010000000000000000000000000000000000000000000000000000000000000000000406070a0c0e101011100f0e0b08080602000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c50433639414c5664717e8a97a4b0bdbdb2a895897c6f6256493c2f23160900121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000030c1a25313b454d53545c55534e4b5864717e8b979d9d9b8e8275685b4f4c52545a55544e463c30261c0f06000000000a1724313d4a5764707d8a97a3b0b3b3b3b3b3b3b3b8b9bec4cdc9c1bbb6b5b3b3b3b3b3b3b3ab9e9185786b5e5245382b1f12000000000000000000000c1926333f4c5966727f8c99a5b2bfb8ab9e9285929ea9b3b2a6998c7f73665966727f8c99a5b2b5ab9e9285929eabb8c0b3a69a8d8073675a4d4031251a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2a3744515d6a7784909daab7c3c9beb3a996897d7063564a3d3023170a00000000000000000000000000000000000002090e161c20222327282724201f1c18120b0300000000000000020e1a26313c454d53575e61666b6f747a7e83888d91969b9fa3aaacb1b0aba8a09e988b7f7265584c3f3225190c00000000010e1b2834414e5b6774818686868686868686867e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000000002090f15191b1c2020202020202020201e1d1b17120c04000000000000000000000000000000000000000000000000000000000000070c10131316191b1c1d1d1d1c1a181514120e090401000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504341464b525e6874818e9ba7b4c1b9aca196877a6d6154473a2e21140700121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000009141f29333b4246484f4847434b5865727e8b909090908f8275695c4f4146474e4947433c342a1e150a00000000000a1724313d4a5764707d8a97a3b0b4b4b4b4b4b4b4b8b9bec5cdcac2bbb7b6b4b4b4b4b4b4b4ab9e9185786b5e5245382b1f1200000000000000000004111d2935414b556875828e9ba8b5c0b4a79a8d818d97a1adb5a89b8e827568546875818e9ba8b4afa3998d818d9aabb5c0b6a99c8f827669574d42362a1e120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101c2936434f5c6976828f9ca9b3bdc0b9ada197887c6f6255483c2f2215090000000000000000000000000000000000000000050b101416171a1c1b181313100c070000000000000000000009151f2a333c42474d5254596063676d71767b8084898e92989da0a7b1b7b2acaa988b7f7265584c3f3225190c00000000010e1b2834414e5b6774818e939393939393938b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000000030c141b202528282d2d2d2d2d2d2d2d2d2b2a27231d160e060000000000000000000000000000000000000000000000000000030a0f12181c1f20232628292a2a2a29272522211e1a15100d070100000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c504f4c52555c616e7a86929facb9c4b7ab9e918478685e5246392d20130700121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0200000000000000000000000000000000000000000000000000000000000000000000000000000000030d17212931363a3b433c3a3e4b5764717e8384848484838174675b4e41393a413c3b37322a22190c0300000000000a1724313d4a5764707d8a97a3a7a7a7a7a7a7a7a7abadb3bbc5c2b8b0aba9a7a7a7a7a7a7a7a79e9185786b5e5245382b1f120000000000000000000613202c3945515d677784919eaab7bfb4aa978a7d85919eabb7aa9d908477665c667783909daab6ac9f92867c8999a4afbbb8ab9e928578695e53463a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c97a2abb2b5afa69e9185786c605346392d201306000000000000000000000000000000000000000000000407090a0e0f0e0b070604000000000000000000000000030e18212a31373b4246474f54555d6064696e73787d81868b9095a0acb8bdb2a5988b7f7265584c3f3225190c00000000010e1b2834414e5b6774818e9a9f9f9f9f9f978b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c3023160900000000000000000000000000020c151e252c3134353939393939393939393837332e2820180e04000000000000000000000000000000000000000000000002080d151a1d23282c2d303335363737363634322e2d2b26201d18120c04000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376695c5c5c565e61676d75828f98a3aebabfb4aa9b8e817568564c41362a1d110500121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000050f171f252a2d2e362f303d4955616c71777777777777746f64584c40332e342f2e2b26201910070000000000000a1724313d4a5764707d8a979b9b9b9b9b9b9b9b9b9ea1a9b3bebbb0a69f9c9b9b9b9b9b9b9b9b9b9185786b5e5245382b1f120000000000000000000714212d3a4754606d7a86939facb9baaea298887b828f9ca9b5ac9f9286796d606d7986929facb7aa9d90847986939facb9b9ada297877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a859299a1a8aba39f948b7f72665b5044382b1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f181f262b30363a3d43484b5153575f61666c70757a7f83909daab6beb2a5988b7f7265584c3f3225190c00000000010e1b2834414e5b6774818e9aa7acacaca4978b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000009141e2730373d414246464646464646464644433f39322a20160c01000000000000000000000000000000000000000000040c131920262b2e34383a3d3f414343444342413e3b3a37312c29241d160d060000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f8376696969696a686e7279818e949eaab4bfbaaea3988a7e7164574b3e3025190d0100121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02000000000000000000000000000000000000000000000000000000000000000000000000000000000000050d141a1e212129222d3945505a61646a6a6a6a6a6a67645c53483c30212722221f1b150e07000000000000000a1724313d4a5764707e8a8e8e8e8e8e8e8e8e8e8e9297a1adb9b7ab9f948f8e8e8e8e8e8e8e8e8e8e85786b5e5245382b1f12000000000000000000091623303c4956636f7c899aa4afbbb8ac9f928577808d9aa7b3afa399887b6f626e7b8898a3aeb4a89b8e817784919eaab7beb3a9978a7d7064574a3d31241708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c3945525d68707d8791969a9a99928d82786c60544a3f33281c0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f171f262a3036393d43474b5153575f61666d70757a7f83919daab7beb2a5988b7f7265584c3f3225190c00000000010e1b2834414e5b6774818e9aa7b4b9b1a4978b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c30231609000000000000000000000000040f1b25303942484d4f535353535353535353514f4b443c32281d12060000000000000000000000000000000000000000070e161e2429313739404546494c4e4f5050504f4d4b4847423c39352f281f17110a03000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c2b6a99c8f83767676767676787a7e848e939ea6b0bcc0b6ac9f92867a6d6054473a2d2114080000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f020000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e1214151c1d28333e485055575d5d5d5d5d5d5b58534a41362b201b1615130f0a0400000000000000000916222f3c4955626f7c818181818181818181818185929eabb8b6a99c8f82818181818181818181818074675a4d4134271a0e0000000000000000000c1925323f4c5865727f8b98acb6c0b6a99d9083767e8b98acb6b5ab978a7e7164717d8a97aab4b2a6998c7f75828e9ba8b5bfb3a6998c807366594d403025190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c56606b707d848a8d8d8c8780786d665b5042382d22170b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030d17212931363a4146474e54555d6064696e73797d82868c9195a0acb8c0b2a5988b7f7265584c3f3225190c00000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000915202c37424b53595b6060606060606060605e5c564e44392e23170b00000000000000000000000000000000000000071018202830353c43474b515356595b5c5d5d5d5c5a5855534d474540393128231c150c030000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8ab9f928582828282828384878b91969ea5afb8c1bbafa49a8e8174685d5245392c2013070000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f02020200000000000000000000000000000000000000000000000000000000000000000000000000000000000000020507080c17222c363e45494b5151515151514e4c4841382f251a0f09080603000000000000000000000815222e3b47545f6a6f747474747474747474747783909daab6b0a3968a7d74747474747474747474746e64584c3f33261a0d000000000000000004101c2934404b556874818e9ba7b4c0b4a79a8d81747c899aa4afb3a6998d80736673808c99a6b3b4aa978a7d737f8c99a6b2bfb5a89b8f827568564c4135291d1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d19242f3a444f59606b70797d80807f7b746d665c544a3f2f261c11060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f29333b42464c5254586062676d71767b80848a8f92999da0a7b1b9b5afa5988b7f7265584c3f3225190c00000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000000c1925313d48535d65686c6c6c6c6c6c6c6c6c6b6760564b3f33271b0e020000000000000000000000000000000000071019222a323a41454e53545c60636668696a6a69696765615f5753514b433e342e261e150c0300000000000000000000000000000000121e2b3845515e6b7884919eabb7c4baada297928f8f8f8f8f909196989ea0a8afb7c1bdb3a99f93877c6f62564c4135291d11040000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c0f0f0f0f0c0b09060100000000000000000000000000000000000000000000000000000000000000000000000000000000000006101a242c33393d3e44444444444441403c362f261d1308000000000000000000000000000006131f2b37434e585f626868686868686868686a7783909daab6b0a3968a7d7068686868686868686867645c52473c3024170b000000000000000006131f2c3845515c677784909daab7c0b6ac988b7e727a86939facb5a89c8f82756975828f9ba8b5aea298887b707d8a97a9b3beb7ab9e918478685e5246392d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e28323d474f5960676d717374726e69605c544a42382d1d140a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a26313b454d53565e61656a6f74797e83888d91969b9fa3abacb1b3adaba39f988b7f7265584c3f3225190c00000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000020e1b2834414d59656f757979797979797979797772675c4f43372a1d110400000000000000000000000000000000050f19222b343c444c52585f62666d707274767677767574716e6965605d5550443f3830261e150a00000000000000000000000000000000121e2b3845515e6b7884919eabb7c4beb3a9a29f9c9c9c9c9c9d9ea1a8aaacb2bac1beb5aba1978e81756a5f53443a3024190d010000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c1b1b1b1b191816120d0700000000000000000000000000000000000000000000000000000000000000000000000000000000000008121a22282d30313737373737373433302b251d140b010000000000000000000000000000030f1b26323c464e54555b5b5b5b5b5b5b5b5d6a7783909daab6b0a3968a7d70635b5b5b5b5b5b5b5b5a58524a40362b1f130700000000000000000714202d3a4753606d7986929facb9bbafa49a897c6f7784919eaab7ab9e918478677784919daab7ac9f9285796e7b8797a2adbab9ada196877a6d6154473a2e21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c16202c353d474f555c6064676765615f57514a42392f261c0b020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d575f61686d72777c81858b9094999ea1a9acaeb5b1aba9a19e99928e897e7165584b3e3225180b00000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427303d4a5763707d8a96a3b0bdbcafa296897c6f6356493c302316090000000000000000000000020f1c2835424f5b68758186868686868686868684776b5e5144382b1e1105000000000000000000000000000000020b17212b343d464e565d606a6f74797c7f818283838382807e7b77726d67615a504a423830261c1106000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c5bbb3adaba9a9a9a9a9a9abacb2b7b9bdc3bcb4aca39992857a6d61584e4332281e1308000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352828282828282625221e1811090100000000000000000000000000000000000000000000000000000000000000000000000000000000000810171d2123242a2a2a2a2a2a282724201a130b02000000000000000000000000000000000a15202a343c4347494e4e4e4e4e4e4e505d6a7783909daab6b0a3968a7d7063574e4e4e4e4e4e4e4d4c4740382f24190e0300000000000000000916232f3c4956626f7c8999a3afbbb9ac9f93867a6d75828f9ca8b5ac9f93867a6d7986929facb6a99d908376697885929fabb8bdb2a896897d7063564a3d302317070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d1a232c353d434b5153575a5a5955534d44403930271d140a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535f696e757a7f84898e92989c9fa6abadb2b5aeaca79f9d97928c86817d716c62564a3d3124170b00000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000131f2c3946525f6c7985929facb8c0b4a79a8d8174675a4e413427313d4a5764707d8a97a3b0bdbcafa296897c6f6356493c302316090000000000000000000000020f1c2835424f5b6875828e939393939393939184776b5e5144382b1e11050000000000000000000000000000000a141d29333d464e585f686d747c8185898c8e8f9090908f8d8b88847f79716c605c544a42382e23170d030000000000000000000000000000121e2b3845515e6b7884919eabb7c4cdc5bebab8b5b5b5b5b5b6b7b9bdc4c4bdb9b1aaa39a92877d70685e52463c3120160c02000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423535353535353532312e29231b1309000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c111417181e1e1e1e1e1e1b1a18140f08010000000000000000000000000000000000040e19222a32373b3c41414141414144505d6a7783909daab6b0a3968a7d7063574a414141414141413f3c362f261d13080000000000000000000b1825323e4b5865717e8b98abb5c0b7aa9e9184776773808d99a6b3afa49a897c6f7c8899a3afb4a79a8e8174697683909ca9b6bfb2a5988c7f7265594c3f2f24180d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a232b31394045474a4d4d4c4846423b342e271e150b0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b81868c90959a9fa2aaabb0b8b3adaba39f9b95908b85807b756f6b625a50453a2e21150900000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000121f2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e413025323e4b5865717e8b98a4b1bebcafa295897c6f6256493c2f2316090000000000000000000000020f1c2835424f5b6875828e9b9f9f9f9f9f9e9184776b5e5144382b1e1105000000000000000000000000000006111b262f3b454e58606a6f7a81878e9297999b9c9d9d9c9c9a9895908b847e746d665c544a3f34281f150b0100000000000000000000000000121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbfbebebeb9b8b2ada8a09892887f716b61564c41342a200e0400000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42424242424242423f3e3a352d251b11070000000000000000000000000000000000000000000000000000000000000000000000000000000000000005080a0b1111111111110e0d0b0803000000000000000000000000000000000000000007101920262b2e2f35353535353744505d6a7783909daab6b0a3968a7d7063574a3d35353535353433302b241d140b01000000000000000003101c28343f4a546774818d9aa7b4c0b5a89b8f827568717e8a97abb5b6ac988b7e717e8b97abb5b2a5988b7f726774818d9aa7b4c0b4a89b8e817568554b4035291d10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000811191f272f34383a3e40413f3b3a363128231c150c030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a92999da0a7abaeb3b9b1aba9a19e99928e89837e79736e6963605950483f34291d110500000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000121f2b3845525e6b7884919eabb8c2b5a89b8f827568564c41362a303f4c5966727f8c99a5b2bfbeb3aa95887c6e6255483b2f2215080000000000000000000000020f1c2835424f5b6875828e9ba8acacacaa9e9184776b5e5144382b1e110500000000000000000000000000000b17222d38414d57606a6f7c848e939a9fa2a9a7a9a9aaa9a8a7a7a09d96918a81786d665c50443e31271d120700000000000000000000000000121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b1b1b3adaba8a19e9591867e716d62594f443a3022180e0000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4e4e4e4e4e4e4e4e4c4a463f372d23180d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070e151b1f2222282828282a3744505d6a7783909daab6b0a3968a7d7063574a3d30282828282726241f19130b0200000000000000000006121f2b3844505c667683909da9b6bfb3a6998c8073666f7b8899a3aeb3a79a8d8074808d9aa6b3b3a996897c7065717e8b98abb5c0b7aa9d918477675d5145392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070d151d23292c2d313434322e2d2a261f18120b03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3abacb1b8b5aeaca79f9d97918c86817c77716d67615e57544f473f362d22180c0100000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000111d2a3744505d6a7783909daab6c3b7aa9d908477685e52463b363942505a6875828e9ba8b5c1baaea298877a6d6154473a2e2114070000000000000000000000020f1c2835424f5b6875828e9ba8b5b9b7aa9e9184776b5e5144382b1e110500000000000000000000000000030f1b27333f49535e696f7c8591969fa4acadb3b4b5b6b6b6b5b3b1aca9a19e938e81786d605a5043392f23180c00000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a4a9a19e9b96918b847c716c625a50473d32291e10060000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5b5b5b5b5b5b5b5b5b595751493f35291e1206000000000000000000000000000000000000000000000000010507070a0d0f101111100f0d0b0707050100000000000000000000000000000000000000000000000000000000000000000000000000040a0f1315161b1b1b1d2a3744505d6a7783909daaafafa3968a7d7063574a3d30241b1b1b1a1a17130e0801000000000000000000000713202d3a4653606d7985929facb8bfb4aa978a7d70646d7986929facb6a99c8f8376828f9ca9b5ada197877a6d626f7c8999a4afbbb9ac9f93867a6d6053473a2d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b12181c1f202427272622211e1a140c070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b5b8b3adaba39f9b95908a85807b756f6b64605c55524d48433d352d241b11060000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000f1c2935424f5c6875828f9ba8b5c2b9ac9f93877a6e61564d4642454b54616c7885919eabb8c4b8ab9f928578685d5246392d2013070000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000000005121f2b3744505b656e7b859297a1a8afb6bab9b8b3b1b0b1b5b9bbb8b2ada59d938d80746c61554b4034291c1004000000000000000000000000121e2b3845515e6b78849198989898989898989898989898989898979697918e8a847f786f6a615a50483f352c20170d000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275686868686868686868686865625b51463a2e2216090000000000000000000000000000000000000000000003080d111314171a1b1d1d1d1d1c1a171413110d080300000000000000000000000000000000000000000000000000000000000000000000000000030608090e0e111d2a3744505d6a7783909da2a2a2a2968a7d7063574a3d3024170e0e0e0d0b07030000000000000000000000000915222f3c4855626f7b8898a2aebabaaea298887b6e61667784919daab7ab9e92857884919eabb7ab9e91857868606d7a86939facb9bbafa499897c6f6256493c2f23160700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070c101314171a1a191514120e0903000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b1aba9a19e99928e89837e79736e6863605953514b46423b38322b231b1209000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000d192633404c5966737f8c99a9b3bebbafa49a8b7f72685e56524d51555d66707d8a97a1adb9c2b6a99c8f837669564c4135291d11050000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e1105000000000000000000000000030f1b27333f4953606c77828f97a1a9b2bbbbb3adaba6a4a3a4a8acafb5bdb9afa59d928a7d70675c5145382c1f150a000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8b8b898785817d79726d66605850483f362d231a0e05000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e81757575757575757575757575726d62574a3e3125180b0000000000000000000000000000000000000000060c1013191d2021242728292a2a2928272421201e1913100c060000000000000000000000000000000000000000000000000000000000000000000000000000000204111d2a3744505d6a7783909696969696968a7d7063574a3d3024170a0201000000000000000000000000000000000b1825313e4b5864717e8b97aab4bfb8ac9f9285796c606875828e9ba8b5ada197887b8896a1adb5a99c8f8276695d677784919eaab7c0b5ab988b7e7265584b3f2e23180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406070b0d0e0c080705020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3a79f9d97918c86817c76716d66615e56544f4645403936302c272119100900000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000a1623303d495663707d8997a2adbac0b6ac9e92857a6e69615e575d60676d7983909da9b3bebdb2a8998c807366594d403024190d010000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000005121f2b3744505b65717e8a949fa9b3bcb7aea9a19e9a9796989b9fa3abb2bab7aea49e9184796d6053473c32261b0f0300000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7e7c7b7875706d66605c544e463e362d241b110800000000000000121e2b3845515e6b7884919eabb7c4b7ab9e91848181818181818181818181817f7265594c3f3226190c000000000000000000000000000000000000030a11171c1f252a2d2e313335363737363533312e2d2a251f1c17110a03000000000000000000000000000000000000000000000000000000000000000000000000000004111d2a3744505d6a778389898989898989897d7063574a3d3024170a0000000000000000000000000000000000030f1b27333f49536774808d9aa7b3c0b6a99d908376655b66737f8c99a6b2b3a9998c7f8c99a8b2b3a69a8d807367556875828e9ba8b5c1b4a79a8e817467544a4034281c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a979f9b95908a857f7a756f6a64605c54524d48433d38342e2a251f1b160f070000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000713202d3a4653606d7985929fabb8c1b9ada29790837b736e696a676d7179828f95a0acbbc4b9aca096897c6f6256493c2f231608000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000000613202d394653606c7884919ea6b0bbb7aea49d97918d8a8a8b8e9299a0a8b2bbb9ada1968b7f7265584e43372b1f130600000000000000000000000b1724313d4a56626c71727272727272727272727272727272727271706e696864605c54514a423c342d241b12090000000000000000121e2b3845515e6b7884919eabb7c4b9aca196918e8e8e8e8e8e8e8e8e8e8e8e8275695c4f4236291c0f0300000000000000000000000000000001070c151c23282c3036393a3d40424344444342403e3a3936302c28231c150c0701000000000000000000000000000000000000000000000000000000000000000000000000000915222f3c4855626f7c7c7c7c7c7c7c7c7c7a6d6054473a2d211407000000000000000000000000000000000005121f2b3744505b6576838f9ca9b6c0b4a79a8d8174675364707d8a97aab4b7aa9d9184919daab7b5ab978b7e71645966737f8c99a6b2bfb6aa9d908377665c5144382c1f1206000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a99928e89837e79736e6862605853514b46413b38322c28231d1a140f0a04000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000006121f2c3844515c6674818e9aa5afbcbeb3a99f9590857f7b7877787a7e838f949fa7b1bcbeb3a99e9184786c605346392d201306000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000000a1723303d4a5663707d8996a0acb8bcafa59d928d85807e7d7e82879196a0a9b3bdb2a89d9184776a5f53473b2e21150800000000000000000000000915212e3a45505a626565656565656565656565656565656565656463615e575753514a444039302b221b1209000000000000000000121e2b3845515e6b7884919eabb7c4bdb2a8a19e9b9b9b9b9b9b9b9b9b9b9b8f8275695c4f4236291c0f030000000000000000000000000000040c13181e262e34383a4146474a4d4e505050504f4d4a4746413a38342e261e18130c040000000000000000000000000000000000000000000000000000000000000000000000000815212e3b47535f6a6f6f6f6f6f6f6f6f6f6d685d5245392c20130700000000000000000000000000000000000613202d394653606c7985929fabb8c0b6ac988b7e726558616e7b8898a2aeb8aca0959195a0acb8afa499887c6f625764707d8a97aab3beb9ac9f9286796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a8c86817c76716d66615e56544e4645403936302c271f1c18120e09020000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000004101c2834404a54626f7c88939eaab4bfbbb1a79f97918c87858484868a91959fa6b0b9c3b9ada1978c7f72655b5044372b1f1205000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e1105000000000000000000000005111e2a36414c566774818e9aa8b2bdb4aa9e938d807973717071757c849197a1adb9b8aca096887c6f6255493c2f221609000000000000000000000005111d29343f485056585959595959595959595959595959595958585654534d4a46444039342e271e19100900000000000000000000121e2b3845515e6b7884919eabb7c4c4bab2acaba8a8a8a8a8a8a8a8a8a89c8f8275695c4f4236291c0f0300000000000000000000000000050d161d242930383f44464c5254575a5b5c5d5d5c5b5a5754524c46443f383029241d160d05000000000000000000000000000000000000000000000000000000000000000000000006121f2b37434e585f626363636363636363605d564c4135291d110400000000000000000000000000000000000815222e3b4855616e7b8897a2adbabbafa49a897c6f6356606c7985929facb8b1a8a09da0a8b1b9ac9f93867a6d6055616e7b8898a2aebabaaea398887b6f6255483c2f221506000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d847f7a746f6a64605c54524c47433d38342e2a251f1b16100c070000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000000c18232e3947535f6a75828e98a2aebac0b9b1a9a19e999892919193999da0a8b0b8c2bab0a69e9185796d6053493f33271b0f03000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000713202d3946525e687884919eabb7baaea3988e81746d676463656a6f7b85929eabb8bdb2a8998c7f7266594c3f332619070000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4b4b494846423d3a38342e28231c150c070000000000000000000000121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b4b4b4b4b4b4b4b4b4a89c8f8275695c4f4236291c0f03000000000000000000000000050e171f282f353e424a5053565e61646668696a6a69686664615e5653504a423e352f281f170e0500000000000000000000000000000000000000000000000000000000000000000000030f1b26323c464e5355565656565656565654524c443a3024190d0100000000000000000000000000000000000b1724313e4a5764717d8a97a9b3beb9ac9f93867a6d60545b667783909daab6bab1acaaacb1bab7aa9e918477675d535f697885929fabb8bfb4aa978b7e7164584b3e2d22170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a79736e6862605853514a46413b37322c28231d19140f0a0400000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000007121c2b37434e58616e7b86929fa4aeb7c0bbb3adabaaa29f9d9e9fa4abacb1bac2bab1a89e948b7e71675d5141382d22170b00000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000714212e3a4754616d7a8796a1acb9b9ac9f92867a6e615d5557585f69727f8c99aab4bfb5a89b8f8275685c4f422f24180c00000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3e3d3b3a36312d2c28231c18120b03000000000000000000000000121e2b3845515e6b7884919eabb7c4ccc4bdb9b7b4b4b4b4b4b4b4b4b4a89c8f8275695c4f4236291c0f030000000000000000000000050e172029313a414550545c6064686d707375767777767573716d6864605c545045403a312920170e05000000000000000000000000000000000000000000000000000000000000000000000a15202a343c43474849494949494949494745413a32281e13080000000000000000000000000000000000000d1a2733404d5a6673808d99a6b3c0b7ab9e918478675d51546874818e9ba7b4c1bdb8b7b8bdc2b5a89b8f827568554d57697683909ca9b6c0b3a79a8d80746753493f33271b0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945525d686d6d66615e56544e4644403936302b271f1c18120e0802000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000000000f1b26323c46535f69717e8b929da5aeb9bebeb9b8b4aeabaaabacafb5b8bdbfbab0a8a0958f82756c62554b402f261b110600000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1623303d495663707c8996a8b2bdb6a99c8f8376685e524b4a4e57616e7b8898a2aeb1b1aa9e9184776b554b4035291d100400000000000000000000000009121b22292e3132323232323232323232323232323232323231302e2d2a25201f1c18120c070000000000000000000000000000121e2b3845515e6b7884919eabb7c4c4bab2acaba7a7a7a7a7a7a7a7a7a79c8f8275695c4f4236291c0f0300000000000000000000030c162029323b434b515a61666d71767a7d80818383838382807d7a76716d66615a514b433b322920160c03000000000000000000000000000000000000000000000000000000000000000000040e18222a32373b3c3c3c3c3c3c3c3c3c3a3935302820160c02000000000000000000000000000000000005111e2a36424d566976828f9ca9b5c2b5a89b8f827568554c5965727f8c98a5b2bfc8c5c4c5c8bfb3a6998c807366594e5a6774818d9aa7b4c0b6a99c908376655b5044372b1f120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c565d60605c54524c47433d38342e2a251e1b16100c07000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000000000a15202a36424d57626c74808d939da4adb2babec4bebab8b7b7b9bbc0bfbab4aea69f9691837a6d605a50433a2f1d140a0000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000b1825313e4b5864717e8b97a4b1beb3a79a8d807467564c413d46535f697985929fa4a4a4a49f928579675d5145392c1f1306000000000000000000000000000911181d2124252626262626262626262626262626262625252321211e1a1312100c0700000000000000000000000000000000121e2b3845515e6b7884919eabb7c4bdb2a8a19e9b9b9b9b9b9b9b9b9b9b9b8f8275695c4f4236291c0f03000000000000000000000b151e28323b444c555d606c70787e82868a8d8e8f90908f8e8d8a86837e78706c605d554c443b32281e150b0000000000000000000000000000000000000000000000000000000000000000000006101820262b2e2f30303030303030302d2c29241e160e040000000000000000000000000000000000000714202d3a46525e697885929eabb8bfb3a6998c807366594d5663707d8996a9b3becad1d0d1cbbfb4aa978a7d7164574b5865727e8b98acb6c0b8ab9f9285796c605346392d201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d19242f3a434c525453514a46413b37322c28231c19140f0a040000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000000040e1a26313b45505a606d78818d929ea1a9adb3b8b9bebdbdbdbebab8b4aeaaa39f9490847b6e685d52483f31281d0b020000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000c1925323f4c5865727f8b98a5b2beb3a6998c807366594d4036424d576b78859197979797979798867a6d6053473a2d2014070000000000000000000000000000060c11151718191919191919191919191919191919191818161514120e090604000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b9aca196918e8e8e8e8e8e8e8e8e8e8e8e8275695c4f4236291c0f0300000000000000000007121c27303a444c565e676d757d848a8f9299999b9c9d9d9c9b999993908a847d756d675e564c443a30271c120700000000000000000000000000000000000000000000000000000000000000000000060e151b1f2122232323232323232321201d19130c04000000000000000000000000000000000000000814212e3b4754616e7a8797a1adb9bfb4aa978a7d7164574a54616e7a8797a2adb9c6d2ddd3c7baaea398887b6e62554956626f7c899aa4afbbbaaea298887b6e6155483b2e2215080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040607090a08070502000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e28313a4145474644403936302b271f1c18120e080200000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000000000009141f29333f44505c666d77808a91979fa2a9abadb3b0b0b0b3adabaaa39f98928c827a6e695e564c41362d1f160c000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000c1926333f4c5966727f8c99a5b2bfb3a6998c807366594d403145525e6b78848b8b8b8b8b8b8b8b877a6d6154473a2e2114070000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0b0a08070502000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b7ab9e91848181818181818181818181817f7265584c3f3225190c000000000000000000000c18232e39424c565e686e79818a91969c9fa3aba8a9aaaaa9a8aba49f9c96918a81796e685e564c42392e23180c0300000000000000000000000000000000000000000000000000000000000000000000040a0f12151516161616161616161413110d080200000000000000000000000000000000000000000a1724303d4a5763707d8a96a9b3bebaaea298887b6e615548525e697885929eabb8c5d1ded2c5b8ac9f9286796d60534753606d7a86939facb9beb3aa978a7d7164574a3e31241708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d11131416161514120e0903000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c161f282f35393a3a38342e2a251e1b15100c0700000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000030d182128343f4a545c656c737d848c92979b9ea1a9a3a4a3a9a29f9c98928e867f786e685e574d443a30241b0d04000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333e4a5764717e7e7e7e7e7e7e7e7e7e7a6d6053473a2d20140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e81757474747474747474747474726d62564a3e3125180b00000000000000000004101c2834404a545e686e7a838e939ea0a8acafb5b4b6b6b6b6b5b5afaca8a19e938e837a6e685e544a40342820150900000000000000000000000000000000000000000000000000000000000000000000000003060809090909090909090907070401000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfb8ac9f9285796c6053464d56697683909ca9b6c3cfdcd0c3b6aa9d908377665c5045515d677784919eaab7c0b3a6998d8073665a4d403025190e02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080d13181d2021232322211e1a14100b050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d161e24292c2d2d2c28231c19140f0a04000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000060f17232e38424a535b606c707a80858a8e9297969697969697928f8b86817b736d665e564d453b32281e120900000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333c4955616c717171717171717171716d675d5145382c1f130600000000000000000306070707070707070707070706040000000000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275686868686868686868686865625b51463a2e2216090000000000000000030e18212c3844515c666d7a8490959ea5acb2b9bbc0c1c0bebec0c1c0bbb9b2aca59e9590847a6d665c51443c31261a0f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c566875828f9ba8b5c2b6a99d908376665b50444e5a6774818d9aa7b4c0cddacec1b4a79b8e817468544a404b556875828f9ba8b5c2b5a99c8f827669564d41362a1e110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c13191d24292c2d30302e2d2a261f1c160f080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c13191d2021201f1c18120d08020000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000006111c2630384149505a61676d73797e828587898a8a8a898785827e7a746e69605c544c443b332920160c0000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333945505a6164646464646464646464605d554b4035291d1004000000000000060c1012131414141414141414141413100c07010000000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b5b5b5b5b5b5b5b5b5b585651493f34291e1206000000000000000009141f2b37434e58606d78839096a0a7afb9bdc3bcb8b6b3b2b1b3b6b7bcc2bdb9afa7a0969082786d60584e43372b1f14090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c3945525d687884919eabb7c1b4a79a8e817467544a3f4b5865727e8b98a5b1becfdacbbfb2a5988c7f7265594c404c5966737f8c99a6b2bfb8ab9e918578685e5246392d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050e161e24292f35393a3c3d3b3a36312c27211a1109010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001080d1113141312100c070000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000a141e262f383f4450555d60676d7175787a7c7d7d7d7c7b7975726d68615f57504a423b322921170e040000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033333e4850555758585858585858585853514b43392f24180c0000000000030a11171c1f20202020202020202020201f1d18120b0300000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4e4e4e4e4e4e4e4e4c4a463f372d23180d0100000000000000020e1a26313a47535f6a73808d959fa8b1b9c1bbb7b1abaaa6a5a5a6a9abb0b8bcc1b9b1a89f948d80736a5f53473b31261a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a8796a1acb9beb1a5988b7e7265584b3f4956636f7c8996a9b2bdc9d5cabeb3a996897d7063564a3d4a5764707d8a97aab3beb9ada197877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050e17202830353a41454749494846423b38332b231b13090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104060707060400000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b0000000000000000000000000000020c141d262d333e434c51555d606468686e6f7071706f6e6c6565615e56534d443f38302920170f05000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40332c363e45494a4b4b4b4b4b4b4b4b4b4745403931271d120700000000030c151c23282c2d2d2d2d2d2d2d2d2d2d2d2c29241d150d03000000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42414141414141413f3e3a342d251b1107000000000000000005121e2a36424d57626e7c87929fa7b1bac1b8b0aba79f9d9a9898999c9fa6abb1b9c2bab0a69f92877c6e62574d42362a1e120500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707d8996a8b2bdbdb2a896897c6f6356493c4754606d7a8796a1adb9c5d2c6b9ada297877a6e6154473b4855616e7b8898a2aebabeb3a9968a7d7063574a3d3024170800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b172029323a41464b5154565655534d48443d352d251b110700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b000000000000000000000000000000020b141b2227313a41454b515357565e61636364636361605b5354524c46423b342e261e170e0500000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033262c33393c3e3e3e3e3e3e3e3e3e3e3a38352f271f150b01000000000a151e262e34383a3a3a3a3a3a3a3a3a3a3a38352f271f150b010000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f423535353535353532312e29231b13090000000000000000000714212d3a46535f6975828f99a3afb9c1b8b0a69f9c95908d8b8b8d90949d9fa7b0b8c2bbafa3998f8275695f53463a2d21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926323f4c5965727f8c98a5b2bfb9aca196877a6d6054473a45525d687885919eabb8c4d1c5b8ab9e928578695e5246394653606c7985929fabb8bfb2a6998c7f7366594c402f24190d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141d29333b444c52555d606363615f57544f473f372d23190f05000000000000000000030709090b0b0b0b0b0b0b0b0b090806030000000000000000000000000000000000000000000000000000000000000000000000000306070f1010101010100e0d0b070300000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b00000000000000000000000000000000020a11171f282f35394045474b4c52545657575756545350494746413a363128231c150c050000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40332622282d30313131313131313131312d2c29241d150d030000000006111c2630383f44464747474747474747474745403931271d12070000000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352828282828282525221e181109010000000000000000000815222e3b4855616e7b87939fabb5c0bbb0a69e94908883807f7e80838890959fa6b0bcc0b5ab9f93877b6e6155483b2f24190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101d2935404b556875818e9ba8b4c1b7ab9e918478685d524539414c566976828f9ca9b5c2cfc2b6a99c8f837669564d423744505b657683909ca9b6c1b5a89b8e827568564c4135291d1104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c262f3b454d565d61676d6f706e6963605951493f352b21160b00000000000000040a0f1315161818181818181818181515120f0a040000000000000000000000000000000000000000000000000000000000000000060c1012131c1c1c1c1c1c1c1a1a17130e08010000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e3125180b040000000000000000000000000000000000060d161e24292f35393a3e414647494a4a4a494846443f3a3935302a261f17110a03000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033261a1c212324252525252525252525201f1d18120b0300000000000c17232e38424a505353535353535353535353514b43392f24180c0300000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281c1b1b1b1b191816120d0b0b09050100000000000004111d2935414c566673808c99a4afbdbeb3a99e948f827c7773727273767c838f949faab4bfbbafa4998c807366564c4135291d11040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d677784919daab7c2b5a89b8f827568564c4135404d5a6773808d9aa6b3c0d2c0b4a79a8d8174675a4e41333f49536774818d9aa7b4c0b7aa9e918477685d5245392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d38424d575e686d747a7c7c7b77706b625b51473d33271c10030000000000070f161b1f222325252525252525252522211f1b150e060000000000000000000000000000000000000000000000000000000000030a11171c1f20292929292929292726241f1a130b0200000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e31251814100b0500000000000000000000000000000000040c13191d24292c2d3036393b3c3d3e3d3c3b3937332d2d29251e1a140c060000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033261a111417171818181818181818181413100c0701000000000003101c28343f4a545c60606060606060606060605d554b4035291f140900000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4235281e1e1e1e1e1e1e1e1e1e181715110c0600000000000713202c3945525d687784909dabb5c0baada2978f82786f6a676565666a6f79828f98a2aebac0b5ab9d908377685d5245392c2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7a86939facb9bfb3a6998c807366594d402f3e4b5864717e8b97abb5c0ccbeb1a5988b7e7265584b3f2d3f4b5865727e8b98acb6c0b9aca096877a6d6054473a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c28333f4a545e696e7a8186898988837d726d62594f44382c1f14090000000007101921272c2e2f3131313131313131312f2e2b2620181006000000000000000000000000000000000000000000000000000000030c151c23282c2d363636363636363433302b241d140b0000000000000000000000000000000009101b2834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e312523201c1610080000000000000000000000000000000001080d12181d2020252a2d2e30303130302e2d2b2722201d19130e0903000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033261a0f1315161616161616161616161313100c0700000000000006121f2c3844505c666d6d6d6d6d6d6d6d6d6d6d675d51453b31261a0e02000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f42352a2a2a2a2a2a2a2a2a2a2a2524211d181109000000000714212d3a4754606d7a8795a0acbdc5b8ab9f92857a6d665f585858585f676e7b86929facb8c5b9ac9f93867a6d6054473a2d211407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8999a4afbbbfb4aa978a7d7164574a3e313c4955626f7c8899a4afbbc7bdb2a896897c6f6356493c303c4956626f7c899aa4afbbbdb2a896897c706356493d302316070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505b666e7b848e9298969590877f726b6054483b31251a0e020000040f19222b32383b3c3e3e3e3e3e3e3e3e3e3c3a37312a22180e0400000000000000000000000000000000000000000000000000000a151e262e34383a42434343434343413f3c362f261d0f06000000000000000000000000000009121a222834414e5b6774818e9aa7b4beb1a4978b7e7164584b3e32302f2c27211a1108000000000000000000000000000000000001070d101314191e2021232424242321201f1b1713110d08020000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033261a1b1f2223232323232323232323201f1c18120b03000000000713202d3a4653606d787a7a7a7a7a7a7a7a7a796d60574d42362a1e1205000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f4237373737373737373737373732312e29221b12090000000a1723303d4a5663707d8996a7b1bcc0b3a79a8d8074685d544e4c4b4e555e6974818d9aa7b4c0bbafa49a897d706356493d3023160a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98abb5c0baaea298887b6e6155483b2e3a4753606d7a86939facb9bfb9aca196877a6d6054473a2d3a4753606d7a86939facb9beb2a5988b7f7265584c3f2f23180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c788390969fa3a7a09993877d7063574d42362a1e120500000a16212b343d4348494b4b4b4b4b4b4b4b4b4847433c342a20150a0000000000000000000000000000000000000000000000000006111c2630383f44464f4f4f4f4f4f4f4d4c4740382f21180e0300000000000000000000000006101a242c3439414e5b6774818e9aa7b4beb1a4978b7e7164584b3f3f3d3c38332c231a1005000000000000000000000000000000000000010406080e11141416171717161513120f0b06050100000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40332621272c2e2f3030303030303030302d2c28231d150c030000000a1623303d495663707d8686868686868686868578695f53463a2d211407000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b4f444444444444444444444444443e3d3a342d241b110600000c1825323f4b5865727e8b98a5b1bebfb5ab96897d7063564c423f3f434d5763707d8a96abb5c0c0b6ac988b7e7165584b3e3225180b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b546774818e9aa7b2b2b2ac9f9285796c605346392d3845515d677784919eaab2b2b2ab9e918478675d5145392c3945515d677784919eaab2b2b2a79b8e817468554b4034291c10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313e4b5764717e8a959fa8aeb1aba499908377695e53463a2d21140700030f1b27323d464e545658585858585858585855534e463c31261b0f030000000000000000000000000000000000000000000000000c17232e38424a50535c5c5c5c5c5c5c5a58524a40332a1f15090000000000000000000000000c17222c363e45494e5b6774818e9aa7b4beb1a4978b7e7164584c4c4c4a48443d352c21160b0000000000000000000000000000000000000000000002050708090a0b0a09080605030000000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033262b32383b3c3d3d3d3d3d3d3d3d3d3a38342e271e150b0000000714202d3a4753606d7a869393939393939397887b6e6155483b2e221507000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685b51515151515151515151515151514b4a453f362d22180c01000d1a2633404d596673808c99a6b3bfbbaea399877a6d6154473a30313b4754616d7a8799a3afbbbfb3a6998c807366594d4033261a0d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c667783909da5a5a5a5a59d908376665b5044382b35404b556875828f9ba5a5a5a5a59c8f827569554c41352935404b556875828f9ba5a5a5a5a59d908477675c5145382c1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1c2935424f5c6875828f9ba7b1babdb5aba095877b6e6154483b2e2115080007131f2c38434e586062646464646464646464625f584e43372b1f1206000000000000000000000000000000000000000000000003101c28343f4a545c606969696969696967645c52453c31261a0e000000000000000000000005111d28343e485055575b6774818e9aa7b4beb1a4978b7e71645858585856554f473d33271c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40332b343d4348494949494949494949494645403930271d120700000613202c3945515d677784909da0a0a0a0a9978a7e7164574b3e2f23180c000000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e8275685d5d5d5d5d5d5d5d5d5d5d5d5d5d5d585650483f34291d1105000e1a2734414d5a6774808d9aa7b3c0b9ac9f9286796c605346392d2d394653606c7986929facb9c0b3a69a8d8073675a4d4034271a0d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d798692989898989898988e817467544a3f33282f404d596673808c989898989898988d8073665a4d402f242f404c5966737f8c989898989898989286796d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111d2a3744505d6a7783909daab6c2c7bdb1a796897d706356493d3023160a000915222e3b4854606a6f7171717171717171716f6a5f53473a2e211508000000000000000000000000000000000000000000000006121f2c3844505c666d75767676767676746e64574d42372b1d1207000000000000000000000815212d3945505a6164656774818e9aa7b4beb1a4978b7e7165656565656361594f44382c20140700000000000003080b0d0e1313131313131313130c0b090501000004090e111213131313131313131313080705020000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d4033323d464e545656565656565656565653514b42392e23180c000004111d2935404b556774818e9aa7adadada79a8d807467554b4034291c10040000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e82756a6a6a6a6a6a6a6a6a6a6a6a6a6a6a6a65625a50453a2e211509000e1b2734414e5a6774818d9aa7b4c0b8ab9f928578655b5044372b2b3744505b657885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c888c8c8c8c8c8c8c8c8b7f7265584c3f2d22313e4a5764717e8a8c8c8c8c8c8c8c8a7e7164574b3e3124313d4a5764707d8a8c8c8c8c8c8c8c8c887c6f6255493c2f221609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c0c4bbafa399897c6f6356493c30231609000916232f3c4956626f7c7e7e7e7e7e7e7e7e7e7c6f6255483c2f22150900000000000000000000000000000000000000000000000713202d3a4653606d78828282828282828074695f5347392e23180c000000000000000000000a1724303d4955616c71727274818e9aa7b4beb1a4978b7e727272727272706b6155483c2f2316090000000001080f14181a1b202020202020202020181815110c06080f151a1d1f202020202020202020201414110e0802000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d403338434e586062636363636363636363605c544b4034281c100400010d18242f3e4b5865717e8b98a9b3beb6aa9d908377675c5145382c1f13060000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c1b5a89b8e817777777777777777777777777777777777716c62564a3d3124170b000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f493f332727333f495f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222f3b4855626e7b7f7f7f7f7f7f7f7f7f7f7b6e6155483b2e222e3b4754616e7a7f7f7f7f7f7f7f7f7f7b6e6154473b2e212e3a4754616d7a7f7f7f7f7f7f7f7f7f7f7c6e6255483b2f2215080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa4aeb7b8b2a99f92867a6d6054473a2d211407000e1b2734414e5a6774818b8b8b8b8b8b8b8b8b7f7366594c403326190d000000000000000000000000000000000000000000000006121f2c3844505c6676838f8f8f8f8f8f877b6e61554b4034281c10040000000000000000000b1824313e4b5764717e7f7f7f82909da9b6c1b4a89b8e817f7f7f7f7f7f7d7063564a3d3023170a000000020b131a202427272d2d2d2d2d2d2d2d2d2524221d1811121920262a2c2c2d2d2d2d2d2d2d2d2d21201e19140d050000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333b4854606a6f7070707070707070706d665c5145382c1f130600000715222f3c4855626f7b8897a2adbab9ac9f9286796d6053473a2d2014070000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4b8ab9f928583848484848484848484848484848484837e7165584b3e3225180b000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f52452d22222d45525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3a47535f696e727272727272727272726e695f53463a2d212d3946525e686e7272727272727272726e695e52463a2d202d3946525e686d727272727272727272726e6a5f53473a2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4956626f7c89929da4aaaba8a1978e8175685d5245392c201306000e1b2734414e5a6774818d979797979797978c7f7366594c403326190d000000000000000000000000000000000000000000000003101c28343f4a5466737f8c999c9c9c9a8d8073675c5145382c1f1509000000000000000000111e2b3744515e6a77848b8b8b90959fabb7c2b6aa9e938e8b8b8b8b8b8b8175685b4f4235281c0f0000010b141d252b30333439393939393939393932312e29231b1b242b313638393939393939393939392e2d2a251e170e0500000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d40333c4956626f7c7c7c7c7c7c7c7c7c7d796d6053463a2d20130700000613202d394653606c7985929fabb8bbaea399897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4baada29792909090909090909090909090909090908c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121e2b37424d575f6265656565656565656565615f574d42362a1e2a36414c565e61656565656565656565615e564d42362a1e2a36414c565e6165656565656565656565625f574e42372b1e12060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4754606a74808d929b9e9e9d9691857b6e61564c4135291d1104000e1b2734414e5a6774818d9aa4a4a4a4a4998c7f7366594c403326190d0000000000000000000000000000000000000000000000000c17232e3c4955626f7c8897a1a9ac9e9285796d6053463c31261a0e000000000000000000111e2b3744515e6a77849198989d9fa7b1bcc6baafa59e9b98989898988e8275685b4f4235281c0f000008131d262f363c40414646464646464646463f3d3a342d24242d353d4245464646464646464646463b3936302920170d02000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000d192633404c5966737f8c99a6b2bfb3a6998c807366594d403845525e6b78848989898989898989877a6d6154473a2e211407000005121f2b3744505b6576828f9ca9b5bfb5ab988c7f7265594c3f30251a0e0200000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4beb3a9a29f9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d998c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a26313c454d53555959595959595959595955534d453b31261a25303b444c525459595959595959595954524d443b30251925303a444c52545959595959595959595955534e453c31261a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2b37434e58606d7880898e9191908c847c6f695e52433a2f24190d01000e1b2734414e5a6774818d9aa7b1b1b1a6998c7f7366594c403326190d0000000000000000000000000000000000000000000000000613202d394653606c7885929eabada1978a7e7164574d42372b1d12070000000000000000111e2b3744515e6a7784919da5a9abb1b9c2cbc1b7afaaa8a5a5a5a59b8e8275685b4f4235281c0f00030f1a252f3841484c4e5353535353535353534b4a453f372d2b353f474e52535353535353535353535346413b32291e1408000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000c1926323f4c5965727f8c98a5b2bfb3a6998c807366594d4035414c566b7885919696969696969a877a6d6054473a2d2114070000030f1b27333f49536673808c99a6b3bfb5a89b8e827568574d42362a1e120500000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4c5bbb3adabaaaaaaaaaaaaaaaaaaaaaaaaaaaaa6998c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009151f2a333c4247484c4c4c4c4c4c4c4c4c4c4846423b33291f141e29323b4146474c4c4c4c4c4c4c4c4c4746423b32291f141e29323a4146474c4c4c4c4c4c4c4c4c4c4847423c332a20150900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27323d44505c666d747d828485837f796f6a5f574d4231281e130800000e1b2734414e5a6774818d9aa7b4beb2a6998c7f7366594c403326190d00000000000000000000000000000000000000000000000005121f2b3744505b6575818e9ba8b3a99c8f8376695f5347392e23180c0000000000000000111e2b3744515e6a7784919daab6b7bcc2cbd3c9c1bab6b4b2b2b2a89b8e8275685b4f4235281c0f000814202b36414a53585a606060606060606060585651493f34313d4751595e5f6060606060606060605f524c443b3025190e020000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000c1825323f4b5865727e8b98a5b1beb3a69a8d807367544b403845525d687885929fa3a3a3a39f9386796d6053463a2d2013070000000b17222d3d4a5763707d8a96a8b2bdb7ab9e918478695e52463a2d20140700000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7c4cdc5bebab8b7b7b7b7b7b7b7b7b7b7b7b7b7b2a6998c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030e18212a31373a3b3f3f3f3f3f3f3f3f3f3f3b3a36312921170d1720293036393b3f3f3f3f3f3f3f3f3f3b3a36302920170d1720293036393a3f3f3f3f3f3f3f3f3f3f3b3a37312a21180e0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a152028343f4a545c606b7075777876726d675f584e453b301f160c0100000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000030f1b27333f495364717e8b97a7b1ab9f94887b6e62554b4034281c100400000000000000111e2b3744515e6a7784919daab6b8bcc3cbd3c9c1bbb6b5b2b2b2a89b8e8275685b4f4235281c0f000b1824303c48535c64676c6c6c6c6c6c6c6c6c65625b51453a36424e59636a6c6c6c6c6c6c6c6c6c6c6c5e564c41362a1e11050000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000a1724303d4a5763707d8a96aab4beb5a89b8e8275665c5147464a54606d7a86939facafafab9e918578665c5044382c1f12060000000614212e3a4754616d7a8796a0acb9b9ada196877b6e6154483b2e21150700000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb7bfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb2a6998c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f181f262b2e2f323232323232323232322e2d2a261f170f060e171e252a2d2e3232323232323232322e2d2a251f170e050e171e252a2d2e323232323232323232322f2e2b2620180f06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c17232e38424a50596063686b6b6a66605d554e463c33291f0d040000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d000000000000000000000000000000000000000000000000000b17222d3b4754616e7a8795a0acb0a69a8d8073675c5145382c1f150900000000000000111e2b3744515e6a7784919da6aaabb1b9c3ccc1b7afaaa8a6a6a6a69b8e8275685b4f4235281c0f000d1a2733404c58646e74797979797979797979726d62564a3d3845525e6a757979797979797979797976685e5246392d2014070000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000815222f3b4855626e7b8898a2aebab8ab9e9285796d60595352545c66717d8a9aa4afbbb6a99c90837669544a3f34281c10030000000713202d3946525e687784919eaab7bdb2a8978a7d7164574a3e2e23180c00000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919eabb2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a6998c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e151a1e21222626262626262626262622211e1a140d0600050d14191e202126262626262626262621201e19140d0500050c13191d20212626262626262626262622211e1a150e06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c2630383f444f54565b5e5e5d5953514b433c342a21170d000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326190d0c0b0a070604000000000000000000000000000000000000000614202d3946525e687784909daab7ab9e9285796d6053463c31261a0f01000000000000111e2b3744515e6a77849199999d9fa7b1bcc6bbafa59e9b99999999998e8275685b4f4235281c0f000e1b2734414e5a6774808686868686868686867f7265584b3f3946535f6c79878686868686868686867a6e6154473b2e2114080000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e110500000000000000000000000613202d394653606c7985929fabb8b9ada1978b7f726b63605e61666d7883909dacb6beb3a99a8d8073675a4d402e23170c0000000005111d2a36414c566875818e9ba8b4c0b3a69a8d807367544a4034281c1004000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b7884919ea5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5998c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e121415191919191919191919191514120e090300000002080e1114141919191919191919191414110e090200000002080d111314191919191919191919191514120e0903000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a151e262e343d4448494f5152504c4745403a312a22180f05000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403326191a1918161313100c07000000000000000000000000000000000005111e2a36414d566773808d9aaab4ada1978a7e7164584e43372b1d1207000000000000111e2b3744515e6a77848c8c8c90959fabb8c3b6aa9e938f8c8c8c8c8c8c8275685b4f4235281c0f000e1b2734414e5a6774818d939393939393938b7e7265584b3f3946535f6c79869293939393939393877a6e6154473b2e2114080000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e1105000000000000000000000006121f2b3844505b6675828f9ba9b3beb3a99f92867d746f6d686d7178818e959fabbebaada2978a7d7063574a3d3024170600000000010d1925303f4c5865727f8b98aab4bfb6a99c908376665c5144382c1f1206000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b788491989898989898989898989898989898989898989898989898988c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020608080c0c0c0c0c0c0c0c0c0c0807050200000000000000020507080c0c0c0c0c0c0c0c0c0807050200000000000000010507070c0c0c0c0c0c0c0c0c0c08080602000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c151c232833383b3d424445433f3a39352f281f18100600000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c4033262627262523201f1c18120f0a040000000000000000000000000000020e1925303d4a5663707d8998a2aeb3a99c9083766a5f5347392f23180c0000000000000c1825323f4b5865727e7f7f7f83909daab6c2b5a89b8f817f7f7f7f7f7f7d7164574a3e3124170b000e1b2734414e5a6774818d9a9f9f9f9f9f988b7e7265584b3f3946535f6c7986929f9f9f9f9f9f94877a6e6154473b2e2114080000000000000000000000000000020f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000030f1c28333f4a5464717e8b97a2adbabaaea3989288817c7a797a7e838e939da7b1bcb4aa9f9285796d6053473a2d20140700000000000816232f3c4956626f7c8998a3aebab8ac9f9286796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000121e2b3845515e6b78848c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c7f7366594c403326190d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a111721272c2f3035383837332d2c29241d160d060000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c40333133333332302d2c28231d1b160d0802000000000000000000000000000813202d3a4653606d7985929facb8ab9f94887b6e62554b4034291c100400000000000b1824313d4a56626d72737374818d9aa7b4beb1a4988b7e737373737373716c6155493c3023160a000e1b2734414e5a6774818d9aa7acacaca5988b7e7265584b3f3946535f6c7986929facacacaca194877a6e6154473b2e2114080000000000000000000000000000040f1c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11050000000000000000000000000b17222d3a4753606d7985929fa8b2bdb4aaa39a938e898686878a90959da5afb9baaea2988d8073675c5145382c1f130600000000000713202d3a4653606d7986929facb8baaea398887c6f6255493c2f2216080000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7c6f6256493c2f231609000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c161c202223282b2b2a2620201d18130c04000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c403c3e40403f3e3d3a38342e2b272019130c0400000000000000000000000006131f2c3845515c6775828f9ca8b5b0a69a8d8074675c5145382c1f150a00000000000915222e3a45515b6265666774808d9aa7b3beb2a5988b7f72666666666664615a5044392d211408000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3946535f6c7986929facb9b9ada194877a6e6154473b2e2114080000000000000000000004080a0a11111c2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e11110d0c0a07020000000000000006131f2c3945515d67737f8c96a0abb4bcb4aca49f9b96999399979da0a7afb7b9b0a69f92867b6e61554b4034291c1004000000000006121f2c3844515c667683909ca9b6bfb4aa988b7f7265584c3f3025190d0100000000000000000000000000000000000000000000000000000000000b1724313d4a56626c717272727272727272727272727272727272727272727272727272726f6a6054473b2e221508000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b101316161c1e1f1d191413110d070100000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594c47484b4c4d4c4b4946454039383229251e160e05000000000000000000000004101c2834404b5565727f8b98a8b2b8ab9f9285796d6053473c31261a0f010000000005111d29343f495156585a6773808d9aa6b3bfb2a6998c7f736659595959575550483e33281c1004000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000050b101416171e1e1e2835424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b1e1e1e1a1917130e0800000000000004101d2935404b55606d79849199a3abb4bcb6afaca7aba49fa4abaaabb1b9bbb1a79f948c7f72685e5243392f23180c00000000000004101c2834404a546773808d9aa6b3c0b4a89b8e817568564c41362a1d110500000000000000000000000000000000000000000000000000000000000915212e3a45505a62656565656565656565656565656565656565656565656565656565656260584e43382b1f1306000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407090a0f1112100c07060401000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366594e535558595a59585653514b47433d35302820170f0500000000000000000000000c18232e3b4855626e7b8896a1acb9ada2978b7e7164584e43372b1d120700000000010c18232d373f454a4c5966737f8c99a6b2bfb4a79a8e817467554b4c4c4a49443e362c22170b00000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000810171c2023242a2a2a2a35424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144382b2a2a2a2726231f19120a0200000000000c18242f3945515d676f7d879299a3aab1b8bbb9b4b5afacafb5b6b8bab5afa79f958f82786d60564d4131271d1207000000000000000c18232e3e4a5764717d8a97a9b2bdb7aa9e918477685e5246392d201307000000000000000000000000000000000000000000000000000000000005111d29343f4850565859595959595959595959595959595959595959595959595959595956544e463d32271b0f03000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736659585f62646666666563605c54544e46413a322921170d04000000000000000000000714212e3a47535f6a7884919eabb7b3a99c9083766a5f5347392f24180c000000000006111b242d343a3f4b5865727e8b98a5b1beb6a99c908376675d514b4b4a49443e362c22170b00000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000008111a21282d30313737373737424f5b6875828e9ba8b5c1b7aa9e9184776b5e5144383737373733322f2a241c140a000000000007121d2935404b55606b717e879298a0a7acb1b5b7b8b9b9b9b8b6b4aeaba39f9590837a6d665c50443b301f150b01000000000000000715212e3b4854616e7b8796a1adb9b9aca096877a6d6154473a2e2114060000000000000000000000000000000000000000000000000000000000010c18222d363f454a4b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4947433d342b20160a00000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030608090e0e0e0e0e0e0e09080603000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736660666a6f7173737271706d66626058524c443b33291f160c0100000000000000000006121f2b37434e586774818e9aabb5b7ab9f94887b6f62554b4035291d1004000000000009121b2329313e4a5764717d8a97a4b0bdb8ac9f92867a6d60595858575550483e33281c1004000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000005101a232c33393c3d4444444444444f5b6875828e9ba8b5c1b7aa9e9184776b5e51444444444444403f3b362e261c120800000000010d18242f39434f59616c717e8690959da0a7a8aaabacafacaba9aba39f99928d837a6d685d544a3f32291f0d0300000000000000000714212d3a46535e697885919eabb8bdb2a8968a7d7063574a3d2d22170b00000000000000000000000000000000000000000000000000000000000006111b242d343a3d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3c3b38322b22190f0400000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f1215151a1a1a1a1a1a1a1615130f0a0400000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f73676d72787b7e7f807f7e7c79756f6a615e564d453b31281e1308000000000000000000020f1a26313e4a5764717d8a99a3afbbb0a69a8d8074675d5145382c1f150a000000000000091116232f3c4956626f7c8995a8b2bdbaaea3988b7f726b66656564615a5044392d201408000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000b17212c353e44494a515151515151515b6875828e9ba8b5c1b7aa9e9184776b5e515151515151514d4b4740382e24190e020000000007121d28313d46505a616c717c838b9095999b9d9f9fa39f9e9d9a99928e8780786d685e564c42382e20170d00000000000000000005121e2a36424d576875828f9ba8b5c0b3a6998d807366544a3f33281c0f0300000000000000000000000000000000000000000000000000000000000009121b22292e31323232323232323232323232323232323232323232323232323232322f2e2b27201910070000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e151b1f21222727272727272722211f1b150e07000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736f797f84888b8c8d8c8b8985827c756d685e574d433a2f24190d040000000000000000000914212d3a4754606d7a86929facb9b8ab9f9285796d6053473c31261b0f010000000000000714212d3a4754606d7a8796a1adb9bfb4aa9f92867d77737271706c6155493c3023160a000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000004101c28333e474f55575d5d5d5d5d5d5d5d6875828e9ba8b5c1b7aa9e9184776b5e5d5d5d5d5d5d5d5a58524a40362a1f130700000000010c161f2b343e48505a616a6f787e83888c8f919293999292908d8a86817c736d665e564c443a30261c0e05000000000000000000020e1a25313f4c5966727f8c99abb5c0b6a99c8f8376665b5044382b1f1206000000000000000000000000000000000000000000000000000000000000000911181d21242526262626262626262626262626262626262626262626262626262623221f1b160f07000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006101820262b2e2f343434343434342f2e2b26201810070000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f737d848c9196979999999898928f89817a6e695e564c41352921160b0000000000000000000713202c3945525d687683909da9b6baada2978b7e7164584e43372b1d12070000000000000613202c3945515d677884919eabb7c4baaea298928a83807e7e7e7064574a3d3124170a000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000814202d39444f5961646a6a6a6a6a6a6a6a6a75828e9ba8b5c1b7aa9e9184776b6a6a6a6a6a6a6a6a66635c52473b2f23170a0000000000040d19222d363e4850585f666d71777c7f8284858686868583817e7a746e6a605c544c443a32281e140a0000000000000000000000091623303d495663707c8999a3afbbb8ab9f9285796c605346392d2013060000000000000000000000000000000000000000000000000000000000000000060c111517181919191919191919191919191919191919191919191919191919191615130f0a0400000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040e18222a32373b3c414141414141413c3b37322a22180e0400000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7d8791969ea1a8a6a6a5aaa29f9b938e837b6e685d52453d32271b1002000000000000000004111d2935414c566673808c99a9b3b5b3a99d9083766a5f5347392f24180c00000000000004111d2935414c556874818e9ba9b3bebeb4aaa29f95908d8b8b8376695d5043362a1d10000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000a1623303c4955616c7077777777777777777777828e9ba8b5c1b7aa9e918477777777777777777777736e63584b3f3226190c00000000000007101b242d363e464e545c60646a6f72757778797979787674716d68625f58514b423a322820160c0200000000000000000000000714202d3a4753606d7a86929facb9baaea298887b6f6255483c2f2215080000000000000000000000000000000000000000000000000000000000000000000105090b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c09080603000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a15202a343c4347484d4d4d4d4d4d4d4947433c342a20150a00000000000e1b2734414e5a6774818d9aa7b4c0b5a89c8f82869299a1a8acb2b2b3b2b4aeaca59e9591847a6d60594f44382c1e13080000000000000000010d19242f3c4956626f7c8997a2a8a8a8a89f95887c6f62554b4035291d10040000000000010d19242f3e4b5764717e8a97a1adb9c2bcb4aea79f9d9998908376695d5043362a1d10000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000a1724313d4a5764707d8384848484848484848385929fabb8c5b9ac9f9287838484848484848484838073665a4d4033271a0d0000000000000009121b242c343c424a5053585f6266686a6c666d666b6a6764605d56534e454039302820160e0400000000000000000000000006131f2c3945515d677783909daab6beb4aa988b7e7165584b3e2f24190d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b26323c464e53555a5a5a5a5a5a5a55534e463c32261b0f03000000000e1b2734414e5a6774818d9aa7b4c0b7aa9e948f9299a3abb2b3b5b8babebfbab8afa7a0968e81746b6054483a3025190d0100000000000000000813202d3a4653606d7985929b9b9b9b9b9b9a8d8074675d5145392c1f13060000000000000813202d3a4653606d7985919ea6b0bbc0bebab1abaaa69c908376695d5043362a1d10000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b9090909090909090909297a2adbac6baaea399929090909090909090908e8175685b4f4235281c0f000000000000000009121a222a30383f44464e5355595c5e5f5c605c545d5a5754524c47433c342e271e160e050000000000000000000000000004101d2935404b556774818d9aa7b4c0b4a79a8e817467564c4135291d11040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b37434e585f6267676767676767625f584e43372b1f1306000000000e1b2734414e5a6774818d9aa7b4c0bbb0a69e9c9fa3aba9a7a7a8abadb3bbc0c1b9b1a89d93897d7063564c41362a1d1105000000000000000006121f2b3844505c6675828e8e8e8e8e8e8e8e8e857a6d6053473a2d20140700000000000006131f2c3845515c66727f8b949fa7afb5b8bcbcb8b6a99c908376695d5043362a1d10000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b979d9d9d9d9d9d9d9d9fa2a9b3becabfb4aba39f9d9d9d9d9d9d9d9d9b8e8275685b4f4235281c0f0000000000000000000810181e262e34383c4347484c4f514a5153514a504e4b4745413a373128231d150c050000000000000000000000000000000c18242f3e4b5864717e8b97a9b3beb7aa9d918477685d5245392c2013060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815212e3b47535f6a6f747474747474746f6a5f53473b2e211508000000000e1b2734414e5a6774818d9aa7b4c0c1b8b0aaa8aca49f9d9a9a9b9fa2a9afb6bec3baafa59b8e8175685e5246392d201307000000000000000003101c28343f4a5463707d828282828282828282817c6f6256493c2f23160900000000000004101c2834404b54606c788290959fa4abacb1b0b1b1a99c908376695d5043362a1d10000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b97a4aaaaaaaaaaaaaaabadb3bcc5d0c6bdb4aeacaaaaaaaaaaaaaaa89b8e8275685b4f4235281c0f00000000000000000000060c141c23282b31373a3c3f4244404446444043413e3a39352f2b262018120b03000000000000000000000000000000000715222f3b4855626e7b8897a2adbab9ac9f93867a6d6054473a2d2114070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3c4855626f7c808080808080807c6f6255493c2f221609000000000e1b2734414e5a6774818d9aa7b4c0cac1bab1a7a09a93908e8d8f92979fa4acb6c0c1b9ac9f92867a6d6154473a2e2114070000000000000000000b17232e384855616b70757575757575757575756f6a6054473b2e221508000000000000000c18232e3944505b666d7a838e93999da0a7a3a4a4a49c908376695d5043362a1d10000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b97a4b1b7b7b7b7b7b7b8babec5cecbcfc6bfbab9b7b7b7b7b7b7b5a89b8e8275685b4f4235281c0f0000000000000000000000020a11171c1f262b2e2f33352e34383a38342e34312d2c29241e1a150c070000000000000000000000000000000000000613202d394653606c7985929fabb8bbafa49a897d7063564a3d302317090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825313e4b5864717e8b8d8d8d8d8d8b7e7165584b3e3225180b000000000e1b2734414e5a6774818d9aa7b4c0c8bdb2a8a095908783818082858c939aa4afbbc3baaea3998a7e7164574b3e3124180b00000000000000000006111c2c38444f596163686868686868686868686260584e43372b1f13060000000000000007121d28333f4a545d686d7981878d9095959797989797908376695d5043362a1d10000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b97a4b1bebfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb5a89b8e8275685b4f4235281c0f00000000000000000000000000060b10151b1f2122262923282c2d2c2823272421201d19130f09030000000000000000000000000000000000000005121f2b3744505b6576828f9ca9b5c0b6ac998c7f7366594c4031261a0e0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1925323f4c5865727f8b989a9a9a988c7f7265594c3f3226190c000000000e1b2734414e5a6774818d9aa7b4c0c5b9aca09690837c76747475797f88939fa7b1bcbfb4ab9a8d8073675a4d4034271a0700000000000000000000101c28333e474f55575b5b5b5b5b5b5b5b5b5b56544e463d32271b0f0300000000000000000b17222d38424c565d676d747b808487888a8a8b8b8a898276695d5043362a1d10000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b97a4b1b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2a89b8e8275685b4f4235281c0f000000000000000000000000000000030a0f121515191c181c1f201f1c181b181413110d0801000000000000000000000000000000000000000000030f1b27333f49536673808c99acb6c0b5a89c8f827569574d42372b1e120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6a7a6998d8073665a4d4033271a0d000000000e1b2734414e5a6774818d9aa7b4c0bdb2a89e91847a6f6a6767676d737f8c95a0acb8c3b6a99c908376695d50432e23180c000000000000000000000b16212c353e44484a4f4f4f4f4f4f4f4f4f4f4947433d342b20150a00000000000000000006111c262f3a444c555d60696e73777a7c7d7e7e7e7e7d7b6e6154483b2e211508000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b97a4a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a59b8e8275685b4f4235281c0f0000000000000000000000000000000000030608090c070c10121312100c070b070604010000000000000000000000000000000000000000000000000b17222d3d4a5663707d899aa4afbbb8ab9e928578695f53473a2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1a2734404d5a6773808d9aa6b3a79a8d8174675a4e4134271b0e010000000e1b2734414e5a6774818d9aa7b4c0b9aca196897d70685f58555c606c7883909daab7c3b8ab9e9185786b544a4034281c100400000000000000000005101a232c33383c3d424242424242424242423c3b37322b22190f04000000000000000000000a141d28323a434b51575f6167676d6f7071717171706e695e53463a2d211407000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b97989898989898989898989898989898989898989898989898989898988e8275685b4f4235281c0f0000000000000000000000000000000000000000000000000406070604000000000000000000000000000000000000000000000000000000000000000614212d3a4754606d7a86939facb9b9ada297887b6e6255483b2f22150700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e1b2834414e5b6774818e9aa7b4a89b8e8175685b4e4235281b0f020000000e1b2734414e5a6774818d9aa7b4c0b7ab9e9184786c60564e4b515b66727f8c99a5b2bfb8ac9f928579665c5144382c1f12060000000000000000000008111a21282c2f30353535353535353535352f2e2b27201910070000000000000000000000020b162028313940454d5355555d6062646465646463615e574d42362a1e1205000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000b1825313e4b5864717e8b8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8175685b4f4235281c0f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c3945525d687784919daab7beb3a9978b7e7164584b3e2f24180d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f1c2835424f5b6875828e9ba8b5a99c8f8276695c4f4336291c10030000000e1b2734414e5a6774818d9aa7b4c0b4a89b8e8175655b5044404a54636f7c8996a2afbcbaaea29886796d6053463a2d20130700000000000000000000000810161c2023242828282828282828282823221f1b150f0700000000000000000000000000040e161f282f353c4246484c51545557575858575654534d453b31251a0e02000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000915222f3c4855626f7c7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7d7063574a3d3024170a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c566874818e9ba7b4c0b4a79a8d817467554b4035291d1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c2936434f5c6976828f9ca9b5a99d9083766a5d5043372a1d07000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f736653493f3a4754616d7a8794a0b5c0bfb4aa94877a6d6154473a2e211407000000000000000000000000050b101416171c1c1c1c1c1c1c1c1c1c1615130f0a04000000000000000000000000000000040d161d242931373a3b414547494a4b4b4b4b494846423b33291f140900000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000815212e3a47535f6a6f72727272727272727272727272727272727272727272727272727272727272706b6155483c2f231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1924303f4b5865727e8b98aab4bfb6aa9d908377675d5145392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101d2a3743505d6a7683909da9b6aa9d9184776a5e51442f24180d010000000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f3a4653606d798699a3afbbbaada194877a6e6154473b2e21140800000000000000000000000000000407090a0f0f0f0f0f0f0f0f0f0f09080603000000000000000000000000000000000000040c12181f262b2d2f35393a3c3d3e3e3e3e3d3b3a36312921170d0300000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000006121f2b37434e585f62656565656565656565656565656565656565656565656565656565656565656361594f44382c201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000816222f3c4955626f7c8898a2aebab9ac9f92867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111e2b3744515e6a7784919daab7ab9e9285786b554b4035291d10040000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3844505c667986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070d141a1e2124292c2d2f3131323131302e2d2a251f170f050000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000030f1a26313c464e53555959595959595959595959595959595959595959595959595959595959595957554f473e33281c1004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d7985929facb8bbafa399897c706356493d30231609000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a546b7885919eabb8ac9f928679675d5145392c2013060000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f343f4a5f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e1214191d20212224242525242321211e1a140d05000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000a15202a343c4347484c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4a48443e352c21160b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844505c667683909ca9b6c0b5ab998c7f7266594c3f31251a0e020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844505c667985929facb8aea399867a6d6053473a2d2014070000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f2e46535f6c7986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000205080d111314161718181818161514120e090300000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000030e18222a31373a3c3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3d3c38332c231a1005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a546773808d9aa6b3c0b5a89b8f827568574d42362a1e12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d798698a2aebab5ab94877b6e6154483b2e2115080000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040607090a0b0b0b0b0a08070502000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000006101820262b2e2f32323232323232323232323232323232323232323232323232323232323232302f2c28211a1108000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c17232e3d4a5764707d8a97a8b2bdb8ab9e918578695e53463a2d2114070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212e3a4754616d7a8794aab4bfaea295887b6f6255483c2f2215090000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000060e151a1f2122262626262626262626262626262626262626262626262626262626262626262423201c16100800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000614212e3b4754616e7a8796a1adb9b9ada197877b6e6154483b2e2115070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b8894a1aebbafa296897c6f6356493c302316090000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000000000050a0d101013131313131313131313131313131313131212100e0b07070401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000000000000000030a0f12151519191919191919191919191919191919191919191919191919191919191919171614100b050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a46525e697884919eabb7beb3a9978a7e7164574b3e2e23180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8c0b4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4955626f7c8895a2afbbb0a3978a7d7064574a3d3124170a0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000030a11161a1c1d20202020202020202020202020202020201f1e1d1a181413110d080100000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000000000000000000030608090c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0a090704000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36424d566875828e9ba8b5c0b3a79a8d807467554b4034281c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb8ab9f9285786c5f5245392c2c3945525f6c7885929fabb8bfb4a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1623303d495663707c8996a3afbcb1a4978b7e7164584b3e3125180b0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000000040d151c2226292a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c2b2a272421201d1913100b050000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3844515c667986929facb9baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1925303f4c5965727f8c98abb5bfb6a99d908376675c5145382c1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b2b2b2ab9f9285786c5f5245392c2c3945525f6c7885929fabb2b2b2a79a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a3b0bdb2a5988b7f7265584c3f3225190c0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080000030d161f272d323637393939393939393939393939393939393939383634312d2c29241e1c160f0a04000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3a4653606d798699a3afbbbaada194877a6e6154473b2e21140800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8999a3aebbb9ac9f9286796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa5a5a5a5a59f9285786c5f5245392c2c3945525f6c7885929fa5a5a5a5a59a8d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825313e4b5864717e8b97a4b1beb3a6998c807366594d4033261a0d0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800000a151f2831383e42434646464646464646464646464646464646454543413e3a39352f2c27211b150b060000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb2a5988b7f7265584c3f3a4754616d7a8794a0b5c0baada194877a6e6154473b2e211408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7986929facb9baaea399897c6f6256493c2f23160800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d989898989898989285786c5f5245392c2c3945525f6c788592989898989898988d8174675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1925323f4c5865727f8b98a5b2beb3a79a8d8074675a4d4134271a0e0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e2114080005111c27313a434a4e5053535353535353535353535353535353535251504d4b4745413a38332b272017110a02000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bfb2a6998c7f7366544a3f3c4955626f7c8895a2afbbbfb4aa93877a6d6054473a2d2114070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c677783909daab6bfb4ab988b7f7265584c3f3025190e02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774808c8c8c8c8c8c8c8c8c85786c5f5245392c2c3945525f6c78858c8c8c8c8c8c8c8c8c8074675a4e4134271b0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c99a5b2bfb4a79b8e8174685b4e4135281b0e0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000a16222d38434d555b5d60606060606060606060606060606060605f5e5d5a5754524c48443d373227221b140b030000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b4a79b8e8174665b5046464d5764717e8b97a4b1bebaaea29886796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2934404b556774818d9aa7b4c0b5a89b8e817568564d41362a1e1105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1723303d4a5663707d7f7f7f7f7f7f7f7f7f7f7265584c3f322525323f4c5865727f7f7f7f7f7f7f7f7f7f7d7063564a3d3023170a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2733404d5a6673808d99a6b2b2b2a89b8f8275685c4f4235291c0f0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e211408000d1a26323e4a555f666a6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6b696764605d56544f47433c332d261d150c0300000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7ab9e9184786c60575353555f6975828e9ba8b5c1b8ac9f928579665c5044382b1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232f3e4b5764717e8a97a9b3beb7ab9e918478685e5246392d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916222f3c4854606b70727272727272727272726d62564a3e312424313e4a56626d72727272727272727272706b6054483c2f2216090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa5a5a5a5a59c908376695d5043362a1d100000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101c2936424e5b667176797979797979797979797979797979797978787674716d68636059544e443f382f271e150b00000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b9ada1968a7e716962606061676e7b87929facb9c4b7ab9e9184786b544a3f34281c100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000715222e3b4855616e7b8897a1adb9b9aca196877a6e6154473b2e211406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202c38444f59606365656565656565656565625b51463a2e22222e3a46515b62656565656565656565656360594f44382c2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b2835424e5b6875818e989898989898989084776a5d5144372a1e110000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a76838686868686868686868686868686868686858483807e7a75706b6260585049413930271c1207000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bdb2a89e91857b736e6d6d6e7179839099a3afbbc2b5a99c8f8276695c4f432e23170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535f697885929eabb8bdb2a8978a7d7064574a3d2e23170c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c27333d474f5456595959595959595959585651493f34291e1e29343f4951565859595959595959595956544f473d33271c10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1c2936424f5c6975828c8c8c8c8c8c8c8c8c84786b5e5145382b1e120000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a76839093939393939393939393939393939a939291908d8a86827d776f6a605b534a42392e23180e050000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c4b9ada19791857f7b79797b7e8490959fabb5c0bfb4aa998d8073665a4d4033271a0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2b37424d576975828f9ca8b5c0b3a6998d807366544a3f34281c1003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b16212b353d44484a4c4c4c4c4c4c4c4c4c4c4a463f372d231818232d373f464a4c4c4c4c4c4c4c4c4c4c4a48443d352b21160b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313e4a5764717e7f7f7f7f7f7f7f7f7f7f7265584c3f3225190c0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3946535f6c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909d9f9f9f9f9f9f9f9f9f9f9f9f9fa49f9f9e9c9a99928f89837c736c655c544a40342820170c0200000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c9beb3a9a198928c888686878b91969fa7b1bdc7baaea2988a7e7164574a3e3124170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a2631404c5966737f8c99acb6c0b6a99c908376665c5044382c1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050f19232b33383c3d3f3f3f3f3f3f3f3f3f3f3e3a342d251b11111b252d343a3e3f3f3f3f3f3f3f3f3f3f3d3c38332b23190f05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1723303d4955616c71727272727272727272726d62564a3e3124180b0000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f35404b556c7986929facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9acacacacacacacacacacacb6afacababa9aba39f9c95908780776d665c51443f32291e130800000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c4bab2acaaa29f9995999399989ea1a8b1b9c3c0b5ab9f92867a6d6053473a2d20140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091723303d4a5663707d899aa4afbbb8ac9f9285796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111921272c2f3032323232323232323232312e29231b130909131b23292e3132323232323232323232302f2c272119110800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212d3945505a616465656565656565656565625b51463a2e2215090000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3945515d677986939facb9baada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6b9b9b9b9b9b9b9b9b9b9c0bbb9b8b7b6b5aeaca79f99928c81786d605a50443a3025190d02000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bdb2a8a19ea1a8a6aba49fa4ababacb2bac3c2bbafa4998e8175675d5145392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a4754606d7a86939facb9baaea298887c6f6255493c2f221608000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080f161c2022232626262626262626262524221e18110901010911181e2224252626262626262626262322201c160f0800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d28333e48505557595959595959595959585651493f34291e12060000000e1b2734414e5a6774818d9aa7b4bfb2a5988c7f7265594c3f3a4753606d7a8699a4afbbbaada194877a6e6154473b2e21140800101d2a3743505d6a7683909da9b6c3c6cdc7c4c3bababababababbbdc0c3bfbbb9b1aba39f938e81746c62564c41362a1e1308000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b9aca19691969ea5aeafacafb5b7b9bdc4bebab1a79f93877c6f62554b4035291d1104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202c3945515d677784919daab7bfb4aa988b7e7265584b3f3025190d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b10131617191919191919191919191815120d0600000000060d12151819191919191919191919171613100b0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c17222c363e45494a4c4c4c4c4c4c4c4c4c4c4a463f372d23180d010000000e1b2734414e5a6774818d9aa7b4c0b3a69a8d807367564c413b4854616e7b8794abb5c0bfb4aa94877a6d6154473a2e21140700101d2a3743505d6a7683909da9b6c3cbc2bcb7b6adadadadadadaeb0b4b8b9bec3bdb5afa59d938b7e71685e52463a3025190d010000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0b7ab9e91848f939da4acb1b7b9bbbbb9b8b4aea79f958d80746a6054433a2f24180d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004111d2935414c556874818e9ba7b4c1b4a79b8e817468564c4135291d110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407090a0c0c0c0c0c0c0c0c0c0c0b0906010000000000000106090b0c0c0c0c0c0c0c0c0c0c0a0907040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005101a242c33393d3e3f3f3f3f3f3f3f3f3f3f3e3a342d251b1106000000000e1b2734414e5a6774818d9aa7b4c0b6a99c8f8276685d5246454d5764707d8a97a3b0bdbaaea398867a6d6053473a2d20140700101d2a3743505d6a7683909da9b6c3c2b9b0aba9a0a0a0a0a0a1a2a3a7abadb3bbc1c0bbafa59f92857a6d61564c41362a1e11050000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7f828d929da0a7aaacafafacabaaa29f959083796d60584e4331281d13070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d19242f3e4b5865717e8b98aab4bfb7aa9e918477685e5246392d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008121a22282d303132323232323232323232312e29231b130900000000000e1b2734414e5a6774818d9aa7b4c0b9ac9f92867a6d60595351555e6974818e9aa7b4c1b8ac9f928579675d5145392c1f130600101d2a3743505d6a7683909da9b6c3bcb0a69f9c94949494949495979a9ea2a9afb7c1c0baaea2988d8074685e5246392d2014090000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e79808990959a9d9fa3a39f9e9b98928c837a6d675d51463d321f160c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222f3c4855626f7b8898a2aebab8aca096877a6d6154473a2e21140600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810171d2123242626262626262626262524221e1811090100000000000e1b2734414e5a6774818d9aa7b4c0baaea3998c80736b615e5d60676e7b86929facb8c4b7aa9e9184776b554b4035291d100400101d2a3743505d6a7683909da9b6c3b7ab9f9490878787878787888a8d92979ea5afb7c1beb3aa9f92867a6d6154473b30251a0e0200000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e72747d83898d9092999992918f8b857f796d685d554c41342b200d04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7985929facb8bdb2a8968a7d7063574a3d2d22170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050c11141717191919191919191919191815120d06000000000000000e1b2734414e5a6774818d9aa7b4c0bfb4ab9f92867d736e69676d7179829098a2aebac2b5a99c8f8276695c4f432f24180c0000101d2a3743505d6a7683909da9b6c3b6a99c90837a7a7a7a7a7a7b7d81858e939da5afbbc4bbaea3998c7f7265574d42362a1e120500000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e726b70777c80848687878685827e7a726d675d564c433a2f22190f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505b6676838f9ca9b6bfb3a6998c80736653493f33271b0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005080a0b0c0c0c0c0c0c0c0c0c0c0b09060100000000000000000e1b2734414e5a6774818d9aa7b4c0c6baaea3989287807b78787a7d8390949faab4bfbeb3a9998d8073665a4d4033271a070000101d2a3743505d6a7683909da9b6c2b6a99c8f83766d6d6d6d6e6f70747a818e939da9b3bebfb5ab9d918477695e52463a2d20140700000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265636b6f7477797a7a797875716d68605c554c443a31281e10070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c28333f4a546673808d99a6b3c0b5a99c8f8276655b5044372b1f12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0c4bdb4aaa399928d878585868a91959fa6b0bcc5baada297897d7063564a3d3023170a0000101d2a3743505d6a7683909da9b6c2b6a99c8f837669616161616264686d77818e97a1adb9c6b8aca095877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e726559606367666c6d6d6c656865615e56514b433a32281f160c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d3d4a5764707d8a97a8b2bdb8ab9f9285796c605346392d2013060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4c0bab2adababa39f9997929192999da0a8b0b8c2bfb4aa9f9285796d6053463a2d2013070000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c54545455565d656d7985919eabb8c3bcb1a7978b7e7164584b3e3125180b00000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265585456545b606161605b535854524c454039312820160d04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000614212e3b4754616e7a8796a1acb9baada297887b6e6255483b2f2215070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4bdb2a8a19e9ea0a8a9a29f9e9fa3abacb1bac2bfbaaea2988d8074665c5145382c1f13060000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504747484c535d67727f8c98a8b2bdc0b4a79a8d8174675a4e4134271b0600000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b494a505354545350494b4746413a342f271f160e0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3946525e687884919eabb7beb3a9988b7e7165584b3e2f24180d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4b9ada196919196a0a9adababacafb5b8bdc3bcb8aea59f92867b6e61544b4034281c10040000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433b3c414b55616e7b8796a0acb8c2b5a99c8f8276695c4f432d22170b00000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3f4446474746443f3e3a39363029231d150d0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36414c566875818e9ba8b5bcb4a79a8e817467554b4135291d110400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b2b2ab9e9184849197a0a7aeb4b8b9bebab8b7b1aba49c938c7f72695e5242392e23180c000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362f3946535e697784919daab7c4b7ab9e9184786b5e493f33271b0f03000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3338393a3a3937332d2e2d2a251e18120b0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d1925303f4c5865727f8b98aab4afafaa9d908477675d5145392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa6a6a6a69e91847b8591959fa2aaabadb3aeacaaa7a09d928d81746d62574d4230271d1207000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362a36424d576875828f9ba8b5c2b8ab9f928578655b5044372b1f1205000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f322b2d2e2e2d2b272221201d19130c07010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000816232f3c4956626f7c8998a3a2a2a2a29f93867a6d6054473a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9999999999999184777c838d92989b9ea1a9a29f9d9a95908980746f645b51453b301e150b00000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362531404d5a6673808d99a6b3c0b9ac9f9386796c605346392d201306000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225202121201f1b171413110d080200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3a4653606d79869295959595959599897d706356493d3023160a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734414e5a6774818c8c8c8c8c8c8c8c84776e7980858b8f9297949892918d89837d736e645d53493f33291f0c0300000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629333f4c5966727f8c99a5b2bfbbafa49a867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f322518141413120f0b060705010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3845515c6676838989898989898989897f7366594c403326190d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a1724303d4a5763707d7f7f7f7f7f7f7f7f7f72676d737a7f82858687868584807d78706b635c534a41372d21170d0000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323f4c5865727f8b98a5b2bec0b6a093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c0706050300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c2834404b54616e7b7c7c7c7c7c7c7c7c7c7b6e6155483b2e22150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000916232f3c4855616b707373737373737373726d6260686d7275787a7a7a797774706c656059524a41382f251b0f050000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c18232e3946535f696e6f6f6f6f6f6f6f6f6f6e695f53463a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202c38444f596163666666666666666665625b565d606568676d6e6d676a6763605b534f4740382f261d1309000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4beb1a5988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121d2b37424d575f61626262626262626262615f574d42362a1e1205000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101c28333e474f555759595959595959595856514c525458555c6061605d555a56535049413d352e261d140b01000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7b4b9b1a5988b7e7265584b3f3225180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1a26313c454d535556565656565656565655534d453b31261a0e020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b16212c353e44484a4c4c4c4c4c4c4c4c4b4a464145474b4b51535453514b4d4a46443f382f2b231c140b0200000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa7adadada5988b7e7265584b3f3225180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f2a333c4246484949494949494949494846423b33291f14090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005101a232c33383c3d40404040404040403f3d3a35393a3f40454747474540413d3937332d261d19110a010000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d9aa0a0a0a0a0988b7e7265584b3f3225180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030e18212a31373a3b3c3c3c3c3c3c3c3c3c3b3a36312921180d03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a21282c2f30333333333333333332312e292c2d2f34383a3b3a39352f302d2b27221b140b0700000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774818d939393939393938b7e7265584b3f3225180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f181f262b2d2e2f2f2f2f2f2f2f2f2f2e2d2a261f180f06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810161c20232426262626262626262524221d202123292c2d2e2d2c292423201f1b17110a020000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000e1b2734414e5a6774808686868686868686867e7265584b3f3225180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060e141a1e212223232323232323232322211e1a140d06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b101416171919191919191919181815111314181c1f202120201d181713120f0b0600000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000713202d3a4653606d797a7a7a7a7a7a7a7a7a786d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003090e1214151616161616161616161514120e09030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407090a0d0d0d0d0d0d0d0d0c0b090406070c101314141413100d07060503000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d2014070000000000000000000000000000000000000000000000000006131f2c3845515c676d6d6d6d6d6d6d6d6d6d6d665c5044382c1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000205070809090909090909090908070502000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040607080706040100000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d2014070000000000000000000000000000000000000000000000000004101c2834404b555c60606060606060606060605c544a3f34281c100300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000000000000000000000000000000000000000c18232e39434b515353535353535353535353504a42382e23170c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406070a0d0f11121211100f0c0906050300000000000000000000000000000000000000000000000003080b0d0e1313131313131313131212100c08020000000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000007121d27303940454647474747474747474746443f3830261c1106000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001070c101314171a1c1e1e1f1e1d1b191613120f0b06000000000000000000000000000000000000000001080f14181a1b2020202020202020201f1e1c18130d0600000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d2014070000000000000000000000000000000000000000000000000000000b151e272e34383a3a3a3a3a3a3a3a3a3a3a38342e261e150a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030a0f12181d1f202427292a2b2b2b2a282623201f1b17110d080200000000000000000000000000000000020b131a202427272d2d2d2d2d2d2d2d2d2c2b28241f181007000000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000030c151d23282c2d2d2d2d2d2d2d2d2d2d2d2c28231c150c03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080d151a1d24292c2d303335373838383735322f2d2b27221b19130c060000000000000000000000000000010b141d252b3033343939393939393939393938353029221910060000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000000000000000000000000000000000000000000030b12181c1f20202020202020202020201f1c17110a030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040c131920262b2f35393a3d40424445454443423f3c3937332d29251e17110a0300000000000000000000000008131d262f363c40414646464646464646464544413b342b22180d0200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000070c1013131414141414141414141312100c06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070e161e24293137394045474a4d4f51515251504e4c4946443f38353028231c150c0500000000000000000000030f1a252f3841484c4e53535353535353535352514c463d34291f130800101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000004060707070707070707070707060300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081019202830353c43474b5153575a5c5d5e5e5e5d5b595653504946413a342e261e170e060000000000000000000814202b36414a53585a6060606060606060605f5d574f463b3024180c00101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a222b323a41464e53555d606366686a6b6b6b6a686562605b53524c443f38302920180f0600000000000000000b1824303c48535c64676c6c6c6c6c6c6c6c6c6c6961574c4135281c1000101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111a232c343d444c52585f62676d707375777878777675726f6c65615e56504a423b322a21180f06000000000000000d1a2733404c58646e747979797979797979797873695d5144382b1e1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d201407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f1a232c363e464f565d616a6e74797d80828484858483817f7c78736d68605c544d443c332a21180d040000000000000e1b2734414e5a67748186868686868686868685786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c18212c353e48505960686d747c81858a8d8f90919191908e8c8984807a726d665e564e463c332a1f160c0100000000000e1b2734414e5a6774818d939393939393939285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323e4b5865717e8b98a4b1beb9ada093867a6d6053473a2d20140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a151e2a333e47505a616b6f7a81878e9298999b9d9e9e9e9d9b9896918c867f786e695f584e453b31281e130800000000000e1b2734414e5a6774818d9a9f9f9f9f9f9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629323f4b5865727e8b98a5b1beb9ada093867a6d6053473a2d2014070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c26303c454f59616c707d848e939a9fa2aaa8aaababaaa9a8a8a19e98928c827b6e6a5f574d433a2f24190d05000000000e1b2734414e5a6774818d9aa7acacacab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433629333f4c5966727f8c99a5b2bfbbafa49986796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c17232e38424e57616b707e8791969fa4acaeb4b5b7b7b8b7b6b4b2acaaa29f9490847c6e695f554c41352921160b000000000e1b2734414e5a6774818d9aa7b4b9b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362933404d5a6673808d99a6b3c0b9ac9f938679665c5145382c1f130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c28343f4a545f6a707d879299a1a9afb6babfc2c0bebdbec1c1bdb9b4aea69f9691857b6e675d51453d32271c10040000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5043362c38434f596875828f9ba8b5c2b8ab9f9285786c544b4034281c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2c3844505c666e7c869299a3abb2bbc0bdb9b8b3b1b0b1b4b8babfbfbab0a8a19791847a6d60594f44382c21160a0000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504334383e4854606b7884919eabb8c3b7aa9d9084776a5d51442e23180c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004101d2935404b55606d78839098a2abb4bdc0bbb2adaba6a4a3a5a7acaeb4bcc1bab2a9a0968e81746b6054483d32271b0f0000000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c50433f4446505a636f7c8996a1adb9c2b5a89c8f8275695c4f4236291c0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006131f2c3945515d67727f8b959faab4bdbdb5afa8a19e999796989b9fa3aaafb7c1bbb2a89d93897d7063594f44382c1c110600000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c504f4a505359616c75818e9ba8b2bdc0b5ab998d8073665a4d4033271a0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a4753606d7985929ea7b1bcc0b5aba39f96918d8b8a8b8e92989ea5afb7c1baafa59d9083776b605448382e23170b00000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376695c5c5c545c60636b707e8a939eaabac4bbafa3998a7d7064574a3d3124170a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36414c5665717e8b97a1adb9c3bbafa399928c84807e7d7e81868f939da5afbbc1b8ab9f95897c6f63544a3f34281c1003000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f83766969696969666d6f757d86929fa5afbac5b9ac9f92867a6d6054473a2d21140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3946525e687683909ca9b3bebbb0a69f92877f7973717072747a818e939da9b3bebcb1a79b8e8174665c5044382b1f1206000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c2b6a99c8f8376767676767677797c828a9298a2aeb7c1bdb2a89c8f8276675d5145392c20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3b4754616e7a86939facb9c5b7aa9e948a7e726d66646365686d77818e97a1adb9c3b8ab9e9285796d6053463a2d201307000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c3b8ab9f92858282828282838485898e939fa2aab4bfc4b9aca0968a7e7164554c4135291d110400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313e4a5764717d8a99a4afbbbfb4aa9c8f82766c605c5457565e656d7a85929eabb8c5b9ada297887c6f6255483c2f221509000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c3baada297928f8f8f8f8f8f9092989b9ea5aeb4bcc4bab0a69e9184786d6053463a2f24190d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d1a2733404d5a6673808d99abb5c0baaea398897d70635a504a4a4c535d6873808d99a6b3c0beb3a9988b7e7165584b3e3225180b000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c3beb3a9a29f9c9c9c9c9c9c9d9fa2aaaaafbabfc4bbb2a89e948a7e71665c504438281e13080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1c2835424f5b6875818e9ba8b5c1b8ac9f9286796d6053473f3d414c56636f7c8996aab4bfc0b3a6998d8073665a4d4033271a0d000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c3c5bbb3adaba9a9a9a9a9a9aaabaeb4b6bbc1c1bab2a9a0968f82756c61544a3f3428160c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3643505d697683909ca9b6c3b7aa9d908477675c5145382f3a4753606d7a8698a2aebac1b4a79b8e8174685b4e4135281b0e000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6c3cdc5bebab8b5b5b5b5b5b6b7b8babec5c2bcb8afa8a09791847a6d615a5042382e23170400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2a3744515d6a7783909daab7c2b5a99c8f827669554b40342c3945515d677985929facb8c2b5a89b8f8275685c4f4235291c0f000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b6bfbfbfbfbfbfbfbfbfbfbfbfbfbebdbdb8b7b1aba59e9691857c6e685e52483e30261c110600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a7784919daab6b6b5a89b8f8275685c4f422f2935404b556b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da9b2b2b2b2b2b2b2b2b2b2b2b2b2b2b1b1b2acaaa79f9d938e847b6e6a5f564c41362c1e150a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a7784919da9a9a9a9a89b8f8275685c4f4235242f45525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909da5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a4a8a09d9a959089817a6e695f584e443a30241a0c030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a7784919d9d9d9d9d9d9b8f8275685c4f42352b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a7683909898989898989898989898989898989898979696918d89837d756d685f574e463c32291e1208000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a778490909090909090908f8275685c4f42352b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200101d2a3743505d6a76838c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8b8a898784807c76706b605d564d453c342a20170c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1c2835424f5b6875818383838383838383838073665a4d40332b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000b1824313e4b5764717e7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7e7e7c7a77746f6a636059524c433c332a22180e05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2734404d59656f75767676767676767676736e63584b3f322b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000a1723303d4955616c71727272727272727272727272727272727272716f6d6867626058544f45413a312a21180f0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825313d48535d65686a6a6a6a6a6a6a6a6a66635c52473b2f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000815212d3945505a61646565656565656565656565656565656565656463615e5656544e48443d352f281f180f060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814202c37414b53595b5d5d5d5d5d5d5d5d5d5a58524a40362a2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120005111d28343e48505557595959595959595959595959595959595958575654524c4947433d383329241e160d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040f1a252f3941484d4f5050505050505050504d4b4740382e242b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000c17222c363e45494b4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4b4b494746413c3b38322c272119130c0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009131e272f373d4042434343434343434343403f3b362e261c2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000006101a242c34393d3e3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3e3c3a3935302e2b27201c160d080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c151e252c31343537373737373737373733322f2a241c1f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f1200000008121a22282d303132323232323232323232323232323232323231302e2d2925221f1b16100b0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c131a202527282a2a2a2a2a2a2a2a2a2726231f19121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f12000000000810171d212324262626262626262626262626262626262625242321201d1915130f0a040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002090f14181b1c1d1d1d1d1d1d1d1d1d1a1917130e121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000060c1115171819191919191919191919191919191919191818161413110d080603000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004080c0e0f1010101010101010100d0d0a0702121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000005080a0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0b0907070501000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020404040404040404040000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4c0b8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8c2b5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b4bfb8ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb8bfb5a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa7b2b2b2ab9f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919eabb2b2b2a99c8f8276695c4f4336291c10000e1b2734414e5a6774818d9aa5a5a5a5a59f9285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b7885919ea5a5a5a5a59c8f8276695c4f4336291c10000e1b2734414e5a6774808d989898989898989285786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b788591989898989898988f8276695c4f4336291c10000e1b2734414e5a6774818c8c8c8c8c8c8c8c8c85786c5f5245392c1f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3845525e6b78858c8c8c8c8c8c8c8c8c8276695c4f4336291c10000a1723303d4a5663707d7f7f7f7f7f7f7f7f7f7f7265584c3f3225190c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727f7f7f7f7f7f7f7f7f7f7e7164574a3e3124170b000916222f3c4854606b70727272727272727272726d62564a3e3124180b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313d4a56626d72727272727272727272716c6155493c3023160a000713202c38444f59606365656565656565656565625b51463a2e22150900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222e3a45515b626565656565656565656564615a5044392d2114080004101c27333d474f5456595959595959595959585651493f34291e1206000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121d29343f49515658595959595959595959575550483e33281c100400000b16212b353d44484a4c4c4c4c4c4c4c4c4c4c4a463f372d23180d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c18232d373f454a4b4c4c4c4c4c4c4c4c4c4a49443e362c22170b000000050f19232b33383c3d3f3f3f3f3f3f3f3f3f3f3e3a342d251b11060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111b252d343a3d3f3f3f3f3f3f3f3f3f3f3e3c39332c241a10050000000008111921272c2f3032323232323232323232312e29231b130900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b23292e313232323232323232323231302d28221a1208000000000000080f161c2022232626262626262626262524221e18110901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000911181d2224252626262626262626262423211c1710080000000000000000050b10131617191919191919191919191815120d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c12151818191919191919191919171614100b0500000000000000000000000407090a0c0c0c0c0c0c0c0c0c0c0b0906010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105090b0c0c0c0c0c0c0c0c0c0c0b0a08040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + m_StreamData: + serializedVersion: 2 + offset: 0 + size: 0 + path: diff --git a/Assets/Common/Fonts/Korolev Condensed W04 Bold SDF.asset.meta b/Assets/Common/Fonts/Korolev Condensed W04 Bold SDF.asset.meta index d6cf5df..d2bd114 100644 --- a/Assets/Common/Fonts/Korolev Condensed W04 Bold SDF.asset.meta +++ b/Assets/Common/Fonts/Korolev Condensed W04 Bold SDF.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 3602bedf0ebe5b64596873f09eddf57b +guid: 1baf2eae62f542f4585aaf3c9c3e229a NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/Common/Fonts/contb SDF.asset b/Assets/Common/Fonts/contb SDF.asset new file mode 100644 index 0000000..beafa51 --- /dev/null +++ b/Assets/Common/Fonts/contb SDF.asset @@ -0,0 +1,504 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!28 &-8106515014133881816 +Texture2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: contb Atlas + m_ImageContentsHash: + serializedVersion: 2 + Hash: 00000000000000000000000000000000 + m_ForcedFallbackFormat: 4 + m_DownscaleFallback: 0 + m_IsAlphaChannelOptional: 0 + serializedVersion: 2 + m_Width: 1024 + m_Height: 1024 + m_CompleteImageSize: 1048576 + m_MipsStripped: 0 + m_TextureFormat: 1 + m_MipCount: 1 + m_IsReadable: 1 + m_IsPreProcessed: 0 + m_IgnoreMasterTextureLimit: 0 + m_StreamingMipmaps: 0 + m_StreamingMipmapsPriority: 0 + m_VTOnly: 0 + m_AlphaIsTransparency: 0 + m_ImageCount: 1 + m_TextureDimension: 2 + m_TextureSettings: + serializedVersion: 2 + m_FilterMode: 1 + m_Aniso: 1 + m_MipBias: 0 + m_WrapU: 0 + m_WrapV: 0 + m_WrapW: 0 + m_LightmapFormat: 0 + m_ColorSpace: 0 + m_PlatformBlob: + image data: 1048576 + _typelessdata: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030709091313131313131313131313130c0b0906010005090d0f1013131313131313131313131312100d080200030709091313131313131313131313130c0b0906010000000000000000000000000407090a1313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313130d0c0a070200000000000000000000000000000000000000000000000000000000000000000001040607070604000000000000000000000000000000000000000000000000030607070605030000000000000000000000000000000000000000000000000000000000000000000001060b0e11111313131313131313131313080705020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f131516202020202020202020202020191816120d0a1015191c1d20202020202020202020201f1f1c19140d0a0f131516202020202020202020202020191816120d07000000000000000000050b101316172020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020201a1917130e0700000000000000000000000000000000000000000000000000000000030608070d1113141312100c070704010000000000000000000000000000000406060b1012131413120f0b0605030000000000000000000000000000000000000000000000000000000000040c12171b1d1e20202020202020202020201514120e09020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070f161b1f22232d2d2d2d2d2d2d2d2d2d2d2d2625221e18141b212628292d2d2d2d2d2d2d2d2d2d2d2c2b29251f18161b1f22232d2d2d2d2d2d2d2d2d2d2d2d2625221e18110a01000000000000080f161c2022232d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2626231f19120a01000000000000000000000000000000000000000000000000040a0f121515181d2021201f1c181413110d08010000000000000000000000070c101213171c1f2021201f1b1713120f0b060000000000000000000000000000000000000000000000000000060e161d23272a2b2d2d2d2d2d2d2d2d2d2d2d21201e1a140d0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007101921272c2f3039393939393939393939393932312e29231e262d3235363939393939393939393939393835302a2221272c2f3039393939393939393939393932312e29231b130a000000000008111921272c2f3039393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393933322f2a241c130a00000000000000000000000000000000000000000000030a0f151b1f212224292c2d2d2c282321201d19130b060000000000000000030b12181c1f2023282b2d2d2d2b2722201f1b17110a020000000000000000000000000000000000000000000000040e1820282e33373839393939393939393939392e2d2a251f170f0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040f19232b32383b3c4646464646464646464646463f3e3a352d2830383e414346464646464646464646464644413b342c2b32383b3c4646464646464646464646463f3e3a352d251b1107000000050f19232b33383c3d464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646403f3b352e261c12070000000000000000000000000000000000000000060e151b20262b2e2f2f35393a3a38342e2d2c29241e17110a020000000000060c151c23282c2d2e34383a3a3937332d2d2b27221b140b07000000000000000000000000000000000000000000010c16202a32393f434446464646464646464646463b3a36302921170d020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a16212b353d4348495353535353535353535353534c4a463f37303a42494e50535353535353535353535352514d463e34353d4348495353535353535353535353534c4a463f372d23180d0100000b16212b353d44484a5353535353535353535353535353535353535353535353535353535353535353535353535353535353535353535353534d4b4740382e24190e0200000000000000000000000000000000000009101820262b31373a3c404145474644403f3a39352f28231c140c050000020a11171e272e34383a3e3f44464746443f3d3937332d261d19110a010000000000000000000000000000000000000006121d28323c444b4f5153535353535353535353534846423b33291f14090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27323d474f5456606060606060606060606060595751493f38424c545a5c60606060606060606060605f5d5850463b3d474f5456606060606060606060606060595751493f35291e12060004101c27333d474f54566060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060605957524a40352a1f1307000000000000000000000000000000000009121b222a31373c4347484d4b515453514a4c4745413a342e261e170e05020b141b222730394044464b4a5053545350494946443f382f2b231c140a020000000000000000000000000000000000000b17232e39444e565c5e60606060606060606060605f524d453b30251a0e020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007131f2c38434f5960636c6c6c6c6c6c6c6c6c6c6c6c65625b51463e49545e66696c6c6c6c6c6c6c6c6c6c6c6c6962584d41434f5960636c6c6c6c6c6c6c6c6c6c6c6c65625b51463a2e221609000713202c38444f5960636c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c66635c52473b2f23170a0000000000000000000000000000000009121b242d343c43474e53555a555d60605c545954524c443f38302920170e0a141d262d333e424a515358545c6060605b5356535049413d352e261c140a0000000000000000000000000000000000020e1b27333f4b5660676b6c6c6c6c6c6c6c6c6c6c6c6c5e574d42362a1e1205000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3b4854606b6f797979797979797979797979726d62574a414e5a66707679797979797979797979797974695d51444854606b6f797979797979797979797979726d62574a3e3125180b000916222f3c4854606b70797979797979797979797979797979797979797979797979797979797979797979797979797979797979797979797979736e63574b3f3226190c00000000000000000000000000000007101b242d363f464e53585f62676a676d6d666965605d56504a423a32292016111b262f383f4450545c606468666d6d6c656763605b534f4740382e261c11080000000000000000000000000000000004111d2a37434f5c677277797979797979797979797976695e52463a2d20140700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7d8686868686868686868686867f7265594c43505c697682868686868686868686868686796c5f52464956636f7d8686868686868686868686867f7265594c3f3226190c000a1723303d4a5663707d868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686807366594d4033261a0d0000000000000000000000000000040e19222d363f4850585f626a6f7377797a797876726d68605c544c443a32281e17222d384149505a61666d717578797a797774706c656059524a40382e241a0c0300000000000000000000000000000005111e2b3844515e6b778486868686868686868686867b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c89939393939393939393938c7f7265594c43505c6976838f9393939393939393939285796c5f52464956636f7c89939393939393939393938c7f7265594c3f3226190c000a1723303d4a5663707d89939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393938c807366594d4033261a0d00000000000000000000000000000a15202b343f48505a626a6f767c808386878685827f7a736d665e564c443a30251f27333f49535b606c70797e828586878684817c78706b635c524a40362c1e150b00000000000000000000000000000005111e2b3844515e6b778491939393939393939393877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c89969f9f9f9f9f9f9f9f988c7f7265594c43505c6976838f9c9f9f9f9f9f9f9f9f9285796c5f52464956636f7c89969f9f9f9f9f9f9f9f988c7f7265594c3f3226190c000a1723303d4a5663707d89969898989898989898989898989898989898989898989898989898989898989898989898989898989898989898988c807366594d4033261a0d00000000000000000000000000030f1b27323c46505a626c717c82888d90929897928f8c857f786d685e564c41362a27313944505b656c747d848b8f91939992918d89837d736e645c52483e30271d1207000000000000000000000000000005111e2b3844515e6b7784919e9f9f9f9f9f9f9f94877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8996a2acacacacacaca5988c7f7265594c43505c6976838f9ca9acacacacacac9f9285796c5f52464956636f7c8996a2acacacacacaca5988c7f7265594c3f3226190c000a1723303d4a5663707d898b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b8b807366594d4033261a0d0000000000000000000000000006131f2b37434e58626d717e868f949a9d9fa3a29f9c98928c837a6d685e52463e332f3943505a606c77808a91969b9e9fa39f9d9a95908880736e645a5042392e23180c000000000000000000000000000005111e2b3844515e6b7784919eaaacacacacaca194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8996a2afb9b9b9b9b2a5988c7f7265594c43505c6976838f9ca9b6b9b9b9b8ac9f9285796c5f52464956636f7c8996a2afb9b9b9b9b2a5988c7f7265594c3f3226190c000814212e3b4754616e7b7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7c6f6256493c2f231609000000000000000000000000000815222e3b4754606a717f8b92989fa6aaacaeadabaaa29f9590837a6d615a50443935404b55616c74808d929ea1a8abacafacaaa7a09a938d80736c61544b4034281c10040000000000000000000000000005111e2b3844515e6b7784919eaab7b9b9b9aea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8996a2afbcc6c6bfb2a5988c7f7265594c43505c6976838f9ca9b6c2c6c5b8ac9f9285796c5f52464956636f7c8996a2afbcc6c6bfb2a5988c7f7265594c3f3226190c000714202d3a46525e696e7272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272726f6a6054473b2e22150800000000000000000000000006131f2b38434e58626f7c87929fa3aab0b6b9babab8b4aea79f958f82756c6155493b3845515d67717e8a929da4adb2b8b9bbb9b7b1aca49f928a7d70665c5145382c1f13060000000000000000000000000005111e2b3844515e6b7784919eaab7c4c6baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8996a2afbcbebebeb2a5988c7f7265594c43505c6976838f9ca9b6bebebeb8ac9f9285796c5f52464956636f7c8996a2afbcbebebeb2a5988c7f7265594c3f3226190c0005111e2a36424d575e616565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656260584e43372b1f13060000000000000000000000000815222e3b4754606a76839099a3aeb4bcc2c5c7c6c5bebab1a79e938a7d7064564c413a4753606d7985929ea4aeb9bdc4c6c7c5c3beb6afa49e9184796d6053463a2e23170c0000000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8996a2afb2b2b2b2b2a5988c7f7265594c43505c6976838f9ca9b2b2b2b2b2ac9f9285796c5f52464956636f7c8996a2afb2b2b2b2b2a5988c7f7265594c3f3226190c00020e1a25303b454d525458585858585858585858585858585858585858585858585858585858585858585858585858585858585858585858585856544e463d32271b0f030000000000000000000000000916232f3c4956626f7c89949fabb5bfc6cfd2d3d3d0cac2b9b0a69c908376685e52463f4a5465717e8b97a1adb6c0c9cfd2d3d2d0c7c0b9aca1968a7e7164544a3f34281c100300000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c8996a2a5a5a5a5a5a5a5988c7f7265594c43505c6976838f9ca5a5a5a5a5a5a59f9285796c5f52464956636f7c8996a2a5a5a5a5a5a5a5988c7f7265594c3f3226190c000009141f29333b4246474b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4947433d342b20150a00000000000000000000000004101d2935404b556774808d9aa6b0bdc6d1d8dfe0dfdbd6cbc1b7ab9f94877a6e61544744505b6676828f9ca9b3bec8d5dadfe0dfd9d2c9bdb2a89c8f8275665c5044382c1f120600000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7c89969898989898989898988c7f7265594c43505c6976838f9898989898989898989285796c5f52464956636f7c89969898989898989898988c7f7265594c3f3226190c0000020d17202930363a3b3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3c3b37322b22190f0400000000000000000000000006131f2c3845515d677784909daab7c2cfd8e2eaecece7ddd3c7bbb0a6968a7d7063574a4653606c7985929fabb8c5cfdee5ecedebe4dacec4b8ab9f9285796d6053463a2d20130700000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7d898b8b8b8b8b8b8b8b8b8b8b7f7265594c43505c6976828b8b8b8b8b8b8b8b8b8b8b86796c5f52464956636f7c898b8b8b8b8b8b8b8b8b8b8b7f7265594c3f3226190c000000050e171f252a2d2e3232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232322f2e2b2720191007000000000000000000000000000714202d3a4753606d7a86939facb9c6d2dfeaf4f9f8efe4d8cdbfb2a5988c7f7265594c4855616e7b8898a2aebac6d3dfecf6f9f5ebdfd3c6baaea298887b6f6255483c2f22150900000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3b4754616e7b7f7f7f7f7f7f7f7f7f7f7f7f7c6f6255493d4a5764707e7f7f7f7f7f7f7f7f7f7f7f7f7265584b3f4754616e7b7f7f7f7f7f7f7f7f7f7f7f7f7c6f6255493c2f22160900000000050d141a1e202125252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252523221f1b150f0700000000000000000000000000000916232f3c4956626f7c8999a4afbbc7d4e0edfcfffff5e6dacdc0b3a79a8d8074675a4d4a5663707d8996aab3becad6e2eefbfffbeee2d6cabeb4aa978b7e7164584b3e3125180900000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714202d3a46525e696e7272727272727272727272726f6a5f54473c4955616c707272727272727272727272726d62564a3d46525e696e7272727272727272727272726f6a5f54473b2e221508000000000002090e1114141818181818181818181818181818181818181818181818181818181818181818181818181818181818181818181818181615130f0a040000000000000000000000000000000b1825323e4b5865717e8b98abb5c0ccd7e3f0faf8f8f5e8dbcec2b5a89b8f8275685c4f4b5865727e8b98a5b1bed0dbe6f2f8f8f9f2e7dbd0c0b3a69a8d8073675a4d4030251a0e02000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e2115080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36424d565e61656565656565656565656565625f584e433944505a6164656565656565656565656565625b51463a424d565e61656565656565656565656565625f584e43372b1f130600000000000000020507080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0908060300000000000000000000000000000000010e1b2734414e5a6774818d9aa7b4c0d2dde8f2eeecebece9ddd0c3b6aa9d9083776a554b4d5a6774808d9aa7b3c0cddae6ececebeceee9dccfc2b6a99c8f827669574d42362a1e1105000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1925303b444d525458585858585858585858585855544e463c333e485055575858585858585858585858585651493f343b444d525458585858585858585858585855544e463c32261b0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d57697683909ca9b6c3cfdce9e6e2dfdedfe2ded1c4b8ab9e918578675c514a546975828f9ca8b5c2cfdbe3e0dfdedfe2e6ded1c5b8ab9e928578695e52463a2d201407000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f29323b4246474c4c4c4c4c4c4c4c4c4c4c4c4947433c342c363e44494a4c4c4c4c4c4c4c4c4c4c4c4b4a463f372d323b4246474c4c4c4c4c4c4c4c4c4c4c4c4947433c342a20150a0000000000000000000000000000000406070a0e1012121313131313131313131313131313131313131313131313131313130a09070400000000000000000000000000000000000000000000000000000714212d3a46535e697885929fabb8c5d2dee1dad5d2d1d2d5dad2c6b9ac9f9386796d6053505b667784919daab7c4d0dcd7d3d2d2d3d6dbdfd2c6b9ada197877b6e6154473b2e211408000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e2115080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d17202930363a3b3f3f3f3f3f3f3f3f3f3f3f3f3c3b37322a242c33393c3d3f3f3f3f3f3f3f3f3f3f3f3f3d3a342d252930363a3b3f3f3f3f3f3f3f3f3f3f3f3f3c3b37322a22190e0400000000000000000000000000070c101213171a1d1e1f202020202020202020202020202020202020202020202020202020171614100b050000000000000000000000000000000000000000000000000815212e3b4854616e7b8797a2adbac6d3dfd6cfc9c6c5c6c9cfd4c8bbafa49a887b6e615553606c7986929facb9c5d2d1cbc7c5c5c6cad0d7d5c9beb3a9968a7d7063574a3d30241707000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050e171f252a2d2e3232323232323232323232322f2e2b26201a22282d3031323232323232323232323232312e29231b1f252a2d2e3232323232323232323232322f2e2b2620191007000000000000000000000000060b12181c1f202427292b2c2c2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2423201c16100800000000000000000000000000000000000000000000000a1724313d4a5764707d8a97a9b3becad6d6cdc5beb9b8b9bec5cdccc0b6ac96897c70635654616e7b8799a3aebac7cfc6bfbab9b8babec5ced7cfbfb2a5998c7f7266594c3f2f24180c000000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050d14191e202125252525252525252525252522221f1b1510171c20232425252525252525252525252524221d181114191e202125252525252525252525252522221f1b150e070000000000000000000000020a11171c23282c2d3034363839393939393939393939393939393939393939393939393939393939302f2c28211a1108000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfd0d8cfc5bbb3adabadb3bbc5cfbdb1a4978a7e7164575663707d8996abb4bfcbc6bdb4aeacabadb3bcc5d0cec1b5a89b8e827568554b4035291d10040000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002090e1114141919191919191919191919191615130f0a050b101416171919191919191919191919181815120c06090e1114141919191919191919191919191615130f0a040000000000000000000000040b141b22272e34383a3d414345454646464646464646464646464646464646464646464646464646463d3c38332c231a1005000000000000000000000000000000000000000004111d2935404b556875828f9ba8b5c2ced1c6bdb3a9a19ea1a9b3bec9bfb2a5998c7f7266595865727e8b98a5b1becbbfb4aba39f9fa2a9b3becad0c4b7aa9d918477675d5145392c1f13060000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020507080c0c0c0c0c0c0c0c0c0c0c0c0908060300000004080a0a0c0c0c0c0c0c0c0c0c0c0c0c0b0906010000020507080c0c0c0c0c0c0c0c0c0c0c0c09080603000000000000000000000000040d161d262d33394044464a4d5051525353535353535353535353535353535353535353535353535353534a48443e352c21160b00000000000000000000000000000000000000000613202c3945515d677784919eaab7c4d1cbbfb5aba1979297a1adb9c6c0b4a79a8d8174675a5a6773808d9aa6b3c0c7baaea399929297a2adbac6d2c6b9ac9f93867a6d6053473a2d2014070000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e2115080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d161f282f383f444a5153575a5c5e5f5f606060606060606060606060606060606060606060606060606057554f473e33281c1004000000000000000000000000000000000000000714202d3a4753606d7a86939facb9c6d2c7bbaea3999285929eabb8c5c2b5a89c8f8275695c546975828f9ca8b5c2c5b9ac9f928785929fabb8c5d2c7bbafa499897c6f6256493c2f2316060000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e2115080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105090b0c1313131313131313131313131313131313131313131313131313131211100d09070603000000000000000000000000000000000000000000000000000000000000000000000000010c161f28313a414950545c606367696b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6361594f44382c20140700000000000000000000000000000000000000091623303c4956636f7c899aa4afbbc8d2c5b9ac9f9287818e9ba7b4c1c3b6aa9d9083776a555b667784919daab7c4c4b7aa9e918482909ca9b6c3cfccc0b5ab988b7e7165584b3e2d22170b0000000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e2115080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c111518182020202020202020202020202020202020202020202020202020201f1e1c19161312100b060000000000000000000000000000000000000000000000000000000000000000000007131d28313a434c535b60666d7074767878797979797979797979797979797979797979797979797979797979706b6155483c2f231609000000000000000000000000000000000000000c1825323f4b5865727e8b98acb6c0ccd0c3b7aa9d90837f8c99a5b2bfc5b8ab9e928578675d606c7985929facb8c5c2b5a99c8f82808d9aa7b3c0d1d2c0b4a79a8d81746753493f33271b0f0300000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000911181d2224252d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c2c2b292623201f1c17110c0700000000000000000000000000000000000000000000000000000000000000010d18242f3a434c565d656c71797d808384858686868686868686868686868686868686868686868686868686867d7063574a3d3024170a000000000000000000000000000000000000030f1b27333f49536774818d9aa7b4c0d2cec1b4a79b8e817e8a97a4b1bdc6b9ada197867a6d60616e7b8798a3aebac7c1b4a79a8e817e8b98abb5c0cbcfc3b6a99c908376655b5044372b1f120500000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b23292e313239393939393939393939393939393939393939393939393939393938373633302d2b28231c18120b03000000000000000000000000000000000000000000000000000000000004111d2935414b555d686d777e848a8d8f919292999393939393939393939393939393939393939393939393938a7d7063574a3d3024170a00000000000000000000000000000000000005121f2b3744505b657683909da9b6c3d0cbbfb2a5988c7f7c8995aab4bfcabeb3a995887b6e6263707c8996aab4bfcbbfb2a5998c7f7c8899a3afbbc7d2c5b8ac9f9285796c605346392d20130600000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111b242d343a3d3f464646464646464646464646464646464646464646464646464646454443403c3a38342e28231d150c06000000000000000000000000000000000000000000000000000000030e18222c3945515d676d7a828b91969a9c9e9f9fa39f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f968a7d7063574a3d3024170a0000000000000000000000000000000000000613202d394653606c7985929facb8c5d2c9bdb2a896897d7a8798a2aebac6bcafa396897c706365727e8b98a5b1bed0bdb1a4978a7e7986929facb9c5d2c6baaea298887b6e6155483b2e22150800000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c18232d373f454a4b53535353535353535353535353535353535353535353535353535352514f4c4946443f38342e271e180f0700000000000000000000000000000000000000000000000000000a15202d3944505a606d79838f949ea1a9a9ababacafb5acacacacacacacacacacacacacacacacacacacacaca3968a7d7063574a3d3024170a0000000000000000000000000000000000000815222e3b4855616e7b8898a2aebac6d2c5b9ada196877a7985929facb8c5beb1a4978b7e71646773808d9aa6b3c0cabfb4aa95897c7784909daab7c3d0cabfb4aa978a7d7164574a3e3124170800000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e2115080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111d29343f4951565860606060606060606060606060606060606060606060606060605f5f5e5c595653504a454039302a21191107000000000000000000000000000000000000000000000000030f1b26313c4955616c75828f959fa6adb2b6b7b8b9bbc0b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b0a3968a7d7063574a3d3024170a0000000000000000000000000000000000000b1724313e4a5764717d8a97aab4bfcad1c4b8ab9e9184787784909daab7c3bfb2a6998c7f73666875828f9ba8b5c2c6baaea298877a75818e9ba8b4c1ced0bfb3a6998c807366594d403024190d01000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222e3a45515b62656c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6b6a696663605c54514b433c332b23190f06000000000000000000000000000000000000000000000006121f2b37434e5864707d8a939ea7b0b9bdc2c4c5c5c7cbd1c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6bdb0a3968a7d7063574a3d3024170a0000000000000000000000000000000000000d1a2633404d596673808c99a6b3bfd0cfc2b5a89c8f827575828f9ca8b5c2c1b4a79a8e817467657784909daab7c3c5b8ac9f928579727f8c98a5b2bfcfcfc2b5a89c8f827569564c4135291d1104000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313d4a56626d72797979797979797979797979797979797979797979797979797979787776736f6d66605c554d453d352b21180c03000000000000000000000000000000000000000000000815212e3a47535f6a7783909da5afb9c2c9cfd1d1cbc7c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000004111d2935414c566875828f9ba8b5c2ceccc0b3a6998d807374808d9aa7b3c0c2b5a89c8f8275696c7985929facb8c5c4b7aa9d918477707d8996a9b3bec9d1c4b7ab9e918478685d5245392c201307000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727f8686868686868686868686868686868686868686868686868686868584827f7c78716d675f574f473d332a1e150b000000000000000000000000000000000000000000000915222f3c4855626f7c88959fabb8c1cbd5d0cac7c0bbb9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b0a3968a7d7063574a3d3024170a00000000000000000000000000000000000613202c3945525d687884919eabb7c4d1cabfb4aa978a7d71727f8b98a5b2bec3b7aa9d9084776a6e7b8798a2aebac7c2b5a89c8f82756d7a8797a1adb9c6d2c5b9aca196877a6d6054473a2d211407000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b939393939393939393939393939393939393939393939393999292918f8c89847e796e6960594f453c30271c12070000000000000000000000000000000000000000000c1926323f4c5965727f8c98a7b1bccad3cec6bfbab5afacacacacacacacacacacacacacacacacacacacacacaca3968a7d7063574a3d3024170a00000000000000000000000000000000000714212d3a4754606d7a8796a1acb9c5d2c6baaea298887b6e707d8a97a3b0bdc5b8ab9f92857867707c8996aab4bfcac0b4a79a8d8174687885919eabb8c4d1c9bdb2a896897c706356493d30231606000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b989f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9fa39f9e9d9c9996918b837b706b60574d42392e23180c0000000000000000000000000000000000000000000e1b2835414e5b6874818e9ba7b4c1cdd0c6bcb4aeaba39f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f968a7d7063574a3d3024170a0000000000000000000000000000000000091623303c4956636f7c8996a8b2bdc9d2c5b8ac9f9285796c6f7b8895a9b3bec6baada297877a6d717e8b98a4b1bed0bfb2a5988c7f726976828f9ca9b5c2cfcebeb2a5988b7f7265584c3f2e23170c000000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5acacacacacacacacacacacacacacacacacacacacacb5afacabaaa9a8a09e9590867d70695f544a4034281c11060000000000000000000000000000000000000000101d2a3643505d697683909ca9b6c3cfcabfb4aaa29f999292929292929292929292929292929292929292929292928a7d7063574a3d3024170a00000000000000000000000000000000000c1925323f4c5865727f8b98a5b2beced0c3b6a99d908376666d7a8697a1adb9c6beb3a995887b6e73808d9aa6b3c0cabdb0a4978a7d716673808d99a6b3c0d0cec1b4a79b8e817468544a3f34281c10030000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9c0bbb9b8b7b5b2aca7a09892857b6e665c5144382e23170b0000000000000000000000000000000000000000111e2a3744515d6a7784909daab7c3d0c6baaea298928a868686868686868686868686868686868686868686868686867d7063574a3d3024170a0000000000000000000000000000000003101c28343f4a546774818e9aa7b4c1cdcdc0b4a79a8d817467677885929eabb8c5bcb0a396897d7075828f9ba8b5c2cabeb3aa95887c6f64717e8a97aab4bfcad0c3b6aa9d908377665c5044382c1f12060000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1bec6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6d1cbc7c5c5c4c2bdb9b1aaa2979184786d60544a3f34281c100300000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c5b8ac9f92867e79797979797979797979797979797979797979797979797979706b6155483c2f2316090000000000000000000000000000000006121f2b3844505c667783909daab6c3d0ccc0b5ab988b7e72656a7683909da9b6c3beb1a4988b7e717784909daab7c3c6baaea298877a6d626e7b8898a2aebac7d2c5b9ac9f9286796d6053463a2d2013070000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1becbd2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2dcd7d3d2d1d0cec8c3bcb3a9a0968b7e71665c5044382b1f120600000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4cdc0b4a79a8d81746d666c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6361594f44382c201407000000000000000000000000000000000713202d3a4653606d7985929facb8c5d2c7bbafa499897c6f626875818e9ba8b4c1bfb3a6998c80737985929facb8c5c5b8ab9f92857868606d7985929facb8c5d2c7baaea399887b6f6255483c2f2215090000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1becbcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcfd2d3d7dcddd9d4cec5bbb2a89e9184786d6053463a2d20130700000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4cabeb1a4978b7e71645e565f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f57554f473e33281c1004000000000000000000000000000000000815222f3b4855626e7b8898a2aebac7d2c6b9ac9f93867a6d606673808d99a6b3c0c1b4a79a8e81747b8798a2aebac6c3b7aa9d9084776a5c667683909da9b6c3d0cbbfb4ab978a7e7164574b3e312418090000000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1bec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c2c5c7cbd1d9e1e0d7cdc3b9aca196897c6f6256493c2f23160900000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c9bdb0a3968a7d726d6863605c54534e53535353535353535353535353535353534a48443e352c21160b00000000000000000000000000000000000b1824313e4b5764717e8a97aab4bfcad1c4b7aa9e918477675d65717e8b98a4b1bec2b5a99c8f82767c8996aab4bfcac2b5a89b8f827568546774818e9aa7b4c1d2d1c0b3a69a8d8073675a4d403025190e0200000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5b1b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b5b9bbc0c7cfd5dddfd5c9bdb2a8998c7f7266594c3f3326190c00000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d0c3b7aa9d90837f7a75706d66625f5854524c46443f46464646464646464646463d3c38332c231a100500000000000000000000000000000000000d1a2733404d5a6673808d99a6b3c0d0cec1b5a89b8e8275685563707c8996abb5c0c4b7aa9d9184777e8b98a4b1bed0c0b3a79a8d8074675a65727e8b98acb6c0cccfc2b5a99c8f827669564d42362a1e110500000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b98a5a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a8acafb5bdc3cbd5e1dacec2b5a89b8f8275685c4f4235291c0f00000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c5b8aca095908b86827d79736e6a65605d5653504946423b39352f3939393939302f2c28211a1108000000000000000000000000000000000005111d2935414c566975828f9ca8b5c2cfccbfb2a6998c7f736659616e7b8899a3afbbc5b8ac9f928579808d99a6b3c0cbbeb2a5988b7f726558636f7c899aa4afbbc8d1c5b8ab9e928578695e52463a2d20140700000000000005111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b989a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9c9fa3abb1b9c3cfd8dcd0c3b6a99d9083766a5d5043372a1d1000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c8bcb1a7a09d99928f8a85807b76726d6863605b53534d4745403938322d2a252423201c1610080000000000000000000000000000000000000713202d3946525e687884919eabb8c4d1cabeb3a9968a7d706357606d7986929facb9c5baaea298877a828e9ba8b5c1cabdb0a3978a7d706457606d7a86939facb9c6d2c6b9ada197877a6e6154473b2e21140800000000000005111e2b3844515e6b7784919eaab7bcbcbaaea194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1825323f4b5865727e8b8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8f9299a0a7b1bdc6d1dcd1c4b7aa9e9184776b5e5144382b1e1100000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1cec3b9b1acaba39f9b97918d88837e7a75706c65615f5753514b48433d3a36302c28231d150c070000000000000000000000000000000000000714212e3a4754616d7a8796a1adb9c5d2c6b9ada197877b6e61545c667884919eabb7c4bfb4aa95887c83909daab7c3cabeb3a995887b6f62555d677784919eaab7c4d1c9beb3a9968a7d7063574a3d3024170700000000000005111e2b3844515e6b7784919eaaafafafafaea194877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091623303c4956636f7d818181818181818181818181818181818181818181818182879095a0abb5bfcbd7d1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1d5cbc3bcb8b4aeaca9a19e9a95908b86817d78736e6964605d55544f4746423b38342e271e19110700000000000000000000000000000000000a1623303d495663707c8996a8b2bdc9d1c5b8ab9e928578695e52546976838f9ca9b6c2bdb0a3968a7d85929facb8c5c6b9ada197877a6d6054556875828f9ba8b5c2cecfbfb2a5998c7f7266594c3f2f24180c00000000000005111e2b3844515e6b7784919ea3a3a3a3a3a3a194877b6e6154483b2e211508000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915222f3b4854606b6f7474747474747474747474747474747474747474747474757b839099a3aebbc7d3d1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1ddd5cec8c6bfbab9b3adaba79f9d98928e8984807b76716d6763605954524d46454039302b23190f05000000000000000000000000000000000c1926323f4c5965727f8c98a5b2bfcfcfc2b6a99c8f837669574d5b6774818e9aa7b4c1bfb3a6998c808c98a2aebac6c5b8ab9e928578675d515966737f8c99a6b2bfcfcec1b5a89b8e827568554b4035291d1004000000000005111e2b3844515e6b778491969696969696969694877b6e6154483b2e2115080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007131f2c38444f5960636767676767676767676767676767676767676767676767696e7b86929facb9c5d2d1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1d6cdc4beb9b8b9bebeb9b8b1abaaa29f9b96918c87837e79746f6b66615e5753514b433d352b21160b00000000000000000000000000000003101c28343f4a546874818e9ba7b4c1cecdc0b3a69a8d8073675a4d5966737f8c99a6b2bfc3b6a99c9083909caab4bfcac3b6aa9d9083776a554b5764707d8a97a9b3becad0c4b7aa9d918477675d5145382c1f1306000000000005111e2b3844515e6b778489898989898989898989877b6e6154483b2e21150800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27323d474f54565a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a575f697683909ca9b6c3cfd1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1cfc4bbb3adabadb3b8babebcb8b4aeaca8a19e9a938f8b85817c77726e6964605c554f473d33271c1004000000000000000000000000000006121f2c3844505c667783909daab6c3d0cbbfb4ab978b7e7164584b5764717e8a97a4b1bdc5b9ac9f9286929facb9c5d0c1b5a89b8e8275685b4f54616e7b8797a2adbac6d2c6b9ac9f93867a6d6053473a2d2014070000000000000916232f3c4956626f7c7c7c7c7c7c7c7c7c7c7c7d796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a16212b353d4448494e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4d576875828f9ba8b5c2ced1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c9beb3a9a19ea1a9abaeb3b9bbbfbab8b2acaca49f9c98928e89847f7b76716d6760594f44382c20130700000000000000000000000000000713202d3a4653606d7986929facb9c5d2c7baaea399887b6f62554956626f7c8995aab4bfc7baaea3999299a3aebac7cdc0b3a69a8d8073675a4d535e697885929fabb8c5d2c7bbafa499897c6f6256493c2f2316060000000000000815222e3b4754606a6f70707070707070707070706d675c5145382c1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040f19232b32383b3c414141414141414141414141414141414141414141424f5b6875828e9ba8b5c1ced1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c6b9ada19791979a9fa2aaacafb5b8bcbdb9b6afacaaa29f9a96918c86827e79706b6054483b2f22160900000000000000000000000000000915222f3c4855626f7b8899a3aebac7d2c5b9ac9f9286796d60534754616e7a8798a2aebac6bfb4aba39fa3abb4bfcbcbbeb1a5988b7e7265584b4d576976838f9ca9b6c2cfccc0b5ab988b7e7165584b3e2d22170b00000000000006131f2b37434e5860626363636363636363636363605c554b4034281c100400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007111921272c2f30343434343434342f35393a3b3b3b3b3b3b3b3b3b3b424f5b6875828e9ba8b5c1ced1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c4b8ab9e9185898e92989c9fa4abacb1b8b9bebbb9b4aeaba8a09d99928f8a857d706356493d3023160a00000000000000000000000000000b1824313e4b5764717e8a97abb4bfcbd0c3b7aa9d908377665c5146525e687985929facb8c5c6bdb4aeacaeb4bdc6d1ccc0b6ac968a7d7063574a4d5a6774808d9aa7b3c0d1d2c0b4a79a8d81746753493f33271b0f030000000000030f1b27323d464e54565e6166696a6a6966615e5653514b43392e23180c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070f161b1f22232722282f34383a3e41454748484848484848484848484f5b6875828e9ba8b5c1ced1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b7c81858a8f93999da0a7abadb3b9babebab8b2acaba39f9c978b7e7164584b3e3125180b00000000000000000000000000010d1a2734404d5a6773808d9aa6b3c0d1cec1b4a79b8e817468544a414c566a7784909daab7c3cfc6bfbab9babfc6cfd4c8bbafa49a887b6e6255484b5864717e8b97abb5c0cbcfc3b6a99c908376655b5044372b1f120500000000000a15202a343f49515a61686d7276777776726d68625b524a40362c1e140a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f13161d262d33394045474b4c5154545555555555555555555555586875828e9ba8b5c1ced1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b7074797e82878c90959a9ea1a9acaeb4bcc3bdb8b5afaca9978b7e7164584b3e3125180b0000000000000000000000000005111e2a36414c566976828f9ca9b5c2cfcbbfb2a5988c7f7265594c424f5c6975828f9ca8b5c2cfd1cbc7c5c7cbd1d8d2c6b9ac9f93867a6d6053474955626f7c8899a3afbbc7d2c5b8ab9f9285796c605346392d20130600000000030f1b26323c46515b626c717a7f828484827f7a726d635c52483e30261c1106000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d1620282f383f444b515358555d60616262626262626262626262626a7683909da9b6c3d0d1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e676d71767b7f84888d92979b9fa3aab1bac3c7c0bbb1a4978b7e7164584b3e3125180b000000000000000000000000000714202d3946525e687885919eabb8c4d1c9bdb2a896897c70635649414d5a6774808d9aa7b3c0cddcd7d3d2d3d7dcded1c4b8ab9e918578675c51454653606d7986929facb9c5d2c6baaea298887b6e6155483b2e2215080000000006131f2b37434e58626d727e858c8f91918f8c867f736e635a5042382e23170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b161f28323a424a50555c606468676d6e6e6e6e6e6e6e6e6e6e6e6e6f727c87929facb9c5d2d1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e616064696e72777c80858a8e9298a0a8b1bdc8cbbeb1a4978b7e7164584b3e3125180b000000000000000000000000000814212e3b4754616e7a8797a1adb9c6d2c5b9ada196877a6d6154473f4c5865727f8b98a5b2bed0dbe3e0dfe0e3e7dcd0c3b6a99d9083766a554b4045515c677784909daab7c3d0cabeb4aa978a7d7064574a3d31241708000000000815212e3b47535f6a727f8a92989c9d9d9c98928b80736c61544a3f34281c1003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a141d28313a444c545b60676d7175787a7b7b7b7b7b7b7b7b7b7b7b7b7c7f859299a3afbbc7d3d1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6156565e61656a6f74797d82869195a0acb8c5cabeb1a4978b7e7164584b3e3125180b000000000000000000000000000a1723303d4a5663707d8996a9b3bec9d1c4b7ab9e918478685d52463d4a5764707d8a97a9b3becad6e2ecececefe7dbcec1b4a89b8e8175685b4e42404b556875818e9ba8b4c1ced0bfb3a6998c807366594d402f24190d01000005111d2a36414c56626f7c87929fa2aaaaaaaaa29f928a7e71665c5044382b1f120600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006111c262f3a434c565d666c72797e828587878888888888888888888888888c9297a2abb5c0cbd7d1c5b8ab9e9285786b5f5245382c1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c9bcafa396897d706865646464646464666d70757a84919daab7c4cabeb1a4978b7e7164584b3e3125180b000000000000000000000000000c1926323f4c5965727f8c98a5b2bfcfcfc2b5a89c8f827569564c413b4855616e7b8897a2adbac6d3dfeaf5f7efe3d7cbbfb5ab998c7f7366594c403f4c5965727f8c98a5b2bfcfcec2b5a89b8f827568564c4135291d110400000713202d3946525e6875828f99a3aeb3b7b7b4aea49e9184786d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b17222d38424c565d686d787e858b8f919794959595959595959595959595989ea2a9b3bdc7d1dcd1c4b8ab9e9185786b5e5245382b1f1200000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d0c3b7aa9d90837a7371717171717171717171747c86929facb9c5cabeb1a4978b7e7164584b3e3125180b00000000000000000000000004101c2834404b556875818e9ba8b4c1ceccbfb3a6998c807366594d403a46535f697885929fabb8c2cfd9e3ebebe6ded3c7bbaea3998a7d7063574a3d3d4a5663707d8996a9b2bdc9d1c4b7ab9e918478685d5245392c20130700000714212e3a4754616d7a86929fabb5bec4c4bfb9aca196897c6f6356493c302316090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1c28333f4a545d686d7a828b92979b9ea1a9a1a1a1a1a1a1a1a1a1a1a1a2a5abadb3bbc5cfd9ddd0c3b7aa9d9084776a5d5144372a1e1100000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c5b8aca0959085807e7e7e7e7e7e7e7e7e7e81869299a3aebbc7cabeb1a4978b7e7164584b3e3125180b00000000000000000000000006131f2c3845515c677784909daab7c3d0cabfb4aa978a7d7164574a3e36424d576875818e9ba7b1bdc7d1dadededbd6ccc3b9ac9f92867a6d6054473a3a4754616d7a8796a1adb9c5d2c5b9aca196877a6d6054473a2d21140700000a1723303d4a5663707d8999a3afbdc7d0d0c9bdb2a8988c7f7265594c3f3226190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b3844505b666d7a838f949ea1a9abadb3aeaeaeaeaeaeaeaeaeaeaeafb2b8b9bec5cdd7e1dbcec1b5a89b8e8275685b4f4235281c0f00000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c8bcb1a7a097928d8b8a8a8a8a8a8a8a8a8b8d9298a2abb5bfcbcabeb1a4978b7e7164584b3e3125180b0000000000000000000000000713202d3a4653606d7986929facb9c5c6c6baaea298887b6e6155483b313d4a5663707d89959fabb5c0c9ced2d2cfcac2baafa59b8f8275675d5145393946525e687885919eabb8c4c6c9bdb2a896897c706356493d3023160600000b1825313e4b5864717e8b97abb5c0cfd9dacec0b3a6998d8073665a4d4033271a0d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005111e2a36414c56606c78828f959fa6adb3b8b9bebbbbbbbbbbbbbbbbbbbbbbbbbfc5c6cacfd7dfdfd4c8bcb1a7988b7f7265584c3f3225190c00000000000000000000000000000000000000111e2b3744515e6a7784919daab7c4d0cec3b9b1a9a19e9a989797979797979797979a9fa2aab4bdc6d1cabdb1a4978a7e7164574b3e3124180b0000000000000000000000000916222f3c4955626f7c8899a3afbbb9b9b9b8ac9f9285796c605346392d3c4855606b76839099a3afb9bdc4c5c5c4beb9b1a89e93897c6f63554b413536414c566975828f9ca8b5b9b9b9b9b2a5988b7f7265584c3f2e23170c00000b1724313e4a5764717e8a97a8b2bdc8d1d2c9beb3a9988c7f7265594c3f3226190c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713202d3946525e68727f8c949fa7b0b9bec4c6c9cfc8c8c8c8c8c8c8c8c8c8c8cbd1d2d6dbe1dfd6cdc5b8ab9f95887b6e6255483b2f22150800000000000000000000000000000000000000101d2a3643505d697683909ca9b6c3d1d5cbc3bbb3adaba6a4a4a4a4a4a4a4a4a4a4a7acaeb4bcc6cfd6cabeb3a9978a7e7064574a3d3124170a0000000000000000000000000b1825313e4b5864717e8b97abb5acacacacaca99c908376655b5044372b38444f59626f7c87929fa3acb2b7b8b8b7b3ada79f958e81756b6054433a2f30404d5a6673808d99a6acacacacacaca79a8e817467544a3f34281c1003000915222f3c4855626f7c8896a0acb8c0c5c6c0b9ada197897d7063564a3d3023170a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030f1b27333f4953616d7a85929fa6b0b9c2c9cfd2d5dad4d4d4d4d4d4d4d4d4d4d5d8d8d8d8dad5d2cdc5bbb0a69d9083766a5f53473a2e211408000000000000000000000000000000000000000e1b2834414e5b6774818e9aaab4bfcbd7d5cdc5beb9b8b3b1b1b1b1b1b1b1b1b1b1b4b8babfc6ced8d3c6baada297887b6e6255483b2f2215080000000000000000000000010e1a2734414d5a6774808d9a9f9f9f9f9f9f9f9f9a8d81746753493f3327333d4754606a727f8b919ea1a8aaababaaa9a29e9590837a6d60594f443128313e4a5764717d8a979f9f9f9f9f9f9f9f9d908377665c5044382c1f1206000613202d394653606c7884919ea4afb5b9b9b5afa59e9185796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121f2b3744505b6573808c98a2aeb8c2cbd5dadfddd8d4d2cfcccbcbcbcbcbcbcbcbcbcbcbcfc9c6c1bbb3a99f948a7e7164574e42372b1e1206000000000000000000000000000000000000000b1724313e4a5764717d8a98a3aebac5d0d9d6cfc9c6c5c0bebdbdbdbdbdbdbdbdbec0c5c6cad0d8d7cec5b8ab9f9285776c605346392d201306000000000000000000000003101d293643505c6976838f939393939393939393938b7e7165584b3e2d222b37434e58626d737f8a91969b9d9f9f9d9b97928c837a6e685d52473d32222f3b4855626e7b88989393939393939393939286796d6053463a2d2013070005121f2b3744505b65717e8a929fa3abacacaba49f938b7e71665c5145382c1f13060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613202d394653606c7884919eaab3becad4dde2d9d2ccc8c6c2c0bebebebebebebebebebebebdbeb9b8afa9a1979082786c6053463c31261a0e02000000000000000000000000000000000000000714212d3a4754606d7a86929faab4bfc7d0d2d5d5d2d1cdcbcacacacacacacacacacdd2d3d6d5d2cec6bcb0a69b8e8175655b5044372b1f1205000000000000000000000005121f2c3845525f6b78858686868686868686868686867c6f6256493c2f2327323d46515b636d737e848a8e919292918e8a857f786e685e564c41352b202d394653606c78868686868686868686868686867c6f6255483c2f22150900030f1b27333f4953616c74808c92999e9f9f9e99938d81746c62544b4034281c10040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222f3b4855626e7b8896a1adbcc5d0dcdfd7d0c7c0bbb9b6b3b2b2b2b2b2b2b2b2b2b2b1b1b3adaba59e9792857b6e665b5044382a20150900000000000000000000000000000000000000000613202c3945525d6874818d98a2aeb6bec3c5c9cfc9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9cec9c5c2bcb4aa9f94897d706353493f33271b0f03000000000000000000000005111e2b3744505d6873787979797979797979797979796f6a6054473b2e22202b343f49515b636c70797e8284858584817e79726d665e564c433a2f231f2b3844505b667479797979797979797979797979766a5f53473a2e21150800000b17222d3841505a606c7780878e919293918e8780786c605a5042392e23180c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1824313e4b5764717e8a97a8b2bdced7e1d7cdc5beb6afaca9a6a5a5a5a5a5a5a5a5a5a5a5a4a9a19e9a938f857c6f695f544a3f3328180e03000000000000000000000000000000000000000004111d2935414c56616e7b86929fa4acb2b8b9bdbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbdb9b7b1aaa2989083786c605346392d22170b000000000000000000000000030f1c2834404c5761686b6c6c6c6c6c6c6c6c6c6c6c6c6260584e43372b1f19222d374049515a61676d71757778787774716d67605c544c443b31281e1c28333f4a545b606c6c6c6c6c6c6c6c6c6c6c6c6c6c5f584e43372b1f1206000006111b262f3e44505b656c737c8184868684817c736c665b50483f30271d1207000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1925323f4c5865727f8b98a5b2becfd8dbd0c5bbb3aca49f9c999898989898989898989898979697928e89827b6f6a5f574d42382d221706000000000000000000000000000000000000000000010d19242f3a46535e69717e8b939aa0a8abadb2afafafafafafafafafafafafafafafafafafb2acaba79f9892867c6f655b5044372b1b1106000000000000000000000000000c18242f3b454f575d5f60606060606060606060606056544e463d32271b101b252e37404850555c6064686a6c6c6a6864605d55514a423b32291f1617222d38424a50535f60606060606060606060606055534e463c31261a0f030000000a141d27333f49535b606a6f7478797978746f6a605b544a3f362d1e150b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd9d6cabeb3a9a29a938f8d8b8b8b8b8b8b8b8b8b8b8b8a8a8785817c756e695f584e453b2f261c11060000000000000000000000000000000000000000000008131e2a36424d57616c727f8891969b9ea1a9a2a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a2a8a19e9b9590867d706a5f53493f33271b0a000000000000000000000000000007131e29333d454c50525353535353535353535353534947433d342b20160a131c252e363e434b5153575b5e5f5f5e5b5753514b444039302920170d111c262f383f4446525353535353535353535353534847433c342a20150a00000000020b17222d38414950585f6267666c6d6668625f58504a42382d241b0c0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd9d3c6baada297928783807f7f7f7f7f7f7f7f7f7f7e7e7d7b78746f6a615e574e463c33291d140a0000000000000000000000000000000000000000000000010e1a25313b45505a626d727d848a8e9196959696969696969696969696969696969696959596918e89837c706b60584e41382d22170b0000000000000000000000000000020d17212b333b4044454646464646464646464646463c3b37322b22190f040a131c242c30394045464b4f515252514e4b47454039342e271e170e050a141d262d333839464646464646464646464646463c3a37312a22180e03000000000006111b262f383f444e5355545b60605c5455534e443f382f261c12090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd9d2c5b8ab9f92857c7673727272727272727272727271706e6967626058524d453c342a21180b0200000000000000000000000000000000000000000000000009141f29333e48515b626b70787d82858788898989898989898989898989898989898989888784817d766e6a60594f463c2f261b1106000000000000000000000000000000060f1921292f3437383939393939393939393939392f2e2b272019100700010a111a1e272e34383a3e4244454544413e3a39352f28231c150c0500020b141c22282b2d393939393939393939393939392f2e2b2620181006000000000000000a141d262d333c4347484a505353504a4947433c332d261d140a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd8cbbeb2a5988b7f726a6665656565656565656565656463615e5756544e46423b332a22180f0600000000000000000000000000000000000000000000000000030d17212d363f49515960666d7075787a7b7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7b7a7875706b625f584f473d342a1d140a0000000000000000000000000000000000070f171e24282b2c2d2d2d2d2d2d2d2d2d2d2d2d23221f1b160f0700000000080c151d23282c2d31353739393735312d2c29241d18120b03000000020a11171c1f202c2d2d2d2d2d2d2d2d2d2d2d2d22211f1a150e060000000000000000020b141b222731373a3c3f444646443f3c3b373228221c140b02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd4c8bbaea195887b6e62585858585858585858585858575754534d4947433d3630292018100e080100000000000000000000000000000000000000000000000000050f1b242d373f474f545c606468686d6e6f707070707070707070707070707070706f6e6d6868636059534e463d352b22180b02000000000000000000000000000000000000060d13181c1e1f2020202020202020202020201615130f0a04000000000000030b12181c1f2024282b2c2c2b282420201d18120c0700000000000000060b0f12131f2020202020202020202020201515120f0a0300000000000000000000020a111720262b2e2d3338393a38342e2e2b262017110a0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd4c7baada194877a6e61544c4c4c4c4c4c4c4c4c4c4b4b4a4846423c3b37322a252726231f19120a020000000000000000000000000000000000000000000000000009121b252d353d424a505357565e616263636363636363636363636363636363636262615e5656544f47433c332b23191006000000000000000000000000000000000000000002070c0f11121313131313131313131313130908060300000000000000000000070c101313181c1e1f1f1e1b181413100d07010000000000000000000003060613131313131313131313131313090806030000000000000000000000000000060b151a1f2122282b2d2d2b2823211f1b150b06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd4c7baada194877a6e6154473f3f3f3f3f3f3f3f3f3f3e3d3b3a3631343434343434332f2b241c140a010000000000000000000000000000000000000000000000000009131b232b30383f44464a4c5254555656565656565656565656565656565656565554524c4948443d37312a21191107000000000000000000000000000000000000000000000000030505060606060606060606060606000000000000000000000000000000000406070b0f111212110e0b070604010000000000000000000000000000000606060606060606060606060600000000000000000000000000000000000000030a0f1215171c1f20201f1c1715130f0a0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd4c7baada194877a6e615447424242424242424242424241414141414141414141403f3b362e261c120800000000000000000000000000000000000000000000000000010911191e262e34383a3d41464748494949494949494949494949494949494949484746413d3b38332b2620180f070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306060b0f12131312100b060603000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd4c7baada194877a6e61544f4f4f4f4f4f4f4f4e4e4e4e4e4e4e4e4e4e4e4e4e4e4d4c4740382e24190e020000000000000000000000000000000000000000000000000000070c151c23282c2d3036393a3b3c3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3c3b3a3935302f2c27211a150e060000000000000000000000000003070b0d0d0f0f0f0f0f0f0f0f0f0f0f0f101010101010101010101010100f0f0e0d0c090706040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003060607060300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd4c7baaea194877b6e61575c5c5c5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5a58524a40362b1f1307000000000000000000000000000000000000000000000000000000030a11171c1f20252a2d2e2f30303030303030303030303030303030302f2f2e2d292522201c160f090300000000000000000000000001080e1317191a1b1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1d1d1d1d1d1d1c1c1c1c1c1b1a19161313100c07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd6c9bdb0a3968a7d7069686868686868686868686868686868686868676767676767645c52473b2f23170b0000000000000000000000000000000000000000000000000000000000060c101213191d2021222323232323232323232323232323232323232221201d191613100b0500000000000000000000000000020a12191f23262728282828292929292929292929292929292929292929292929292828272523201f1c18120e0903000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd9d0c4b7aa9d91847b767575757575757575757575757574747474747474747474736e64584c3f3326190d000000000000000000000000000000000000000000000000000000000000000306080d11131415161616161616161616161616161616161616151413110d0807040000000000000000000000000000010a141c242b3033343535353535353536363636363636363636363636363636363636353433322f2d2c28231d1a140d050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfccd9d1c5b8aca09691868382828282828282828281818181818181818181818181818073675a4d4034271a0d000000000000000000000000000000000000000000000000000000000000000000000105070708090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a090807070501000000000000000000000000000000000008121c262e363b3f4042424242424242424242424243434343434343434343434343424241403f3c3a38342e2a251f170f0900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1926333f4c5966727f8c99a5b2bfccd8d4c8bdb2a8a09992908f8f8f8f8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e85786b5f5245382c1f12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030e19242e3840474c4d4e4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f5050505050504f4f4f4f4f4e4d4c4946454039363129211b130a020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1925323f4c5865727f8b98a5b2becedad9cec3bab2aba39f9c9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9a9a9a9a9285786b5f5245382c1f12000000000001060b0e11111313131313131313131313080705020000000000000004090c0e0f13131313131313131313130a0907040000000000000000000000000000000000000000000000000007131f2b36404a52585a5b5b5b5b5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5b5b5a585653514b46423b332d251c140a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1724313e4a5764717e8a97a8b2bdc9d5e0d5ccc3bdb4aeaca9a8a8a8a8a8a8a8a8a8a8a8a8a8a7a7a7a7a7a7a7a79e9285786b5f5245382c1f1200000000040c12171b1d1e20202020202020202020201514120e090200000002091015191b1c2020202020202020202020171614100b0500000000000000000000000000000000000000000000000b1723303b47525c646768686868686868696969696969696969696969696969696969696867666562605c54534d453f372e261c130900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222f3b4855626e7b8896a1acb9c7d1dcded5cfc6bfbab9b6b5b5b5b5b5b5b5b5b5b4b4b4b4b4b4b4b4b4b4b4ab9e9285786b5f5245382c1f12000000060e161d23272a2b2d2d2d2d2d2d2d2d2d2d2d21201e1a140d0500030c141b212528292d2d2d2d2d2d2d2d2d2d2d2423201c161008000000000000000000000000000000000000000000000d1926333f4c58646e737575757575757575757575757676767676767676767676767675757473726f6d66615e57514940382e251b0f05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000814212e3a47535f6a7884919eabb5c0cbd7dfe1d8d1cbc7c5c3c2c2c2c2c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1b8ab9e9285786b5f5245382c1f120000040e1820282e33373839393939393939393939392e2d2a251f170f050c151e262c3134353939393939393939393939302f2c28211a11080000000000000000000000000000000000000000000d1a2734404d5a67738081828282828282828282828282828282838383838383828282828281807f7c79746e69625b524a40372d21170d0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006121f2b37434e586773808d99a3afbbc4cdd5dadedcd7d3d2cfcecececececececececececececececececec5b8ab9e9285786b5f5245382c1f1200010c16202a32393f434446464646464646464646463b3a36302921170d141e2730373d414246464646464646464646463d3c38332c231a10050000000000000000000000000000000000000000111e2b3844515e6b77848e8e8e8e8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8e8e8d8b8985807b726d635c52493f33291f1409000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f1a26313c4855616e7b86929fa8b2bbc3c9cfd1d2d2d4d8ddd2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d1c5b8ab9e9285786b5f5245382c1f120006121d28323c444b4f5153535353535353535353534846423b33291f141b26303942494d4f53535353535353535353534a48443e352c21160b0000000000000000000000000000000000000000111e2b3844515e6b7784919b9b9b9b9b9b9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9b9a999897928d867f736e635b51453b31251a0e010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000915212d3a46535f6974818e96a1a9b2b9bec3c4c5c6c8ccd2c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c5b8ab9e9285786b5f5245382c1f12000b17232e39444e565c5e60606060606060606060605f524d453b30251a212c37424b54595c606060606060606060606057554f473e33281c100400000000000000000000000000000000000000111e2b3844515e6b7784919ea8a8a8a8a8a8a8a8a8a8a9a9a9a9a9a9a9a9a9a9a9a9a9a8a8a7a6a9a29f98928b80736d62574d42362a1e130800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d57606d7a849197a0a8adb3b6b7b8b9bbc0b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b8ab9e9285786b5f5245382c1f12000e1b27333f4b5660676b6c6c6c6c6c6c6c6c6c6c6c6c5e574d42362a1e25313d49545d65686c6c6c6c6c6c6c6c6c6c6c6361594f44382c20140700000000000000000000000000000000000000111e2b3844515e6b7784919eaab5b5b5b5b5b5b5b5b5b5b5b5b5b6b6b6b6b6b6b5b5b5b5b5b4b3b3adaaa29f928b7f72695e53463a2f24190d010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a26313b45525d686f7c8591969ea1a9a9ababacafb6acacacacacacacacacacacacacacacacacacacacacab9e9285786b5f5245382c1f1200111d2a37434f5c677277797979797979797979797976695e52463a2d202834414d59656f757979797979797979797979706b6155483c2f23160900000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c1c1c0bebab4aea49f92867b6e61554c4135291d110400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f2935414c565f6a6f7c848c92979a9c9e9f9fa49f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9e9285786b5f5245382c1f1200111e2b3844515e6b778486868686868686868686867b6e6154483b2e212935424f5c68758186868686868686868686867d7063574a3d3024170a00000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4cacacacacacacacacacacacacacacacacacacacccfcecdd0cac6bfbaaea2988e8174675d5145392c201306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030d19242f3a444e585f6a6e797f858a8d909192939a9393939393939393939393939393939393939393939393939285786b5f5245382c1f1200111e2b3844515e6b778491939393939393939393877b6e6154483b2e212935424f5c6875828f9393939393939393938a7d7063574a3d3024170a00000000000000000000000000000000000000111e2b3844515e6b7784919eaab7bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbfc4c5c9ced6d0cabfb4aa9f92857a6d6054473a2d2114070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008131e28323c464e575f676d73797d8083848586868686868686868686868686868686868686868686868686868685786b5f5245382c1f1200111e2b3844515e6b7784919e9f9f9f9f9f9f9f94877b6e6154483b2e212935424f5c6875828f9b9f9f9f9f9f9f9f968a7d7063574a3d3024170a00000000000000000000000000000000000000111e2b3844515e6b7784919eaab0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b3b7b9bdc4ccd4d0c5baaea2988a7e7164574b3e3124180600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c16202a343c454e555c60666d70747678787979797979797979797979797979797979797979797979797979797873685d5044372b1e1100111e2b3844515e6b7784919eaaacacacacaca194877b6e6154483b2e212935424f5c6875828f9ba8acacacacaca3968a7d7063574a3d3024170a00000000000000000000000000000000000000111e2b3844515e6b7784919ea4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a6abacb2bac2cad6cabfb4aa9a8d8174675a4e412d22170b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d18222a333c434b51545c606467696b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6b6861574c4034281c0f00111e2b3844515e6b7784919eaab7b9b9b9aea194877b6e6154483b2e212935424f5c6875828f9ba8b5b9b9b9b0a3968a7d7063574a3d3024170a00000000000000000000000000000000000000111e2b3844515e6b7784919797979797979797979797979797979797979797979797999ea1a8b0b8c2cdd0c3b7aa9d9084776a544a3f33281c0f030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071018212a303940454a5153575a5d5e5f6060606060606060606060606060606060606060606060606060605f5d574f453b2f24180c00111e2b3844515e6b7784919eaab7c4c6baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c6bdb0a3968a7d7063574a3d3024170a00000000000000000000000000000000000000111e2b3844515e6b77848a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8c91969fa6b0bcc7d2c5b9ac9f928679665b5044382b1f1206000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070f181e272e34394044464a4d50515253535353535353535353535353535353535353535353535353535352504c453d33291e130700111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000a1723303d4a5663707d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d7d808490949fabb7c6d0c7baaea39886786c605346392d20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c151d23282e34383a3d414345454646464646464646464646464646464646464646464646464646464544403b332b21170d0200111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000916232f3c4855616b70717171717171717171717171717171717171717171717171737982909caab4bfcacbbfb4a09386796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030b12181c23282c2d31343638393939393939393939393939393939393939393939393939393939393837342f2921190f060000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000714202c38444f596163646464646464646464646464646464646464646464646464676f7c8898a2aebac7d1b9aca09386796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070c12181c1f2024272a2b2c2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2c2b28241e170f07000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a0000000000000000000000000000000000000004101c27333d474f555657575757575757595c5e5f606060606060606060606060555f6a7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070c101213171a1d1e1f2020202020202020202020202020202020202020202020202020201f1e1c18130d0600000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a00000000000000000000000000000000000000000b16212c353d44484a4a4a4f54575f6265696b6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c7985929facb8c5c6b9aca09386796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406070a0e10121213131313131313131313131313131313131313131313131313131312110f0c07020000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000005101a232c333839424b515960636a6e727577787979797979797979797979797979797986929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000000081118232e39424b545c606b6f767b7f828485868686868686868686868686868686868998a2aebac6c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a00000000000000000000000000000000000000000004101c2834404b545c666d737c82888c8f9192939a939393939393939393939393939393a2aab4bfcac6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a0000000000000000000000000000000000000000030e18212c3845515c666d7880878f94989c9e9f9fa49f9f9f9f9f9f9f9f9f9f9f9f9f9fa0aeb4bcc6d0c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a00000000000000000000000000000000000000000915202c38444f59606d78828d93999fa6a8aaabacafb6acacacacacacacacacacacacacacbabfc6ced7c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a00000000000000000000000000000000000000020f1a26313c4855616b75818e949fa4abb0b5b7b8b9bbc0b9b9b9b9b9b9b9b9b9b9b9b9b9b9c6cad0d7d3c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a0000000000000000000000000000000000000006121f2b37434e5863707d8a939ea6afb5bdc2c4c5c6c8ccd2c6c6c6c6c6c6c6c6c6c6c6c6c6d3d6dbe2d3c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000814212e3a47535f6a7783909da5afbbc0c7d0d1d2d1cbc7c5c5c5c5c5c5c5c5c5c5c5c7cbd1d6dbe1e9d3c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000815222f3b4855626e7b8895a0acb7c1ccd2d4cdc7c7c0bbb9b9b9b9b9b9b9b9b9b9b9bbbfc6cacfd7dfd3c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000c1926323f4c5965727f8c98a7b1bcc9d7d4cbc2bcb8b5afacacacacacacacacacacacaeb5babec5cdd7d3c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000e1a2734414d5a6774808d9aa7b3c0ced5ccc2b9b1ababa39f9f9f9f9f9f9f9f9f9f9fa3abadb3bbc5cfdbc6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1b2835424e5b6875818e9ba8b4c1cecec3bab1a79f9d999292929292929292929292999fa2a9b3becad6c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2cec8bdb2a89f95908986868686868686868686868a9297a2adbac6d3c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2cec5b8aca09690837c79797979797979797979797e85929fabb8c5d0c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2cec4b7aa9e9184796f6c666c6c6c6c6c6c6c666d717e8a97aab4bfcac6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2cbbeb2a5988b7f7267605b5f5f5f5f5f5f5f5c606d7a8698a2aebac6c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e212935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d706355504a53535353534a515d677985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b2e292935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3f4646464646404b556c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154483b36363636424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d2d3939392f46525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154484343434343434f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d302c2c2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e6154494f4f4f4f4f4f4d566875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3024202c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4c7baaea194877b6e615b535c5c5c5c5c5c575f687683909ca9b6c3c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d30241f2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4cbbeb1a4988b7e716c656969696969696969696e7a86929facb9c5c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d30241f2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c5b8ab9f92857d78767676767676767676777b829099a3aebbc7c9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d30241f2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3844515e6b7784919eaab7c4d1c6baada297928a85838282828282828283848790949fabb5bfcbc9bdb0a3968a7d7063574a3d3024170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d30241f2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111e2b3744515e6a7784919daab7c4d0cabeb3a9a29f9791908f8f8f8f8f8f8f8f9193999fa6b0bdc6d1cbc0b5ab96897d7063564a3d3023170a000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d30241f2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101d2a3643505d697683909ca9b6c3d2d0c5bcb3ada9a19e9c9c9c9c9c9c9c9c9c9d9fa4abb0b8c2cfd4c7bbafa399887c6f6255483c2f221509000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d30241f2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1b2834414e5b6774818e9aacb6c0ccd8cec5bebab2adaba9a9a9a9a9a9a9a9a9aaacafb5bdc2cad4d2c5b9ac9f9286796d6053473a2d201407000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d30241f2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1825323e4b5865717e8b9aa4afbbc8d4d7d0cac4beb9b8b6b5b5b5b5b5b5b5b6b7b9bbc0c7d0d4d7cdc3b7aa9d908377675d5145392c201306000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d30241f2c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000815222e3b4855616e7b87939facb9c0cbd0d3d6cfc9c6c4c3c2c2c2c2c2c2c2c2c4c6c7ccd2d5d2cdc5bbafa59a8d807367554b4035291d1004000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d3029292c3946525f6c7985929facb8c5c6b9aca09386796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000714212d3a46535f6976828f9ca5afbabfc5c7cad0c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9cec9c5c2bbb3a99e93887b6e6255483b2f24180d01000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a3d363636363946525f6c7985929facb8c5c6b9aca09386796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005121e2a36424d5763707d89939da5aeb4b8babfbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbdb9b7b0a9a1978f82756a5f53473a2e1d120700000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574a43434343434346525f6c7985929facb8c5c6b9aca09386796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e1a26313b4854606b74818e939fa3aaacaeb4afafafafafafafafafafafafafafafafafafb2acaaa69f9792857b6e61584e43372b1f0c0100000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2c9bdb0a3968a7d7063574f4f4f4f4f4f4f4f4e586c7985929facb8c5c6b9aca09386796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141f2c38444f59606d78818c92989c9fa2aaa2a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a2a8a09e9b948f857c6f695e52463c31261a0f0000000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2cabdb0a4978a7d71645a5c5c5c5c5c5c5c5c58606a7985929facb8c5c6b9aca09386796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003101c27323d44515c666d787f868c909298959696969696969696969696969696969696959596918e89827b6f6a5f564d42342a20150a0000000000000000000000000000000000000000000f1c2935424f5c6875828f9ba8b5c2cec1b4a89b8e81756c696969696969696969696a6f7c8898a2aebac6c6b9aca09386796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b16212834404a545c666d727a7f83858888898989898989898989898989898989898989888784817c766e695f584e443b3022180e030000000000000000000000000000000000000000000f1c2835424f5b6875828e9ba8b5c1cec6b9ac9f93877e7776767676767676767676777c84919eaab4bfcac6b9aca09386796d6053463a2d2013070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050c18232e39424a545c60686d7276797b7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7b7a77746f6b615f574e463c32291f0f06000000000000000000000000000000000000000000000e1b2835414e5b6874818e9ba7b4c1cec7bbafa499938a848282828282828282828284899196a1acbcc6d0c6b9aca09386796d6053463a2d20130700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007121c273039424a50565e6165666d6e6f6f707070707070707070707070707070706f6e6d6868636059534d453c342a20170d00000000000000000000000000000000000000000000000e1a2734414d5a6774808d9aa7b3c0cdccc0b5aba49f96918f8f8f8f8f8f8f8f8f8f90959ea1a8b2bdced4c8bbafa49a86796d6053463a2d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b151e2730383f444c5254545c60616263636363636363636363636363636363636262605d5656544f46423b332a22190e0500000000000000000000000000000000000000000000000d192633404c5966737f8c99a6b2bfcdd2c7bdb5afa8a09e9c9c9c9c9c9c9c9c9c9c9da0a7acb2bac4ced2c6b9ac9f9386796c605346392d20130600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c151e262e343a4146474a505355555656565656565656565656565656565656565554524c4948433d363129211910070000000000000000000000000000000000000000000000000a1724303d4a5763707d8a96a7b1bcc8d4d0c7c0bbb2acaaa9a9a9a9a9a9a9a9a9a9aaacb1b9bdc4ccd6d2c5b8ab9f928578655b5044372b1f12050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c141c23283036393a3f44464849494949494949494949494949494949494949484745413c3b38322a261f170f07000000000000000000000000000000000000000000000000000814212e3b4754616e7a8795a0acb8c4d0d8d2ccc3bdb8b7b5b5b5b5b5b5b5b5b5b5b7b8bcc3c9ced6dbd1c4b7aa9e9184776b5e493f33271b0f03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a11171e252a2d2e34383a3b3c3c3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3c3b3a39352f2f2c27211a140d0600000000000000000000000000000000000000000000000000000714202d3946525e687783909da8b2bec6cfd2d4cec8c5c4c2c2c2c2c2c2c2c2c2c2c3c5c8ced5d4d2cfcabfb4aa9b8e8275685b4f422d22170b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060b13191d2023282c2d2e2f30303030303030303030303030303030302f2f2d2c2924221f1b160e090300000000000000000000000000000000000000000000000000000005111e2a36414c5665727f8b96a1acb5bdc3c6c7ccd2c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9d1cbc7c5c4beb9aea2988b7f7265584c3f322519060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080d1113171c1f2022222323232323232323232323232323232323232221201d1915130f0a040000000000000000000000000000000000000000000000000000000000020e1925303b4754606d7a84919aa3abb1b7b9bbc0bcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcc0bbb9b7b3ada69f92867a6d6154473a2e2114070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105060c1012131516161616161616161616161616161616161616151413110d08070300000000000000000000000000000000000000000000000000000000000000000814202c3945515d67707d8892999fa7aaacafb5afafafafafafafafafafafafafafafafafb5afacaaa9a29e948c8073685d5246392d201307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000306070809090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a090807070401000000000000000000000000000000000000000000000000000000000000000000000004111d2935414b55606b717e8790959a9d9fa4aba2a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3aba39f9d9b97928c82786d60564c4135291d110500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d18242f3a434f59626c717d83898d909399959696969696969696969696969696969696969992918e8a857f786d665c50443a3024190d01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007131d28313d47505a626b6f777d8184868788898989898989898989898989898989898989888684817e7a726d665c544a3f32281e1308000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c161f2b353f48505960636b7074777a7b7b7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7b797774716d67605c544a42382e20160c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040d1a232d363f474f5459606367676d6e6f6f707070707070707070707070707070706f6e6d676864605d55504a423830261c0e0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008111b242d353d44484f5456555d60616263636363636363636363636363636363636362605c555753514b443f3830261e150a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009121b232b32383d4448494b515354555656565656565656565656565656565656565553514b4b4745403a342e261e150c0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009111921272c33383c3d4045474848494949494949494949494949494949494949484645403e3a39352f28231c140c030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070f161b21272c2f2f35383a3b3c3c3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3c3b3a38342e2d2c29241d17110a0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040a0f161c202224292c2d2e2f3030303030303030303030303030303030302f2d2c282320201d18130b060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050b101316181d1f20212223232323232323232323232323232323232322201f1c181413110d070100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407070c1013141515161616161616161616161616161616161616151313100c0706040100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000406070809090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a09080706040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + m_StreamData: + serializedVersion: 2 + offset: 0 + size: 0 + path: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71c1514a6bd24e1e882cebbe1904ce04, type: 3} + m_Name: contb SDF + m_EditorClassIdentifier: + hashCode: -2139332507 + material: {fileID: 3354070144502634594} + materialHashCode: 479828389 + m_Version: 1.1.0 + m_SourceFontFileGUID: a963d5f9cc80b6e409b0aac9c1ad2531 + m_SourceFontFile_EditorRef: {fileID: 12800000, guid: a963d5f9cc80b6e409b0aac9c1ad2531, type: 3} + m_SourceFontFile: {fileID: 12800000, guid: a963d5f9cc80b6e409b0aac9c1ad2531, type: 3} + m_AtlasPopulationMode: 1 + m_FaceInfo: + m_FaceIndex: 0 + m_FamilyName: Continuum Bold + m_StyleName: Regular + m_PointSize: 90 + m_Scale: 1 + m_UnitsPerEM: 1000 + m_LineHeight: 91.170006 + m_AscentLine: 73.350006 + m_CapLine: 64 + m_MeanLine: 48 + m_Baseline: 0 + m_DescentLine: -17.820002 + m_SuperscriptOffset: 73.350006 + m_SuperscriptSize: 0.5 + m_SubscriptOffset: -17.820002 + m_SubscriptSize: 0.5 + m_UnderlineOffset: -18.900002 + m_UnderlineThickness: 1.8000001 + m_StrikethroughOffset: 19.2 + m_StrikethroughThickness: 1.8000001 + m_TabWidth: 25 + m_GlyphTable: + - m_Index: 54 + m_Metrics: + m_Width: 40.40625 + m_Height: 63 + m_HorizontalBearingX: 3.515625 + m_HorizontalBearingY: 63 + m_HorizontalAdvance: 47.4375 + m_GlyphRect: + m_X: 10 + m_Y: 41 + m_Width: 41 + m_Height: 63 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 58 + m_Metrics: + m_Width: 72.28125 + m_Height: 65.0625 + m_HorizontalBearingX: 0.984375 + m_HorizontalBearingY: 63.984375 + m_HorizontalAdvance: 74.15625 + m_GlyphRect: + m_X: 157 + m_Y: 10 + m_Width: 74 + m_Height: 66 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 66 + m_Metrics: + m_Width: 48.78125 + m_Height: 4.40625 + m_HorizontalBearingX: -0.265625 + m_HorizontalBearingY: -13.59375 + m_HorizontalAdvance: 48.78125 + m_GlyphRect: + m_X: 88 + m_Y: 10 + m_Width: 50 + m_Height: 5 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 72 + m_Metrics: + m_Width: 39.234375 + m_Height: 47.25 + m_HorizontalBearingX: 4.140625 + m_HorizontalBearingY: 47.25 + m_HorizontalAdvance: 46.890625 + m_GlyphRect: + m_X: 88 + m_Y: 34 + m_Width: 40 + m_Height: 48 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 74 + m_Metrics: + m_Width: 39.875 + m_Height: 64.984375 + m_HorizontalBearingX: 4.140625 + m_HorizontalBearingY: 47.25 + m_HorizontalAdvance: 48.15625 + m_GlyphRect: + m_X: 147 + m_Y: 95 + m_Width: 41 + m_Height: 66 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 76 + m_Metrics: + m_Width: 15.109375 + m_Height: 67.046875 + m_HorizontalBearingX: 2.4375 + m_HorizontalBearingY: 67.046875 + m_HorizontalAdvance: 20.25 + m_GlyphRect: + m_X: 250 + m_Y: 10 + m_Width: 16 + m_Height: 68 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 81 + m_Metrics: + m_Width: 39.15625 + m_Height: 47.25 + m_HorizontalBearingX: 4.140625 + m_HorizontalBearingY: 47.25 + m_HorizontalAdvance: 47.4375 + m_GlyphRect: + m_X: 70 + m_Y: 101 + m_Width: 40 + m_Height: 48 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + - m_Index: 158 + m_Metrics: + m_Width: 57.6875 + m_Height: 11.4375 + m_HorizontalBearingX: 4.765625 + m_HorizontalBearingY: 11.4375 + m_HorizontalAdvance: 67.5 + m_GlyphRect: + m_X: 10 + m_Y: 10 + m_Width: 59 + m_Height: 12 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + m_CharacterTable: + - m_ElementType: 1 + m_Unicode: 83 + m_GlyphIndex: 54 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 87 + m_GlyphIndex: 58 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 95 + m_GlyphIndex: 66 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 101 + m_GlyphIndex: 72 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 103 + m_GlyphIndex: 74 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 105 + m_GlyphIndex: 76 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 110 + m_GlyphIndex: 81 + m_Scale: 1 + - m_ElementType: 1 + m_Unicode: 8230 + m_GlyphIndex: 158 + m_Scale: 1 + m_AtlasTextures: + - {fileID: -8106515014133881816} + m_AtlasTextureIndex: 0 + m_IsMultiAtlasTexturesEnabled: 0 + m_ClearDynamicDataOnBuild: 0 + m_UsedGlyphRects: + - m_X: 0 + m_Y: 0 + m_Width: 78 + m_Height: 31 + - m_X: 78 + m_Y: 0 + m_Width: 69 + m_Height: 24 + - m_X: 147 + m_Y: 0 + m_Width: 93 + m_Height: 85 + - m_X: 78 + m_Y: 24 + m_Width: 59 + m_Height: 67 + - m_X: 0 + m_Y: 31 + m_Width: 60 + m_Height: 82 + - m_X: 240 + m_Y: 0 + m_Width: 35 + m_Height: 87 + - m_X: 137 + m_Y: 85 + m_Width: 60 + m_Height: 85 + - m_X: 60 + m_Y: 91 + m_Width: 59 + m_Height: 67 + m_FreeGlyphRects: + - m_X: 275 + m_Y: 0 + m_Width: 748 + m_Height: 1023 + - m_X: 137 + m_Y: 24 + m_Width: 10 + m_Height: 61 + - m_X: 0 + m_Y: 170 + m_Width: 1023 + m_Height: 853 + - m_X: 197 + m_Y: 87 + m_Width: 826 + m_Height: 936 + - m_X: 197 + m_Y: 85 + m_Width: 43 + m_Height: 938 + - m_X: 60 + m_Y: 31 + m_Width: 18 + m_Height: 60 + - m_X: 0 + m_Y: 158 + m_Width: 137 + m_Height: 865 + - m_X: 0 + m_Y: 113 + m_Width: 60 + m_Height: 910 + - m_X: 119 + m_Y: 91 + m_Width: 18 + m_Height: 932 + m_fontInfo: + Name: + PointSize: 0 + Scale: 0 + CharacterCount: 0 + LineHeight: 0 + Baseline: 0 + Ascender: 0 + CapHeight: 0 + Descender: 0 + CenterLine: 0 + SuperscriptOffset: 0 + SubscriptOffset: 0 + SubSize: 0 + Underline: 0 + UnderlineThickness: 0 + strikethrough: 0 + strikethroughThickness: 0 + TabWidth: 0 + Padding: 0 + AtlasWidth: 0 + AtlasHeight: 0 + atlas: {fileID: 0} + m_AtlasWidth: 1024 + m_AtlasHeight: 1024 + m_AtlasPadding: 9 + m_AtlasRenderMode: 4165 + m_glyphInfoList: [] + m_KerningTable: + kerningPairs: [] + m_FontFeatureTable: + m_GlyphPairAdjustmentRecords: [] + fallbackFontAssets: [] + m_FallbackFontAssetTable: [] + m_CreationSettings: + sourceFontFileName: + sourceFontFileGUID: a963d5f9cc80b6e409b0aac9c1ad2531 + pointSizeSamplingMode: 0 + pointSize: 90 + padding: 9 + packingMode: 0 + atlasWidth: 1024 + atlasHeight: 1024 + characterSetSelectionMode: 7 + characterSequence: + referencedFontAssetGUID: + referencedTextAssetGUID: + fontStyle: 0 + fontStyleModifier: 0 + renderMode: 4165 + includeFontFeatures: 0 + m_FontWeightTable: + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + - regularTypeface: {fileID: 0} + italicTypeface: {fileID: 0} + fontWeights: [] + normalStyle: 0 + normalSpacingOffset: 0 + boldStyle: 0.75 + boldSpacing: 7 + italicStyle: 20 + tabSize: 10 +--- !u!21 &3354070144502634594 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: contb Atlas Material + m_Shader: {fileID: 4800000, guid: 68e6db2ebdc24f95958faec2be5558d6, type: 3} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _Cube: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _FaceTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: -8106515014133881816} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OutlineTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _Ambient: 0.5 + - _Bevel: 0.5 + - _BevelClamp: 0 + - _BevelOffset: 0 + - _BevelRoundness: 0 + - _BevelWidth: 0 + - _BumpFace: 0 + - _BumpOutline: 0 + - _ColorMask: 15 + - _CullMode: 0 + - _Diffuse: 0.5 + - _FaceDilate: 0 + - _FaceUVSpeedX: 0 + - _FaceUVSpeedY: 0 + - _GlowInner: 0.05 + - _GlowOffset: 0 + - _GlowOuter: 0.05 + - _GlowPower: 0.75 + - _GradientScale: 10 + - _LightAngle: 3.1416 + - _MaskSoftnessX: 0 + - _MaskSoftnessY: 0 + - _OutlineSoftness: 0 + - _OutlineUVSpeedX: 0 + - _OutlineUVSpeedY: 0 + - _OutlineWidth: 0 + - _PerspectiveFilter: 0.875 + - _Reflectivity: 10 + - _ScaleRatioA: 0.9 + - _ScaleRatioB: 0.73125 + - _ScaleRatioC: 0.73125 + - _ScaleX: 1 + - _ScaleY: 1 + - _ShaderFlags: 0 + - _Sharpness: 0 + - _SpecularPower: 2 + - _Stencil: 0 + - _StencilComp: 8 + - _StencilOp: 0 + - _StencilReadMask: 255 + - _StencilWriteMask: 255 + - _TextureHeight: 1024 + - _TextureWidth: 1024 + - _UnderlayDilate: 0 + - _UnderlayOffsetX: 0 + - _UnderlayOffsetY: 0 + - _UnderlaySoftness: 0 + - _VertexOffsetX: 0 + - _VertexOffsetY: 0 + - _WeightBold: 0.75 + - _WeightNormal: 0 + m_Colors: + - _ClipRect: {r: -32767, g: -32767, b: 32767, a: 32767} + - _EnvMatrixRotation: {r: 0, g: 0, b: 0, a: 0} + - _FaceColor: {r: 1, g: 1, b: 1, a: 1} + - _GlowColor: {r: 0, g: 1, b: 0, a: 0.5} + - _MaskCoord: {r: 0, g: 0, b: 32767, a: 32767} + - _OutlineColor: {r: 0, g: 0, b: 0, a: 1} + - _ReflectFaceColor: {r: 0, g: 0, b: 0, a: 1} + - _ReflectOutlineColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecularColor: {r: 1, g: 1, b: 1, a: 1} + - _UnderlayColor: {r: 0, g: 0, b: 0, a: 0.5} + m_BuildTextureStacks: [] diff --git a/Assets/Common/Fonts/contb SDF.asset.meta b/Assets/Common/Fonts/contb SDF.asset.meta new file mode 100644 index 0000000..d046a2e --- /dev/null +++ b/Assets/Common/Fonts/contb SDF.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 37d049cc0ec73ba4188bdaf99a92cbe6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Fonts/contb.ttf b/Assets/Common/Fonts/contb.ttf new file mode 100644 index 0000000..45ab0e2 Binary files /dev/null and b/Assets/Common/Fonts/contb.ttf differ diff --git a/Assets/Common/Fonts/contb.ttf.meta b/Assets/Common/Fonts/contb.ttf.meta new file mode 100644 index 0000000..f5a6ae8 --- /dev/null +++ b/Assets/Common/Fonts/contb.ttf.meta @@ -0,0 +1,21 @@ +fileFormatVersion: 2 +guid: a963d5f9cc80b6e409b0aac9c1ad2531 +TrueTypeFontImporter: + externalObjects: {} + serializedVersion: 4 + fontSize: 16 + forceTextureCase: -2 + characterSpacing: 0 + characterPadding: 1 + includeFontData: 1 + fontNames: + - Continuum Bold + fallbackFontReferences: [] + customCharacters: + fontRenderingMode: 0 + ascentCalculationMode: 1 + useLegacyBoundsCalculation: 0 + shouldRoundAdvanceValue: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Animals/dolfijn.png.meta b/Assets/Common/Images/Animals/dolfijn.png.meta index 2c61f14..4b57023 100644 --- a/Assets/Common/Images/Animals/dolfijn.png.meta +++ b/Assets/Common/Images/Animals/dolfijn.png.meta @@ -113,6 +113,18 @@ TextureImporter: overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] diff --git a/Packages/com.unity.barracuda/Editor.meta b/Assets/Common/Images/CourseThumbnails.meta similarity index 77% rename from Packages/com.unity.barracuda/Editor.meta rename to Assets/Common/Images/CourseThumbnails.meta index 3da0412..c28065f 100644 --- a/Packages/com.unity.barracuda/Editor.meta +++ b/Assets/Common/Images/CourseThumbnails.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f6ebab52a13ea425ba87006839f1d776 +guid: eecc30ee326232b4e9d225060dcc3ef2 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Common/Images/CourseThumbnails/ClothesThumbnail.png b/Assets/Common/Images/CourseThumbnails/ClothesThumbnail.png new file mode 100644 index 0000000..e089c93 Binary files /dev/null and b/Assets/Common/Images/CourseThumbnails/ClothesThumbnail.png differ diff --git a/Assets/Common/Images/logo.png.meta b/Assets/Common/Images/CourseThumbnails/ClothesThumbnail.png.meta similarity index 98% rename from Assets/Common/Images/logo.png.meta rename to Assets/Common/Images/CourseThumbnails/ClothesThumbnail.png.meta index 716c436..60a12bc 100644 --- a/Assets/Common/Images/logo.png.meta +++ b/Assets/Common/Images/CourseThumbnails/ClothesThumbnail.png.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7831027558b77f647a264ea6b7e2d8ce +guid: 4913be0505c981a49bdbee0bbe6c33fe TextureImporter: internalIDToNameTable: [] externalObjects: {} @@ -38,7 +38,7 @@ TextureImporter: mipBias: 0 wrapU: 1 wrapV: 1 - wrapW: 1 + wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 diff --git a/Assets/Common/Images/CourseThumbnails/FingerspellingThumbnail.png b/Assets/Common/Images/CourseThumbnails/FingerspellingThumbnail.png new file mode 100644 index 0000000..41b9852 Binary files /dev/null and b/Assets/Common/Images/CourseThumbnails/FingerspellingThumbnail.png differ diff --git a/Packages/com.unity.barracuda/Editor/NNModelIcon.png.meta b/Assets/Common/Images/CourseThumbnails/FingerspellingThumbnail.png.meta similarity index 67% rename from Packages/com.unity.barracuda/Editor/NNModelIcon.png.meta rename to Assets/Common/Images/CourseThumbnails/FingerspellingThumbnail.png.meta index 9a88c6d..75a3173 100644 --- a/Packages/com.unity.barracuda/Editor/NNModelIcon.png.meta +++ b/Assets/Common/Images/CourseThumbnails/FingerspellingThumbnail.png.meta @@ -1,13 +1,13 @@ fileFormatVersion: 2 -guid: 8682ff569c4c7457a8a8e3a527aad537 +guid: 27884d61026c41c41bdf4753dedf4e7f TextureImporter: - fileIDToRecycleName: {} + internalIDToNameTable: [] externalObjects: {} - serializedVersion: 4 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 + sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 @@ -21,6 +21,10 @@ TextureImporter: heightScale: 0.25 normalMapFilter: 0 isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -29,16 +33,16 @@ TextureImporter: maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 - mipBias: -1 + mipBias: 0 wrapU: 1 wrapV: 1 - wrapW: -1 + wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 - spriteMode: 0 + spriteMode: 1 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 @@ -49,13 +53,20 @@ TextureImporter: alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 - textureType: 2 + textureType: 8 textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 platformSettings: - - buildTarget: DefaultTexturePlatform + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 @@ -65,7 +76,9 @@ TextureImporter: allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - - buildTarget: Standalone + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 @@ -75,7 +88,9 @@ TextureImporter: allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - - buildTarget: iPhone + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 @@ -85,7 +100,9 @@ TextureImporter: allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - - buildTarget: Android + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 @@ -95,12 +112,24 @@ TextureImporter: allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime.meta b/Assets/Common/Images/HandGestures.meta similarity index 77% rename from Packages/com.unity.barracuda/Runtime.meta rename to Assets/Common/Images/HandGestures.meta index 195c042..76e07d0 100644 --- a/Packages/com.unity.barracuda/Runtime.meta +++ b/Assets/Common/Images/HandGestures.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a03a1fa0e3b784e19a9e9d31b945b252 +guid: 94386b4db32292f4bb57c1a5399f4aca folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Common/Images/HandGestures/A_vorm.png b/Assets/Common/Images/HandGestures/A_vorm.png new file mode 100644 index 0000000..6d6234a Binary files /dev/null and b/Assets/Common/Images/HandGestures/A_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/A_vorm.png.meta b/Assets/Common/Images/HandGestures/A_vorm.png.meta new file mode 100644 index 0000000..5dd5d54 --- /dev/null +++ b/Assets/Common/Images/HandGestures/A_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: ed5c09a22f5dcb3498f246f9490aa533 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/B_vorm.png b/Assets/Common/Images/HandGestures/B_vorm.png new file mode 100644 index 0000000..abb8a76 Binary files /dev/null and b/Assets/Common/Images/HandGestures/B_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/B_vorm.png.meta b/Assets/Common/Images/HandGestures/B_vorm.png.meta new file mode 100644 index 0000000..940e202 --- /dev/null +++ b/Assets/Common/Images/HandGestures/B_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 8e050dadd89377d4fb62a4ad8f9e8535 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/C_vorm.png b/Assets/Common/Images/HandGestures/C_vorm.png new file mode 100644 index 0000000..411ae03 Binary files /dev/null and b/Assets/Common/Images/HandGestures/C_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/C_vorm.png.meta b/Assets/Common/Images/HandGestures/C_vorm.png.meta new file mode 100644 index 0000000..294ff66 --- /dev/null +++ b/Assets/Common/Images/HandGestures/C_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 330c40bb91dc4b545829054df966ea97 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/D_vorm.png b/Assets/Common/Images/HandGestures/D_vorm.png new file mode 100644 index 0000000..d85d477 Binary files /dev/null and b/Assets/Common/Images/HandGestures/D_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/D_vorm.png.meta b/Assets/Common/Images/HandGestures/D_vorm.png.meta new file mode 100644 index 0000000..4680f7f --- /dev/null +++ b/Assets/Common/Images/HandGestures/D_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: bd9ec5405bb0fea449e9da0f88c524b3 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/E_vorm.png b/Assets/Common/Images/HandGestures/E_vorm.png new file mode 100644 index 0000000..1f4dea0 Binary files /dev/null and b/Assets/Common/Images/HandGestures/E_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/E_vorm.png.meta b/Assets/Common/Images/HandGestures/E_vorm.png.meta new file mode 100644 index 0000000..47e008b --- /dev/null +++ b/Assets/Common/Images/HandGestures/E_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: de823bdd2e36be047a6c7937e5bf5cda +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/F_vorm.png b/Assets/Common/Images/HandGestures/F_vorm.png new file mode 100644 index 0000000..e36c56c Binary files /dev/null and b/Assets/Common/Images/HandGestures/F_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/F_vorm.png.meta b/Assets/Common/Images/HandGestures/F_vorm.png.meta new file mode 100644 index 0000000..50c7d80 --- /dev/null +++ b/Assets/Common/Images/HandGestures/F_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 044b86526fb6697488bbacdc1d76fa03 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/G_vorm.png b/Assets/Common/Images/HandGestures/G_vorm.png new file mode 100644 index 0000000..d0cc22e Binary files /dev/null and b/Assets/Common/Images/HandGestures/G_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/G_vorm.png.meta b/Assets/Common/Images/HandGestures/G_vorm.png.meta new file mode 100644 index 0000000..b790ca7 --- /dev/null +++ b/Assets/Common/Images/HandGestures/G_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 8e61bbc6d63e9d14f88136e81a0b9d84 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/H_vorm.png b/Assets/Common/Images/HandGestures/H_vorm.png new file mode 100644 index 0000000..f0446df Binary files /dev/null and b/Assets/Common/Images/HandGestures/H_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/H_vorm.png.meta b/Assets/Common/Images/HandGestures/H_vorm.png.meta new file mode 100644 index 0000000..3280ad3 --- /dev/null +++ b/Assets/Common/Images/HandGestures/H_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: ed4e4023600c05347874842b68f62231 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/I_vorm.png b/Assets/Common/Images/HandGestures/I_vorm.png new file mode 100644 index 0000000..1ab3364 Binary files /dev/null and b/Assets/Common/Images/HandGestures/I_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/I_vorm.png.meta b/Assets/Common/Images/HandGestures/I_vorm.png.meta new file mode 100644 index 0000000..44f0a39 --- /dev/null +++ b/Assets/Common/Images/HandGestures/I_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: d5bbee7ab92ab2149bffdcd93b93a2d3 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/J_vorm.png b/Assets/Common/Images/HandGestures/J_vorm.png new file mode 100644 index 0000000..e7e80ec Binary files /dev/null and b/Assets/Common/Images/HandGestures/J_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/J_vorm.png.meta b/Assets/Common/Images/HandGestures/J_vorm.png.meta new file mode 100644 index 0000000..6ea7b26 --- /dev/null +++ b/Assets/Common/Images/HandGestures/J_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 32df0c392f6fbfe4faa3bd6f0f009b7a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/K_vorm.png b/Assets/Common/Images/HandGestures/K_vorm.png new file mode 100644 index 0000000..74ac674 Binary files /dev/null and b/Assets/Common/Images/HandGestures/K_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/K_vorm.png.meta b/Assets/Common/Images/HandGestures/K_vorm.png.meta new file mode 100644 index 0000000..2198d34 --- /dev/null +++ b/Assets/Common/Images/HandGestures/K_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 54e8aaec5729e0b438b755ce1c5b8c9f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/L_vorm.png b/Assets/Common/Images/HandGestures/L_vorm.png new file mode 100644 index 0000000..c98abe5 Binary files /dev/null and b/Assets/Common/Images/HandGestures/L_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/L_vorm.png.meta b/Assets/Common/Images/HandGestures/L_vorm.png.meta new file mode 100644 index 0000000..72a740e --- /dev/null +++ b/Assets/Common/Images/HandGestures/L_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: c042d24972c09f849854641b82d164bf +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/M_vorm.png b/Assets/Common/Images/HandGestures/M_vorm.png new file mode 100644 index 0000000..20dcbfc Binary files /dev/null and b/Assets/Common/Images/HandGestures/M_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/M_vorm.png.meta b/Assets/Common/Images/HandGestures/M_vorm.png.meta new file mode 100644 index 0000000..4c4f326 --- /dev/null +++ b/Assets/Common/Images/HandGestures/M_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 6014df6c8e5794c4c91b3d7c636b073f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/N_vorm.png b/Assets/Common/Images/HandGestures/N_vorm.png new file mode 100644 index 0000000..45d437d Binary files /dev/null and b/Assets/Common/Images/HandGestures/N_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/N_vorm.png.meta b/Assets/Common/Images/HandGestures/N_vorm.png.meta new file mode 100644 index 0000000..b094799 --- /dev/null +++ b/Assets/Common/Images/HandGestures/N_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 4a88b6a6c8a4bf5479b9c033313c20dc +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/O_vorm.png b/Assets/Common/Images/HandGestures/O_vorm.png new file mode 100644 index 0000000..5ae3f4a Binary files /dev/null and b/Assets/Common/Images/HandGestures/O_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/O_vorm.png.meta b/Assets/Common/Images/HandGestures/O_vorm.png.meta new file mode 100644 index 0000000..c052066 --- /dev/null +++ b/Assets/Common/Images/HandGestures/O_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 13dd6d407842cbc41a74312f86a7451a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/P_vorm.png b/Assets/Common/Images/HandGestures/P_vorm.png new file mode 100644 index 0000000..6defb9d Binary files /dev/null and b/Assets/Common/Images/HandGestures/P_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/P_vorm.png.meta b/Assets/Common/Images/HandGestures/P_vorm.png.meta new file mode 100644 index 0000000..3c2d41b --- /dev/null +++ b/Assets/Common/Images/HandGestures/P_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: de3b948a0c6e04547afffebadd53c44e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/Q_vorm.png b/Assets/Common/Images/HandGestures/Q_vorm.png new file mode 100644 index 0000000..487d730 Binary files /dev/null and b/Assets/Common/Images/HandGestures/Q_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/Q_vorm.png.meta b/Assets/Common/Images/HandGestures/Q_vorm.png.meta new file mode 100644 index 0000000..22ec35b --- /dev/null +++ b/Assets/Common/Images/HandGestures/Q_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 189b131f13ce67844933e28c6d031cad +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/R_vorm.png b/Assets/Common/Images/HandGestures/R_vorm.png new file mode 100644 index 0000000..dfbce8b Binary files /dev/null and b/Assets/Common/Images/HandGestures/R_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/R_vorm.png.meta b/Assets/Common/Images/HandGestures/R_vorm.png.meta new file mode 100644 index 0000000..a75b357 --- /dev/null +++ b/Assets/Common/Images/HandGestures/R_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: a05e3762c949b83428dc2baf99ab1b34 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/S_vorm.png b/Assets/Common/Images/HandGestures/S_vorm.png new file mode 100644 index 0000000..05c7a51 Binary files /dev/null and b/Assets/Common/Images/HandGestures/S_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/S_vorm.png.meta b/Assets/Common/Images/HandGestures/S_vorm.png.meta new file mode 100644 index 0000000..c19fed4 --- /dev/null +++ b/Assets/Common/Images/HandGestures/S_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 5c157ea40838eb74f8226c89a7244613 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/T_vorm.png b/Assets/Common/Images/HandGestures/T_vorm.png new file mode 100644 index 0000000..a4c84f1 Binary files /dev/null and b/Assets/Common/Images/HandGestures/T_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/T_vorm.png.meta b/Assets/Common/Images/HandGestures/T_vorm.png.meta new file mode 100644 index 0000000..bd1ed8f --- /dev/null +++ b/Assets/Common/Images/HandGestures/T_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: ecd6f60f1bc981b4fb5082ac07e69b6f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/U_vorm.png b/Assets/Common/Images/HandGestures/U_vorm.png new file mode 100644 index 0000000..8b19318 Binary files /dev/null and b/Assets/Common/Images/HandGestures/U_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/U_vorm.png.meta b/Assets/Common/Images/HandGestures/U_vorm.png.meta new file mode 100644 index 0000000..6586542 --- /dev/null +++ b/Assets/Common/Images/HandGestures/U_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: c81ae3b4548e432498e92c09b4f6d0c9 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/V_vorm.png b/Assets/Common/Images/HandGestures/V_vorm.png new file mode 100644 index 0000000..57919c2 Binary files /dev/null and b/Assets/Common/Images/HandGestures/V_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/V_vorm.png.meta b/Assets/Common/Images/HandGestures/V_vorm.png.meta new file mode 100644 index 0000000..1ebcf6a --- /dev/null +++ b/Assets/Common/Images/HandGestures/V_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 5ab8fc41b65050e4a884ef7ac126318b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/W_vorm.png b/Assets/Common/Images/HandGestures/W_vorm.png new file mode 100644 index 0000000..3dd4807 Binary files /dev/null and b/Assets/Common/Images/HandGestures/W_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/W_vorm.png.meta b/Assets/Common/Images/HandGestures/W_vorm.png.meta new file mode 100644 index 0000000..8071fdd --- /dev/null +++ b/Assets/Common/Images/HandGestures/W_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: f345e4c4670a26e43bb67fdd98d17aa5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/X_vorm.png b/Assets/Common/Images/HandGestures/X_vorm.png new file mode 100644 index 0000000..2802268 Binary files /dev/null and b/Assets/Common/Images/HandGestures/X_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/X_vorm.png.meta b/Assets/Common/Images/HandGestures/X_vorm.png.meta new file mode 100644 index 0000000..9ebeedf --- /dev/null +++ b/Assets/Common/Images/HandGestures/X_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 2c38602225a250a45be1017aab650a3d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/Y_vorm.png b/Assets/Common/Images/HandGestures/Y_vorm.png new file mode 100644 index 0000000..e68a915 Binary files /dev/null and b/Assets/Common/Images/HandGestures/Y_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/Y_vorm.png.meta b/Assets/Common/Images/HandGestures/Y_vorm.png.meta new file mode 100644 index 0000000..19ba502 --- /dev/null +++ b/Assets/Common/Images/HandGestures/Y_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 6f880b9858734b34e8d014189cf0535e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/HandGestures/Z_vorm.png b/Assets/Common/Images/HandGestures/Z_vorm.png new file mode 100644 index 0000000..22dfc6f Binary files /dev/null and b/Assets/Common/Images/HandGestures/Z_vorm.png differ diff --git a/Assets/Common/Images/HandGestures/Z_vorm.png.meta b/Assets/Common/Images/HandGestures/Z_vorm.png.meta new file mode 100644 index 0000000..43ff47f --- /dev/null +++ b/Assets/Common/Images/HandGestures/Z_vorm.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: de44788bbe2193043a246d12d2df52e5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/House/Appartement.png b/Assets/Common/Images/House/Appartement.png index bd933ee..1380313 100644 Binary files a/Assets/Common/Images/House/Appartement.png and b/Assets/Common/Images/House/Appartement.png differ diff --git a/Assets/Common/Images/House/Badkamer.png b/Assets/Common/Images/House/Badkamer.png index 4083ba8..3c6b0a4 100644 Binary files a/Assets/Common/Images/House/Badkamer.png and b/Assets/Common/Images/House/Badkamer.png differ diff --git a/Assets/Common/Images/House/Bed.png b/Assets/Common/Images/House/Bed.png index 4cf6ca8..c28ffa1 100644 Binary files a/Assets/Common/Images/House/Bed.png and b/Assets/Common/Images/House/Bed.png differ diff --git a/Assets/Common/Images/House/Bureau.png b/Assets/Common/Images/House/Bureau.png index f5afdff..be09896 100644 Binary files a/Assets/Common/Images/House/Bureau.png and b/Assets/Common/Images/House/Bureau.png differ diff --git a/Assets/Common/Images/House/Chalet.png b/Assets/Common/Images/House/Chalet.png index bab44a3..1c8f0f3 100644 Binary files a/Assets/Common/Images/House/Chalet.png and b/Assets/Common/Images/House/Chalet.png differ diff --git a/Assets/Common/Images/House/Gang.png b/Assets/Common/Images/House/Gang.png index 2b30ac2..9a34703 100644 Binary files a/Assets/Common/Images/House/Gang.png and b/Assets/Common/Images/House/Gang.png differ diff --git a/Assets/Common/Images/House/Huis.png b/Assets/Common/Images/House/Huis.png index e748e3f..cd33255 100644 Binary files a/Assets/Common/Images/House/Huis.png and b/Assets/Common/Images/House/Huis.png differ diff --git a/Assets/Common/Images/House/Kast.png b/Assets/Common/Images/House/Kast.png index 532ba8b..fc5e3ed 100644 Binary files a/Assets/Common/Images/House/Kast.png and b/Assets/Common/Images/House/Kast.png differ diff --git a/Assets/Common/Images/House/Keuken.png b/Assets/Common/Images/House/Keuken.png index 30d176c..0f8c07f 100644 Binary files a/Assets/Common/Images/House/Keuken.png and b/Assets/Common/Images/House/Keuken.png differ diff --git a/Assets/Common/Images/House/Kleerkast.png b/Assets/Common/Images/House/Kleerkast.png index 47761a6..bc53813 100644 Binary files a/Assets/Common/Images/House/Kleerkast.png and b/Assets/Common/Images/House/Kleerkast.png differ diff --git a/Assets/Common/Images/House/Living.png b/Assets/Common/Images/House/Living.png index 212ebe2..07ac674 100644 Binary files a/Assets/Common/Images/House/Living.png and b/Assets/Common/Images/House/Living.png differ diff --git a/Assets/Common/Images/House/Slaapkamer.png b/Assets/Common/Images/House/Slaapkamer.png index d429b61..cbdd5e6 100644 Binary files a/Assets/Common/Images/House/Slaapkamer.png and b/Assets/Common/Images/House/Slaapkamer.png differ diff --git a/Assets/Common/Images/House/Stoel.png b/Assets/Common/Images/House/Stoel.png index 0bc8b09..aa794c8 100644 Binary files a/Assets/Common/Images/House/Stoel.png and b/Assets/Common/Images/House/Stoel.png differ diff --git a/Assets/Common/Images/House/Tafel.png b/Assets/Common/Images/House/Tafel.png index 44c8ee8..c295f11 100644 Binary files a/Assets/Common/Images/House/Tafel.png and b/Assets/Common/Images/House/Tafel.png differ diff --git a/Assets/Common/Images/House/Villa.png b/Assets/Common/Images/House/Villa.png index fc520ab..2f9941c 100644 Binary files a/Assets/Common/Images/House/Villa.png and b/Assets/Common/Images/House/Villa.png differ diff --git a/Assets/Common/Images/House/Zetel.png b/Assets/Common/Images/House/Zetel.png index 9043c8e..0852860 100644 Binary files a/Assets/Common/Images/House/Zetel.png and b/Assets/Common/Images/House/Zetel.png differ diff --git a/Assets/Common/Images/Menus.meta b/Assets/Common/Images/Menus.meta new file mode 100644 index 0000000..b7301f3 --- /dev/null +++ b/Assets/Common/Images/Menus.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 32bcd8fab8cced14097cb83cad6f8a7d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/Button.png b/Assets/Common/Images/Menus/Button.png new file mode 100644 index 0000000..758fd17 Binary files /dev/null and b/Assets/Common/Images/Menus/Button.png differ diff --git a/Assets/Common/Images/Menus/Button.png.meta b/Assets/Common/Images/Menus/Button.png.meta new file mode 100644 index 0000000..50763c8 --- /dev/null +++ b/Assets/Common/Images/Menus/Button.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 46578af6a9f38ea46bf4f53f79e8fca8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/ButtonGlow.png b/Assets/Common/Images/Menus/ButtonGlow.png new file mode 100644 index 0000000..b1792e7 Binary files /dev/null and b/Assets/Common/Images/Menus/ButtonGlow.png differ diff --git a/Assets/Common/Images/Menus/ButtonGlow.png.meta b/Assets/Common/Images/Menus/ButtonGlow.png.meta new file mode 100644 index 0000000..24885cf --- /dev/null +++ b/Assets/Common/Images/Menus/ButtonGlow.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: a96945215efea6247ad7760d024d1eb6 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Close.png b/Assets/Common/Images/Menus/Close.png similarity index 100% rename from Assets/Common/Images/Close.png rename to Assets/Common/Images/Menus/Close.png diff --git a/Assets/Common/Images/Close.png.meta b/Assets/Common/Images/Menus/Close.png.meta similarity index 100% rename from Assets/Common/Images/Close.png.meta rename to Assets/Common/Images/Menus/Close.png.meta diff --git a/Assets/Common/Images/Menus/Free Flat Arrow 2 E Icon.png b/Assets/Common/Images/Menus/Free Flat Arrow 2 E Icon.png new file mode 100644 index 0000000..b20f488 Binary files /dev/null and b/Assets/Common/Images/Menus/Free Flat Arrow 2 E Icon.png differ diff --git a/Assets/Common/Images/Menus/Free Flat Arrow 2 E Icon.png.meta b/Assets/Common/Images/Menus/Free Flat Arrow 2 E Icon.png.meta new file mode 100644 index 0000000..0d6f99d --- /dev/null +++ b/Assets/Common/Images/Menus/Free Flat Arrow 2 E Icon.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 20d0d5f265af8554887f17fc0271b1be +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/Free Flat Arrow 6 E Icon.png b/Assets/Common/Images/Menus/Free Flat Arrow 6 E Icon.png new file mode 100644 index 0000000..e9b16d2 Binary files /dev/null and b/Assets/Common/Images/Menus/Free Flat Arrow 6 E Icon.png differ diff --git a/Assets/Common/Images/Menus/Free Flat Arrow 6 E Icon.png.meta b/Assets/Common/Images/Menus/Free Flat Arrow 6 E Icon.png.meta new file mode 100644 index 0000000..e12561a --- /dev/null +++ b/Assets/Common/Images/Menus/Free Flat Arrow 6 E Icon.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 7e2e820c998654c488cdb2cb1bc084f4 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/Free Flat Arrow Curved Left 2 Icon.png b/Assets/Common/Images/Menus/Free Flat Arrow Curved Left 2 Icon.png new file mode 100644 index 0000000..d8363ce Binary files /dev/null and b/Assets/Common/Images/Menus/Free Flat Arrow Curved Left 2 Icon.png differ diff --git a/Assets/Common/Images/Menus/Free Flat Arrow Curved Left 2 Icon.png.meta b/Assets/Common/Images/Menus/Free Flat Arrow Curved Left 2 Icon.png.meta new file mode 100644 index 0000000..b424d90 --- /dev/null +++ b/Assets/Common/Images/Menus/Free Flat Arrow Curved Left 2 Icon.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: b35e8d4a1c2d02544bb23e9c6a440998 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/Free Flat Gear 2 Icon.png b/Assets/Common/Images/Menus/Free Flat Gear 2 Icon.png new file mode 100644 index 0000000..ed9701b Binary files /dev/null and b/Assets/Common/Images/Menus/Free Flat Gear 2 Icon.png differ diff --git a/Assets/Common/Images/Menus/Free Flat Gear 2 Icon.png.meta b/Assets/Common/Images/Menus/Free Flat Gear 2 Icon.png.meta new file mode 100644 index 0000000..31d708f --- /dev/null +++ b/Assets/Common/Images/Menus/Free Flat Gear 2 Icon.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 9ae27e558c598724ea9fd56afe36904c +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/Free Flat Menu 10 Icon.png b/Assets/Common/Images/Menus/Free Flat Menu 10 Icon.png new file mode 100644 index 0000000..59e4178 Binary files /dev/null and b/Assets/Common/Images/Menus/Free Flat Menu 10 Icon.png differ diff --git a/Assets/Common/Images/Menus/Free Flat Menu 10 Icon.png.meta b/Assets/Common/Images/Menus/Free Flat Menu 10 Icon.png.meta new file mode 100644 index 0000000..dc76cbd --- /dev/null +++ b/Assets/Common/Images/Menus/Free Flat Menu 10 Icon.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 97d2ed59587b322479bc163554094dec +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/Free Flat Move Out Icon.png b/Assets/Common/Images/Menus/Free Flat Move Out Icon.png new file mode 100644 index 0000000..3ae5caa Binary files /dev/null and b/Assets/Common/Images/Menus/Free Flat Move Out Icon.png differ diff --git a/Assets/Common/Images/Menus/Free Flat Move Out Icon.png.meta b/Assets/Common/Images/Menus/Free Flat Move Out Icon.png.meta new file mode 100644 index 0000000..5eba8cb --- /dev/null +++ b/Assets/Common/Images/Menus/Free Flat Move Out Icon.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 3494ae6682f81cb419859e3699220d9d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/MainMenuCircles.png b/Assets/Common/Images/Menus/MainMenuCircles.png new file mode 100644 index 0000000..7dbb558 Binary files /dev/null and b/Assets/Common/Images/Menus/MainMenuCircles.png differ diff --git a/Assets/Common/Images/Menus/MainMenuCircles.png.meta b/Assets/Common/Images/Menus/MainMenuCircles.png.meta new file mode 100644 index 0000000..1b6a5a4 --- /dev/null +++ b/Assets/Common/Images/Menus/MainMenuCircles.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: fd784925a7479504cad5e0e6c1adf3db +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/MenuCircles.png b/Assets/Common/Images/Menus/MenuCircles.png new file mode 100644 index 0000000..b3c9f9a Binary files /dev/null and b/Assets/Common/Images/Menus/MenuCircles.png differ diff --git a/Assets/Common/Images/Menus/MenuCircles.png.meta b/Assets/Common/Images/Menus/MenuCircles.png.meta new file mode 100644 index 0000000..3ab1e45 --- /dev/null +++ b/Assets/Common/Images/Menus/MenuCircles.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 23ab91005e756724387ca6e807ac1de7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/MenuRightCircles.png b/Assets/Common/Images/Menus/MenuRightCircles.png new file mode 100644 index 0000000..8444b2b Binary files /dev/null and b/Assets/Common/Images/Menus/MenuRightCircles.png differ diff --git a/Assets/Common/Images/Menus/MenuRightCircles.png.meta b/Assets/Common/Images/Menus/MenuRightCircles.png.meta new file mode 100644 index 0000000..5372e93 --- /dev/null +++ b/Assets/Common/Images/Menus/MenuRightCircles.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: b64232b71c9f17a4d9494ad951a74dfa +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 1 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/Progressbar.png b/Assets/Common/Images/Menus/Progressbar.png new file mode 100644 index 0000000..7185aa2 Binary files /dev/null and b/Assets/Common/Images/Menus/Progressbar.png differ diff --git a/Packages/com.unity.barracuda/Editor/ONNXModelIcon.png.meta b/Assets/Common/Images/Menus/Progressbar.png.meta similarity index 63% rename from Packages/com.unity.barracuda/Editor/ONNXModelIcon.png.meta rename to Assets/Common/Images/Menus/Progressbar.png.meta index 70427de..a80f948 100644 --- a/Packages/com.unity.barracuda/Editor/ONNXModelIcon.png.meta +++ b/Assets/Common/Images/Menus/Progressbar.png.meta @@ -1,9 +1,9 @@ fileFormatVersion: 2 -guid: 44179f4142e33e24ca4feb8dfe55e56c +guid: 02283f528ead8084db69c7d8a459f0af TextureImporter: - fileIDToRecycleName: {} + internalIDToNameTable: [] externalObjects: {} - serializedVersion: 9 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 @@ -23,6 +23,8 @@ TextureImporter: isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -31,132 +33,112 @@ TextureImporter: maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: -1 - aniso: -1 - mipBias: -100 - wrapU: -1 - wrapV: -1 - wrapW: -1 - nPOTScale: 1 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 lightmap: 0 compressionQuality: 50 - spriteMode: 0 + spriteMode: 1 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteBorder: {x: 20, y: 7, z: 20, w: 7} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 - alphaIsTransparency: 0 + alphaIsTransparency: 1 spriteTessellationDetail: -1 - textureType: 0 + textureType: 8 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 platformSettings: - - serializedVersion: 2 + - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - - serializedVersion: 2 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - - serializedVersion: 2 - buildTarget: iPhone + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - - serializedVersion: 2 - buildTarget: tvOS - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - serializedVersion: 2 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - serializedVersion: 2 - buildTarget: PS4 - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - serializedVersion: 2 - buildTarget: Windows Store Apps - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - serializedVersion: 2 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] - spriteID: + spriteID: 5e97eb03825dee720800000000000000 + internalID: 1537655665 vertices: [] indices: edges: [] weights: [] + secondaryTextures: [] + nameFileIdTable: {} spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 diff --git a/Assets/Common/Images/Menus/ProgressbarEmpty.png b/Assets/Common/Images/Menus/ProgressbarEmpty.png new file mode 100644 index 0000000..e6b7d3c Binary files /dev/null and b/Assets/Common/Images/Menus/ProgressbarEmpty.png differ diff --git a/Assets/Common/Images/Menus/ProgressbarEmpty.png.meta b/Assets/Common/Images/Menus/ProgressbarEmpty.png.meta new file mode 100644 index 0000000..dd3e517 --- /dev/null +++ b/Assets/Common/Images/Menus/ProgressbarEmpty.png.meta @@ -0,0 +1,147 @@ +fileFormatVersion: 2 +guid: 42d6d4c291d8a8a46bd0d545fd445c3d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 20, y: 7, z: 20, w: 7} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 1537655665 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/Rounded40px.png b/Assets/Common/Images/Menus/Rounded40px.png new file mode 100644 index 0000000..8c289a2 Binary files /dev/null and b/Assets/Common/Images/Menus/Rounded40px.png differ diff --git a/Assets/Common/Images/Menus/Rounded40px.png.meta b/Assets/Common/Images/Menus/Rounded40px.png.meta new file mode 100644 index 0000000..93b3b0b --- /dev/null +++ b/Assets/Common/Images/Menus/Rounded40px.png.meta @@ -0,0 +1,123 @@ +fileFormatVersion: 2 +guid: deac5438096d5f64bbdf6b1934ef230e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 37, y: 37, z: 37, w: 37} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 1537655665 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/blue_circle.png b/Assets/Common/Images/Menus/blue_circle.png new file mode 100644 index 0000000..174686b Binary files /dev/null and b/Assets/Common/Images/Menus/blue_circle.png differ diff --git a/Assets/Common/Images/Menus/blue_circle.png.meta b/Assets/Common/Images/Menus/blue_circle.png.meta new file mode 100644 index 0000000..98358ea --- /dev/null +++ b/Assets/Common/Images/Menus/blue_circle.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 88410b681ed1df3499ff0660fe5706b4 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/button clicked.png b/Assets/Common/Images/Menus/button clicked.png similarity index 100% rename from Assets/Common/Images/button clicked.png rename to Assets/Common/Images/Menus/button clicked.png diff --git a/Assets/Common/Images/button clicked.png.meta b/Assets/Common/Images/Menus/button clicked.png.meta similarity index 100% rename from Assets/Common/Images/button clicked.png.meta rename to Assets/Common/Images/Menus/button clicked.png.meta diff --git a/Assets/Common/Images/button unclicked.png b/Assets/Common/Images/Menus/button unclicked.png similarity index 100% rename from Assets/Common/Images/button unclicked.png rename to Assets/Common/Images/Menus/button unclicked.png diff --git a/Assets/Common/Images/button unclicked.png.meta b/Assets/Common/Images/Menus/button unclicked.png.meta similarity index 100% rename from Assets/Common/Images/button unclicked.png.meta rename to Assets/Common/Images/Menus/button unclicked.png.meta diff --git a/Assets/Common/Images/Menus/confetti_and_sparkle.png b/Assets/Common/Images/Menus/confetti_and_sparkle.png new file mode 100644 index 0000000..440611d Binary files /dev/null and b/Assets/Common/Images/Menus/confetti_and_sparkle.png differ diff --git a/Assets/Common/Images/Menus/confetti_and_sparkle.png.meta b/Assets/Common/Images/Menus/confetti_and_sparkle.png.meta new file mode 100644 index 0000000..270f5c9 --- /dev/null +++ b/Assets/Common/Images/Menus/confetti_and_sparkle.png.meta @@ -0,0 +1,245 @@ +fileFormatVersion: 2 +guid: 4d6d852f751f20046ae733db5bdb1af1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 2 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: confetti_and_sparkle_0 + rect: + serializedVersion: 2 + x: 142 + y: 113 + width: 256 + height: 256 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: c1154cb7a7ef9d04dac1610aa91619c8 + internalID: 1457618957 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: confetti_and_sparkle_1 + rect: + serializedVersion: 2 + x: 423 + y: 111 + width: 256 + height: 256 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 0fe19663d184838419232aaefd697385 + internalID: -680790105 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: confetti_and_sparkle_2 + rect: + serializedVersion: 2 + x: 709 + y: 94 + width: 256 + height: 256 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 4ca529c4794447547848dd3a0b01f144 + internalID: -10627408 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: confetti_and_sparkle_3 + rect: + serializedVersion: 2 + x: 993 + y: 126 + width: 256 + height: 256 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: bf0089d5313a75f4384d1c9747a30162 + internalID: -2086278073 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: confetti_and_sparkle_4 + rect: + serializedVersion: 2 + x: 1283 + y: 117 + width: 256 + height: 256 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 163c86bf2d6e0a041acb73a19e17f708 + internalID: -399011709 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 13ae6e17a9a9f774692fa08ddfef0c7b + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: + confetti_and_sparkle_0: 1457618957 + confetti_and_sparkle_1: -680790105 + confetti_and_sparkle_2: -10627408 + confetti_and_sparkle_3: -2086278073 + confetti_and_sparkle_4: -399011709 + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/controller.png b/Assets/Common/Images/Menus/controller.png similarity index 100% rename from Assets/Common/Images/controller.png rename to Assets/Common/Images/Menus/controller.png diff --git a/Assets/Common/Images/controller.png.meta b/Assets/Common/Images/Menus/controller.png.meta similarity index 100% rename from Assets/Common/Images/controller.png.meta rename to Assets/Common/Images/Menus/controller.png.meta diff --git a/Assets/Common/Images/courses.png b/Assets/Common/Images/Menus/courses.png similarity index 100% rename from Assets/Common/Images/courses.png rename to Assets/Common/Images/Menus/courses.png diff --git a/Assets/Common/Images/courses.png.meta b/Assets/Common/Images/Menus/courses.png.meta similarity index 100% rename from Assets/Common/Images/courses.png.meta rename to Assets/Common/Images/Menus/courses.png.meta diff --git a/Assets/Common/Images/Menus/game-controller.png b/Assets/Common/Images/Menus/game-controller.png new file mode 100644 index 0000000..0e90da2 Binary files /dev/null and b/Assets/Common/Images/Menus/game-controller.png differ diff --git a/Assets/Common/Images/Menus/game-controller.png.meta b/Assets/Common/Images/Menus/game-controller.png.meta new file mode 100644 index 0000000..ac2dc71 --- /dev/null +++ b/Assets/Common/Images/Menus/game-controller.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: f30c85a17f81cce4787aad3e86de4eac +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/orange_circle.png b/Assets/Common/Images/Menus/orange_circle.png new file mode 100644 index 0000000..e916108 Binary files /dev/null and b/Assets/Common/Images/Menus/orange_circle.png differ diff --git a/Assets/Common/Images/Menus/orange_circle.png.meta b/Assets/Common/Images/Menus/orange_circle.png.meta new file mode 100644 index 0000000..9208c18 --- /dev/null +++ b/Assets/Common/Images/Menus/orange_circle.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/pause courses.png b/Assets/Common/Images/Menus/pause courses.png new file mode 100644 index 0000000..3b5084d Binary files /dev/null and b/Assets/Common/Images/Menus/pause courses.png differ diff --git a/Assets/Common/Images/Menus/pause courses.png.meta b/Assets/Common/Images/Menus/pause courses.png.meta new file mode 100644 index 0000000..7d53d41 --- /dev/null +++ b/Assets/Common/Images/Menus/pause courses.png.meta @@ -0,0 +1,123 @@ +fileFormatVersion: 2 +guid: e9d7c25ce4800b840a37d69d5b876671 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/Menus/play courses.png b/Assets/Common/Images/Menus/play courses.png new file mode 100644 index 0000000..7564394 Binary files /dev/null and b/Assets/Common/Images/Menus/play courses.png differ diff --git a/Assets/Common/Images/Menus/play courses.png.meta b/Assets/Common/Images/Menus/play courses.png.meta new file mode 100644 index 0000000..92414db --- /dev/null +++ b/Assets/Common/Images/Menus/play courses.png.meta @@ -0,0 +1,123 @@ +fileFormatVersion: 2 +guid: 05a683651206b994fa7921be6d84dddf +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/play.png b/Assets/Common/Images/Menus/play.png similarity index 100% rename from Assets/Common/Images/play.png rename to Assets/Common/Images/Menus/play.png diff --git a/Assets/Common/Images/play.png.meta b/Assets/Common/Images/Menus/play.png.meta similarity index 100% rename from Assets/Common/Images/play.png.meta rename to Assets/Common/Images/Menus/play.png.meta diff --git a/Assets/Common/Images/Menus/reload.png b/Assets/Common/Images/Menus/reload.png new file mode 100644 index 0000000..16d23f2 Binary files /dev/null and b/Assets/Common/Images/Menus/reload.png differ diff --git a/Assets/Common/Images/Menus/reload.png.meta b/Assets/Common/Images/Menus/reload.png.meta new file mode 100644 index 0000000..da5bb61 --- /dev/null +++ b/Assets/Common/Images/Menus/reload.png.meta @@ -0,0 +1,123 @@ +fileFormatVersion: 2 +guid: c503be644b0f16f43beb5cd454225ad1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/settings.png b/Assets/Common/Images/Menus/settings.png similarity index 100% rename from Assets/Common/Images/settings.png rename to Assets/Common/Images/Menus/settings.png diff --git a/Assets/Common/Images/settings.png.meta b/Assets/Common/Images/Menus/settings.png.meta similarity index 100% rename from Assets/Common/Images/settings.png.meta rename to Assets/Common/Images/Menus/settings.png.meta diff --git a/Assets/Common/Images/wesign.png b/Assets/Common/Images/Menus/wesign.png similarity index 100% rename from Assets/Common/Images/wesign.png rename to Assets/Common/Images/Menus/wesign.png diff --git a/Assets/Common/Images/wesign.png.meta b/Assets/Common/Images/Menus/wesign.png.meta similarity index 100% rename from Assets/Common/Images/wesign.png.meta rename to Assets/Common/Images/Menus/wesign.png.meta diff --git a/Assets/Common/Images/Menus/youtube.png b/Assets/Common/Images/Menus/youtube.png new file mode 100644 index 0000000..f9c59c9 Binary files /dev/null and b/Assets/Common/Images/Menus/youtube.png differ diff --git a/Assets/Common/Images/Menus/youtube.png.meta b/Assets/Common/Images/Menus/youtube.png.meta new file mode 100644 index 0000000..d3d56fa --- /dev/null +++ b/Assets/Common/Images/Menus/youtube.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 46681a51b9abdeb4a959db1b53e0fab9 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/MinigameThumbnails.meta b/Assets/Common/Images/MinigameThumbnails.meta new file mode 100644 index 0000000..d41c736 --- /dev/null +++ b/Assets/Common/Images/MinigameThumbnails.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a5270f1141684d0479d54f671bf1e88a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/MinigameThumbnails/Galgje.png b/Assets/Common/Images/MinigameThumbnails/Galgje.png new file mode 100644 index 0000000..d9ba956 Binary files /dev/null and b/Assets/Common/Images/MinigameThumbnails/Galgje.png differ diff --git a/Assets/Common/Images/MinigameThumbnails/Galgje.png.meta b/Assets/Common/Images/MinigameThumbnails/Galgje.png.meta new file mode 100644 index 0000000..3e06a27 --- /dev/null +++ b/Assets/Common/Images/MinigameThumbnails/Galgje.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: a5c737ebfeb7aec458ff909fe92eba43 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/MinigameThumbnails/JustSign.png b/Assets/Common/Images/MinigameThumbnails/JustSign.png new file mode 100644 index 0000000..91f0e90 Binary files /dev/null and b/Assets/Common/Images/MinigameThumbnails/JustSign.png differ diff --git a/Assets/Common/Images/MinigameThumbnails/JustSign.png.meta b/Assets/Common/Images/MinigameThumbnails/JustSign.png.meta new file mode 100644 index 0000000..bece491 --- /dev/null +++ b/Assets/Common/Images/MinigameThumbnails/JustSign.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: bd23bf3e2552a0849ab845e6b9508505 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/MinigameThumbnails/SpellingBee.png b/Assets/Common/Images/MinigameThumbnails/SpellingBee.png new file mode 100644 index 0000000..808c29d Binary files /dev/null and b/Assets/Common/Images/MinigameThumbnails/SpellingBee.png differ diff --git a/Assets/Common/Images/MinigameThumbnails/SpellingBee.png.meta b/Assets/Common/Images/MinigameThumbnails/SpellingBee.png.meta new file mode 100644 index 0000000..64e735a --- /dev/null +++ b/Assets/Common/Images/MinigameThumbnails/SpellingBee.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 99ff017f7243eeb4db0c08a6b832d744 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/SpellingBasics/goedeavond.png b/Assets/Common/Images/SpellingBasics/goedeavond.png new file mode 100644 index 0000000..d90298c Binary files /dev/null and b/Assets/Common/Images/SpellingBasics/goedeavond.png differ diff --git a/Assets/Common/Images/SpellingBasics/goedeavond.png.meta b/Assets/Common/Images/SpellingBasics/goedeavond.png.meta new file mode 100644 index 0000000..ef4ae8e --- /dev/null +++ b/Assets/Common/Images/SpellingBasics/goedeavond.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 1df76d321ac1c984e8809e92a5ae6d5f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/SpellingBasics/goedemiddag.png b/Assets/Common/Images/SpellingBasics/goedemiddag.png new file mode 100644 index 0000000..a5e19e2 Binary files /dev/null and b/Assets/Common/Images/SpellingBasics/goedemiddag.png differ diff --git a/Assets/Common/Images/SpellingBasics/goedemiddag.png.meta b/Assets/Common/Images/SpellingBasics/goedemiddag.png.meta new file mode 100644 index 0000000..5fe120a --- /dev/null +++ b/Assets/Common/Images/SpellingBasics/goedemiddag.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: bf52126d7537c894ca4b576c5eef699b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/SpellingBasics/goedemorgen.png b/Assets/Common/Images/SpellingBasics/goedemorgen.png new file mode 100644 index 0000000..2f1200a Binary files /dev/null and b/Assets/Common/Images/SpellingBasics/goedemorgen.png differ diff --git a/Assets/Common/Images/SpellingBasics/goedemorgen.png.meta b/Assets/Common/Images/SpellingBasics/goedemorgen.png.meta new file mode 100644 index 0000000..8c6206f --- /dev/null +++ b/Assets/Common/Images/SpellingBasics/goedemorgen.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 3d2e3ec9ed08795429f60c10f335196b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/SpellingBasics/goedenacht.png b/Assets/Common/Images/SpellingBasics/goedenacht.png new file mode 100644 index 0000000..067fff0 Binary files /dev/null and b/Assets/Common/Images/SpellingBasics/goedenacht.png differ diff --git a/Assets/Common/Images/SpellingBasics/goedenacht.png.meta b/Assets/Common/Images/SpellingBasics/goedenacht.png.meta new file mode 100644 index 0000000..686b149 --- /dev/null +++ b/Assets/Common/Images/SpellingBasics/goedenacht.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 77bad74134ac6cd439cc026dafffa3aa +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/SpellingBasics/hallo.png b/Assets/Common/Images/SpellingBasics/hallo.png index e379a0b..73a84b7 100644 Binary files a/Assets/Common/Images/SpellingBasics/hallo.png and b/Assets/Common/Images/SpellingBasics/hallo.png differ diff --git a/Assets/Common/Images/SpellingBasics/hallo.png.meta b/Assets/Common/Images/SpellingBasics/hallo.png.meta index 5453e35..87033ed 100644 --- a/Assets/Common/Images/SpellingBasics/hallo.png.meta +++ b/Assets/Common/Images/SpellingBasics/hallo.png.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f2a020e24bfa24842bccecf6b36d5b79 +guid: 9736ebf7e194d954e8db0c651e72210e TextureImporter: internalIDToNameTable: [] externalObjects: {} @@ -102,7 +102,7 @@ TextureImporter: androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 - buildTarget: WebGL + buildTarget: Windows Store Apps maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 diff --git a/Assets/Common/Images/SpellingBasics/slecht.png b/Assets/Common/Images/SpellingBasics/slecht.png new file mode 100644 index 0000000..83e359f Binary files /dev/null and b/Assets/Common/Images/SpellingBasics/slecht.png differ diff --git a/Assets/Common/Images/SpellingBasics/slecht.png.meta b/Assets/Common/Images/SpellingBasics/slecht.png.meta new file mode 100644 index 0000000..7ac02be --- /dev/null +++ b/Assets/Common/Images/SpellingBasics/slecht.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 42286591a195a7542a4f0922fbe161e2 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/SpellingBasics/smakelijk.png b/Assets/Common/Images/SpellingBasics/smakelijk.png new file mode 100644 index 0000000..45781a0 Binary files /dev/null and b/Assets/Common/Images/SpellingBasics/smakelijk.png differ diff --git a/Assets/Common/Images/SpellingBasics/smakelijk.png.meta b/Assets/Common/Images/SpellingBasics/smakelijk.png.meta new file mode 100644 index 0000000..db08da8 --- /dev/null +++ b/Assets/Common/Images/SpellingBasics/smakelijk.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 650f938e5cacbc2409939ab73077b692 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/SpellingBasics/sorry.png b/Assets/Common/Images/SpellingBasics/sorry.png new file mode 100644 index 0000000..905f396 Binary files /dev/null and b/Assets/Common/Images/SpellingBasics/sorry.png differ diff --git a/Assets/Common/Images/SpellingBasics/sorry.png.meta b/Assets/Common/Images/SpellingBasics/sorry.png.meta new file mode 100644 index 0000000..05e3559 --- /dev/null +++ b/Assets/Common/Images/SpellingBasics/sorry.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: 4d265c68fdb4f644ba22e74523ba7f1b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/SpellingBasics/tot ziens.png b/Assets/Common/Images/SpellingBasics/tot ziens.png new file mode 100644 index 0000000..e379a0b Binary files /dev/null and b/Assets/Common/Images/SpellingBasics/tot ziens.png differ diff --git a/Assets/Common/Images/SpellingBasics/tot ziens.png.meta b/Assets/Common/Images/SpellingBasics/tot ziens.png.meta new file mode 100644 index 0000000..5453e35 --- /dev/null +++ b/Assets/Common/Images/SpellingBasics/tot ziens.png.meta @@ -0,0 +1,135 @@ +fileFormatVersion: 2 +guid: f2a020e24bfa24842bccecf6b36d5b79 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Images/logo.png b/Assets/Common/Images/logo.png deleted file mode 100644 index 743945b..0000000 Binary files a/Assets/Common/Images/logo.png and /dev/null differ diff --git a/Assets/Common/Interfaces.meta b/Assets/Common/Interfaces.meta index 5b0f200..75557e1 100644 --- a/Assets/Common/Interfaces.meta +++ b/Assets/Common/Interfaces.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f3e4df0d6e02ad2f0905d1614f2e6545 +guid: 06c24ca85a8bc6b4d947cdb9b2492e99 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Common/Interfaces/Course.cs b/Assets/Common/Interfaces/Course.cs index 0f32dca..583ca95 100644 --- a/Assets/Common/Interfaces/Course.cs +++ b/Assets/Common/Interfaces/Course.cs @@ -20,6 +20,7 @@ public class Course : ScriptableObject /// /// A short description of the course /// + [TextArea] public string description; /// diff --git a/Assets/Common/Interfaces/CourseList.cs b/Assets/Common/Interfaces/CourseList.cs index ce2908a..a5f7e2b 100644 --- a/Assets/Common/Interfaces/CourseList.cs +++ b/Assets/Common/Interfaces/CourseList.cs @@ -4,7 +4,7 @@ using UnityEngine; /// /// Keep track of all courses /// -[CreateAssetMenu(menuName = "Create new Scriptable/CourseList")] +[CreateAssetMenu(menuName = "Create new Scriptable/Course List")] public class CourseList : ScriptableObject { /// diff --git a/Assets/Common/Interfaces/InterfacesScripts.asmdef b/Assets/Common/Interfaces/InterfacesScripts.asmdef index c6d0301..71360c2 100644 --- a/Assets/Common/Interfaces/InterfacesScripts.asmdef +++ b/Assets/Common/Interfaces/InterfacesScripts.asmdef @@ -2,7 +2,8 @@ "name": "InterfacesScripts", "rootNamespace": "", "references": [ - "GUID:5c2b5ba89f9e74e418232e154bc5cc7a" + "GUID:d23f64cfd3b314bb4a18a8284c99bf5e", + "GUID:e83ddf9a537a96b4a804a16bb7872ec1" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Common/Interfaces/InterfacesScripts.asmdef.meta b/Assets/Common/Interfaces/InterfacesScripts.asmdef.meta index 870a1b0..89c2020 100644 --- a/Assets/Common/Interfaces/InterfacesScripts.asmdef.meta +++ b/Assets/Common/Interfaces/InterfacesScripts.asmdef.meta @@ -1,7 +1,6 @@ fileFormatVersion: 2 guid: 7f2d0ee6dd21e1d4eb25b71b7a749d25 -folderAsset: yes -DefaultImporter: +AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: diff --git a/Assets/Common/Interfaces/Learnable.cs b/Assets/Common/Interfaces/Learnable.cs index d3b5bcd..92d967e 100644 --- a/Assets/Common/Interfaces/Learnable.cs +++ b/Assets/Common/Interfaces/Learnable.cs @@ -18,6 +18,16 @@ public class Learnable /// public Sprite image; + /// + /// Sprite of the hand gesture used for fingerspelling + /// + public Sprite handGuide = null; + + /// + /// Addaptive threshold + /// + public float thresholdPercentage = 0.90f; + /// /// Example video clip /// diff --git a/Assets/Common/Interfaces/Minigame.cs b/Assets/Common/Interfaces/Minigame.cs index db50df6..8e6e72e 100644 --- a/Assets/Common/Interfaces/Minigame.cs +++ b/Assets/Common/Interfaces/Minigame.cs @@ -19,6 +19,7 @@ public class Minigame : ScriptableObject /// /// A short description of the minigame /// + [TextArea] public string description; /// diff --git a/Assets/Common/Interfaces/MinigameList.cs b/Assets/Common/Interfaces/MinigameList.cs index 67f3b90..86fae55 100644 --- a/Assets/Common/Interfaces/MinigameList.cs +++ b/Assets/Common/Interfaces/MinigameList.cs @@ -5,7 +5,7 @@ using UnityEngine; /// /// Keep track off installed minigames /// -[CreateAssetMenu(menuName = "Create new Scriptable/MinigameList")] +[CreateAssetMenu(menuName = "Create new Scriptable/Minigame List")] public class MinigameList : ScriptableObject { /// @@ -33,7 +33,7 @@ public class MinigameList : ScriptableObject /// /// public void SetCurrentMinigame(MinigameIndex index) - { + { currentMinigameIndex = minigames.FindIndex((mi) => mi.index == index); } } diff --git a/Assets/Common/Interfaces/ModelIndex.cs b/Assets/Common/Interfaces/ModelIndex.cs new file mode 100644 index 0000000..f188477 --- /dev/null +++ b/Assets/Common/Interfaces/ModelIndex.cs @@ -0,0 +1,9 @@ +/// +/// This enum is used to identify each of the SignLanguage models +/// +public enum ModelIndex +{ + NONE, + FINGERSPELLING, + BASIC_SIGNS +} diff --git a/Assets/Accounts/Tests/ProgressTest.cs.meta b/Assets/Common/Interfaces/ModelIndex.cs.meta similarity index 83% rename from Assets/Accounts/Tests/ProgressTest.cs.meta rename to Assets/Common/Interfaces/ModelIndex.cs.meta index b3be9da..2fdf846 100644 --- a/Assets/Accounts/Tests/ProgressTest.cs.meta +++ b/Assets/Common/Interfaces/ModelIndex.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 30234b937b9c84460ad4846ae1941484 +guid: 6dbd5e1100bc81648b52206df369d0a1 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Common/Interfaces/ModelList.cs b/Assets/Common/Interfaces/ModelList.cs new file mode 100644 index 0000000..b755533 --- /dev/null +++ b/Assets/Common/Interfaces/ModelList.cs @@ -0,0 +1,82 @@ +using NatML; +using System; +using System.Collections.Generic; +using UnityEngine; +/// +/// This scriptable will hold tupples of Courseindices and models +/// +[CreateAssetMenu(menuName = "Create new Scriptable/ModelList")] +public class ModelList : ScriptableObject +{ + /// + /// Small class to link a model to a courseIndex irrespective of its position in a list + /// + [Serializable] + public class ModelTuple + { + /// + /// ModelIndex to which the model corresponds + /// + public ModelIndex index; + /// + /// The model itself + /// + public MLModelData modelWINDOWS; + /// + /// The model itself + /// + public MLModelData modelMAC; + } + + + /// + /// A list of all the models + /// + public List models = new List(); + + /// + /// Index of the currently active model + /// + public int currentModelIndex = 0; + + /// + /// Get a model by modelindex + /// + /// ModelIndex of the model + /// Model associated with this index, null if no model was found + public MLModelData GetCurrentModel() + { + + // Select Model based on OS +#if (UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN) + return models.Find(x => x.modelWINDOWS == models[currentModelIndex].modelWINDOWS)?.modelWINDOWS; +#elif (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX) + return models.Find(x => x.modelMAC == models[currentModelIndex].modelMAC)?.modelMAC; +#endif + return null; + } + + + /// + /// Function to check if the modelIndex has been set + /// + /// + public bool HasValidModel() + { + return models[currentModelIndex].index != (int)ModelIndex.NONE; + } + + /// + /// Function to find a model-index in the list based on its index + /// + /// + public void SetCurrentModel(ModelIndex index) + { + currentModelIndex = models.FindIndex((m) => m.index == index); + } + + public ModelIndex GetCurrentModelIndex() + { + return models[currentModelIndex].index; + } +} diff --git a/Assets/Hangman/Scripts/HangManWebcam.cs.meta b/Assets/Common/Interfaces/ModelList.cs.meta similarity index 83% rename from Assets/Hangman/Scripts/HangManWebcam.cs.meta rename to Assets/Common/Interfaces/ModelList.cs.meta index de815e7..e31c7ee 100644 --- a/Assets/Hangman/Scripts/HangManWebcam.cs.meta +++ b/Assets/Common/Interfaces/ModelList.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a62d2b8bded916443835dc19010b83c1 +guid: 78a3f61c93a08c04496c49ffd10b9021 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Common/Interfaces/Theme.cs b/Assets/Common/Interfaces/Theme.cs index 94d7e19..3ca9a2d 100644 --- a/Assets/Common/Interfaces/Theme.cs +++ b/Assets/Common/Interfaces/Theme.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Unity.Barracuda; using UnityEngine; /// @@ -16,17 +15,19 @@ public class Theme : ScriptableObject /// /// A short description of the theme /// + [TextArea] public string description; /// /// Index of the theme /// - public ThemeIndex index; + public ThemeIndex themeIndex; /// - /// Reference to the model used in the SignPredictor + /// The index of the model you want to use /// - public NNModel model; + public ModelIndex modelIndex; + /// /// List of all learnable words/letters diff --git a/Assets/Common/Interfaces/ThemeList.cs b/Assets/Common/Interfaces/ThemeList.cs index 8681445..f90c0fe 100644 --- a/Assets/Common/Interfaces/ThemeList.cs +++ b/Assets/Common/Interfaces/ThemeList.cs @@ -5,7 +5,7 @@ using UnityEngine; /// /// Keep track off defined themes /// -[CreateAssetMenu(menuName = "Create new Scriptable/ThemeList")] +[CreateAssetMenu(menuName = "Create new Scriptable/Theme List")] public class ThemeList : ScriptableObject { /// @@ -24,6 +24,6 @@ public class ThemeList : ScriptableObject /// public void SetCurrentTheme(ThemeIndex index) { - this.currentThemeIndex = themes.FindIndex((mi) => mi.index == index); + this.currentThemeIndex = themes.FindIndex((mi) => mi.themeIndex == index); } } diff --git a/Assets/Common/Models/BasicSigns.meta b/Assets/Common/Models/BasicSigns.meta new file mode 100644 index 0000000..7859c1b --- /dev/null +++ b/Assets/Common/Models/BasicSigns.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cadb927ad0f664463b8f5fef7146c561 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Models/BasicSigns/embedding_model.mlmodel b/Assets/Common/Models/BasicSigns/embedding_model.mlmodel new file mode 100644 index 0000000..f49f553 Binary files /dev/null and b/Assets/Common/Models/BasicSigns/embedding_model.mlmodel differ diff --git a/Assets/Common/Models/BasicSigns/embedding_model.mlmodel.meta b/Assets/Common/Models/BasicSigns/embedding_model.mlmodel.meta new file mode 100644 index 0000000..32458cf --- /dev/null +++ b/Assets/Common/Models/BasicSigns/embedding_model.mlmodel.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 17fb70e1c284e44da8083b36bb6afcb8 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 3e882272056fc4ddfa14de161aaba2ba, type: 3} diff --git a/Assets/Common/Models/BasicSigns/embedding_model.onnx b/Assets/Common/Models/BasicSigns/embedding_model.onnx new file mode 100644 index 0000000..a8347cd Binary files /dev/null and b/Assets/Common/Models/BasicSigns/embedding_model.onnx differ diff --git a/Assets/Common/Models/BasicSigns/embedding_model.onnx.meta b/Assets/Common/Models/BasicSigns/embedding_model.onnx.meta new file mode 100644 index 0000000..2367a91 --- /dev/null +++ b/Assets/Common/Models/BasicSigns/embedding_model.onnx.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: fa63c40c78ba548468cad97b15cdc6c9 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8264490bef67c46f2982e6dd3f5e46cd, type: 3} diff --git a/Assets/Common/Models/BasicSigns/embeddings.json b/Assets/Common/Models/BasicSigns/embeddings.json new file mode 100644 index 0000000..f2fba82 --- /dev/null +++ b/Assets/Common/Models/BasicSigns/embeddings.json @@ -0,0 +1 @@ +[{"embeddings":[1.7763639688,-3.1912720203,-0.9521460533,-0.9610535502,1.1114379168,0.1387282312,0.2336348891,0.1324800253,0.1113917604,1.0357666016,0.9224734902,1.1723768711,-0.9776515365,0.4712902308,1.2895982265,-1.1841745377,-0.2736907601,-0.5322014093,-1.9371706247,0.8215308189,-1.9528787136,0.5400465131,-0.0710051805,0.0577692837,-0.8172920346,0.8425310254,0.6170938015,-2.7543680668,0.8950541615,0.3217463195,0.7937849164,-0.7707271576],"label_name":"NEE","labels":3},{"embeddings":[1.7610839605,-2.6783227921,-1.107912302,-0.6352344155,2.5966739655,0.2173062116,0.6394487619,-0.7637599111,-1.3238780499,0.4948134124,-0.9345977902,0.3474969566,1.0272641182,1.4108026028,1.2345377207,-0.3868926764,0.3491612077,-0.4609894454,-0.464323312,-0.2004238218,-0.7947492599,0.0119285211,-0.1191795617,-0.1685706973,-0.8047099113,0.4577962458,0.1411647797,-1.6472426653,1.0683716536,-0.4088711441,-0.0284760557,0.2942441404],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[0.91302526,-0.2416291386,0.5122174621,-0.102751486,0.3367956877,1.7259894609,-0.6052535176,-1.7627038956,1.0051989555,-0.3026776314,0.0716279745,0.7956551909,-1.4208037853,0.8660454154,-1.5314471722,-0.9435099959,1.4215251207,0.5521145463,-0.4661634266,1.2521319389,2.276340723,-1.1803455353,2.1788048744,-0.9175488353,-1.1566739082,0.3373167217,1.142255187,-0.6368665695,-0.5706008077,1.2753491402,0.1500054151,0.4856103063],"label_name":"RECHTS","labels":9},{"embeddings":[1.2974061966,-3.3786895275,-1.7737983465,-0.7828662395,1.775408864,-0.6725466847,1.1149597168,0.5610817075,-1.1008995771,1.1772674322,0.2993825376,0.4221803546,0.7760377526,1.1314437389,0.8630550504,-0.5236746073,-0.7960724235,-0.7331047654,-1.4108564854,-0.4237626195,-1.8294472694,1.0137851238,-0.966735065,-0.0666173995,-0.4362661839,0.2465560436,-0.1887108088,-1.3837388754,0.6309615374,0.0495411828,0.6824024916,0.0289013088],"label_name":"GOED","labels":1},{"embeddings":[-0.7117497325,-0.853336215,1.1956688166,-0.3112068176,-1.1757978201,0.2702886462,-0.6330535412,0.1919119209,0.017420508,0.600933075,1.8950737715,1.1246951818,-0.6697360873,0.0182539485,0.5130155087,-0.2731634676,-0.0337213203,-1.7676922083,-2.5008740425,1.4223557711,-0.8419563174,0.3543906808,0.4330492616,-0.8765153885,0.2977792621,0.6577293277,0.4722594023,1.7578846216,-0.5667469501,1.1295797825,-0.402167201,-0.7931195498],"label_name":"GOEDENACHT","labels":2},{"embeddings":[0.8713926077,-2.5777671337,0.6751815677,-1.9412121773,0.6002771854,-0.185951069,-1.3641614914,-0.1859626323,0.0788674578,0.4752109945,0.8403622508,0.9610734582,-0.7758411765,1.4815275669,1.0402457714,-0.2823030651,-0.6862498522,-0.711009562,-2.7017512321,1.6715077162,-1.3044199944,0.8922079206,0.0013608187,-1.0627002716,-0.7628959417,0.2863942087,0.4047830403,-1.1549649239,0.4887218177,0.1053956375,0.8402123451,0.148830086],"label_name":"BEDANKEN","labels":12},{"embeddings":[1.7864868641,-2.1987681389,-0.2462460101,-1.4772286415,1.8600614071,-0.0564967543,-0.3282297552,-0.2458857149,-1.4747308493,0.6487622857,-0.2316109538,0.3797295392,0.9478293061,1.4964745045,0.834841907,0.0673174784,-0.5180274248,-0.7439371943,-0.7211624384,-0.2372838557,-0.9342973232,0.7527505159,0.1726774722,-0.5973324776,-1.2522675991,0.4307409823,0.0353967473,-0.7361733913,0.7358908653,-0.3146584332,-0.3428645134,0.8178830743],"label_name":"SMAKELIJK","labels":8},{"embeddings":[0.6863645315,-1.973528862,-0.2859975398,-0.1235430613,0.1757284403,0.3232569993,-0.8743543625,-0.0442900434,0.417708993,-0.0708189309,0.3567041159,0.188631624,-1.5059956312,-0.4056903124,1.1742019653,-0.6225298643,0.2860187292,0.1133247092,-1.5061047077,1.4394708872,-0.9601070881,-0.7212126851,-0.8007749915,-0.0749935061,0.1392747462,0.1023905799,0.247189641,-2.4029252529,0.8488596678,-0.1725285649,0.7847893834,-1.3293905258],"label_name":"SLECHT","labels":4},{"embeddings":[-0.6859561205,-0.645290792,0.2824152708,0.4911360443,-0.2712836862,1.0815645456,-0.330538094,-2.2100138664,1.1875811815,-1.2792109251,-0.1114567071,0.6670273542,-0.4462137222,0.606584549,-1.5329971313,-0.5233300328,1.9850910902,-0.0462809876,-1.1839334965,1.7771308422,0.7507484555,-2.1838150024,0.6609999537,-0.9980105162,0.2185997367,-1.1449536085,-0.7085445523,0.9015482664,-0.2326255143,0.9462721348,-0.0371706896,-1.4426711798],"label_name":"SALUUT","labels":11},{"embeddings":[-0.3041798472,-1.6430317163,0.4132910371,0.0819983557,-0.184243843,0.2537814081,-0.9196628928,-0.6342142224,0.6110767722,-0.2970709503,0.3774086237,0.2971265018,-1.5702092648,0.0197281502,0.7663198113,-0.2140940726,0.5005736947,0.4009318948,-1.7194527388,1.6184757948,-0.7987033129,-0.7584179044,-1.1120051146,-0.4825130701,0.1790367663,-0.8506331444,-0.29967466,-1.0857229233,0.9358208179,-0.4694308043,0.9013211727,-1.3265792131],"label_name":"SLECHT","labels":4},{"embeddings":[-1.4277319908,0.0735635906,1.8090909719,-0.0740766004,-1.463493824,0.3397239149,-2.286513567,-0.4875959158,0.5558341742,-1.2794657946,0.6370900869,0.4143062234,-2.0543370247,0.2866115868,-0.0859369487,-0.242090404,0.513926208,-0.4075032473,-2.1231632233,2.148058176,-0.0963265747,-1.1255756617,0.0631628036,-0.6335585117,0.5284712911,-0.4596779644,-0.2012760341,0.015429318,-0.2888624966,0.0686699077,0.2197637707,-1.2762635946],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[1.3510650396,-1.7771551609,-0.6348026395,-0.329773128,0.1692387909,-0.8196570873,0.6999639273,1.1786310673,-0.434602499,0.6739457846,1.2465487719,0.726226747,-0.3662394285,-0.1571246535,1.2581073046,-0.541469574,-1.1921635866,-0.8190671802,-1.9120470285,-0.0578650869,-2.6130306721,1.3525804281,-0.1394399554,-0.0206120312,-0.1125046462,0.8907686472,0.7006254196,-0.8813574314,1.2202051878,-0.1800398529,0.178802371,-0.9643304348],"label_name":"JA","labels":6},{"embeddings":[1.9359124899,-1.0531800985,-0.7721303105,-0.0611446872,1.3205338717,0.7415864468,0.4742383957,-1.2770705223,-0.1964254379,-0.1109923422,-0.3782154322,0.4824494421,0.595769465,1.5409582853,-0.4568752646,-0.1921259463,1.0764410496,-0.6329576373,0.0860298052,-0.0766476989,-0.0617785715,0.4663291574,1.7955509424,-0.3673282266,-1.5628577471,0.800614953,0.2609393597,-1.0847753286,0.8146904111,-0.2382262945,-0.3407453895,-0.3618237078],"label_name":"GOED","labels":1},{"embeddings":[0.6121547222,-1.7388967276,0.6601825356,-1.6812596321,-0.4166305065,-0.4955962002,-2.2794449329,-0.476798594,0.2667100728,-0.2193720043,0.266202271,1.1395748854,-0.599342823,1.6177327633,0.4379021227,0.9859451056,0.1015641466,-0.0144876167,-2.5644266605,1.4835119247,-0.3290325403,0.6066228747,-0.1580045819,-0.9250407219,-0.4808055758,-0.3213393986,-0.2471530139,0.0548492745,-0.18703565,0.7530333996,0.7165398598,0.0624365211],"label_name":"SMAKELIJK","labels":8},{"embeddings":[-1.0875866413,-1.4659119844,0.2951740026,0.4842828214,-0.5944662094,0.1473304182,-0.7476466894,-0.3835126162,0.4421735406,-0.532263577,0.4654312432,0.2990401089,-1.209171176,-0.0865720659,0.535168469,-0.0701043084,0.2636514902,-0.4168196917,-1.5616052151,1.692214489,-1.2864458561,-0.9657678604,-1.227738142,-0.3778170943,0.8892444968,-1.0463709831,-0.6003671885,0.0404721126,0.9658361673,-0.2891751528,0.4894969463,-1.2300249338],"label_name":"SLECHT","labels":4},{"embeddings":[1.4570088387,-2.0568802357,-1.6506307125,-0.6593230367,1.4479191303,-0.293017149,1.1748572588,-0.2035029083,-0.580209434,1.0334182978,0.267098546,0.5979781747,1.490593791,1.508567214,0.1595652997,-0.1900058985,-0.2191681266,-0.6369526386,0.0363892056,-0.8684353232,-0.6960636973,1.2920790911,0.3673983216,-0.6073420048,-1.022233963,0.7681050301,-0.0937831774,-0.2332256734,0.0981070623,0.7637836933,0.3055814207,0.2212237716],"label_name":"GOED","labels":1},{"embeddings":[1.5234677792,-2.6639068127,-0.5904372334,-1.4166309834,1.9778661728,0.1721054167,-0.0838110149,-0.86377877,-1.1485906839,0.5714630485,-0.5825967789,0.1497736275,1.4255290031,1.887160182,0.867685914,0.242737323,-0.2486581206,-0.3101930916,-0.6268071532,-0.1760437489,-0.222611919,0.8174934387,-0.0909174234,-0.5956187844,-1.5278520584,0.0990482345,0.0467862412,-0.6287708879,0.0593208447,0.0699243918,-0.1295621991,1.0755785704],"label_name":"SMAKELIJK","labels":8},{"embeddings":[1.9876353741,-0.1525447518,-0.6229496002,-0.1416084319,0.318680197,-1.0563056469,0.7925168872,0.9818572998,-0.9070861936,0.2015966773,0.5383324623,-0.0981415883,0.6967843175,-0.224029839,1.1523542404,-0.277238965,-1.5512779951,-1.2006459236,-0.2585506141,-1.3387042284,-2.4676127434,1.8016865253,0.5133828521,0.4773635864,-0.7140772939,1.5748835802,0.6897760034,-1.2683267593,1.7374924421,-0.91634655,-0.4156680107,-0.041864723],"label_name":"JA","labels":6},{"embeddings":[-0.307058692,-0.5635362864,0.7776136398,-0.4222521484,-0.9248062372,-0.2148074061,-0.3675218821,0.6983985305,0.3207271993,0.9278023839,1.9629787207,1.3328968287,-0.3146366477,0.3483244181,1.2057988644,-0.1947304904,-0.8966225982,-1.6277850866,-1.4920004606,0.5493790507,-1.1671670675,1.681068778,0.4959594011,-0.3734014034,-0.104281798,0.8988946676,0.2675106227,2.4291856289,-0.5743231773,1.1413584948,0.1472075582,-0.0608022213],"label_name":"GOEDENACHT","labels":2},{"embeddings":[1.6928893328,-3.0417580605,-1.5589734316,-0.7043889165,2.1616609097,0.1850540042,0.5779913664,-0.3669098616,-1.2100191116,0.6263768673,-0.8478472829,0.3194809258,1.0316902399,1.6279085875,1.0221774578,-0.6928473115,-0.2953144014,-0.7946798205,-0.7874783278,-0.2159516215,-1.0408111811,0.3966827393,-0.4482270479,-0.212832734,-0.9363744259,0.1887605786,0.1300248802,-2.1588032246,1.2538274527,-0.3259721398,0.155177772,0.1689000875],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[1.561444521,-3.0758712292,-1.2947759628,-0.5603016615,2.4046833515,0.2646133602,0.4812530279,-0.7682378888,-1.1126312017,0.4049234092,-0.7274746895,0.2489915788,1.3931005001,1.8179574013,1.1558520794,0.0086830333,0.1913248003,-0.4646311402,-0.5534793735,-0.2462254614,-1.0175731182,0.1766655743,-0.7207298875,-0.0992190987,-0.8766794801,0.2247821391,-0.0195285603,-1.718473196,0.8858833313,-0.4355651736,-0.0302020572,0.2114863247],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[1.8831551075,-3.1303243637,-1.579608798,-0.8556172848,2.32847929,0.0418943465,0.7299418449,-0.3311955333,-1.1263492107,0.531088233,-0.9478590488,0.2281054258,0.9541679025,1.4579033852,0.9472382665,-0.4409422576,0.013785027,-0.4008561671,-0.8788529038,-0.2896452546,-1.0572428703,0.2408956885,-0.6715857983,-0.0967636108,-0.6378992796,0.0550691858,0.1090000346,-2.135748148,1.030205965,-0.0025410727,0.2332972735,0.1750436127],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[-0.4908067584,-0.2218358666,0.6118279099,0.4361197948,-0.3097043335,1.4342114925,-0.1270092577,-2.503475666,1.3963568211,-1.1293967962,-0.154155165,0.3195056021,-0.957270205,0.5394859314,-1.5473470688,-0.3986577094,2.0292170048,0.3668769896,-1.0329409838,1.7594755888,1.377857089,-1.893037796,1.197655201,-1.078323245,-0.0823462158,-0.8693263531,-0.0698182657,0.5400073528,-0.1591281891,0.8417278528,-0.1029112935,-1.2375226021],"label_name":"SALUUT","labels":11},{"embeddings":[0.5926907063,-1.1513658762,0.8014960885,-1.6106177568,-0.8187755346,-1.066983819,-1.4507699013,0.9912517071,0.2225876749,0.4336421192,1.4477779865,0.6806666255,-1.4643341303,0.1733803302,1.4548401833,-0.0250210539,-1.5873461962,-0.0725992844,-2.4275503159,1.4070278406,-1.9736702442,1.6515995264,-0.4663463235,-0.5966005325,-0.5454865098,0.4626520574,0.4348165393,-0.8402659893,0.6461808085,-0.3263915479,1.2111581564,-0.4358875751],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[0.3911973834,-1.2851458788,0.0081598088,0.7385715842,-0.5669688582,0.6704973578,-0.3585684299,-0.1985711902,0.4236618578,-0.9046241045,0.4483240247,0.5409834981,-1.2578589916,-0.2155991048,1.0225975513,-0.2687417865,0.6163907051,-0.578995645,-1.7411050797,1.6805878878,-1.7439626455,-0.8141228557,-0.2635108232,-0.0125458091,0.2361338735,0.2859105468,0.3636072874,-1.0392614603,1.5070545673,-0.6704319715,0.0157635547,-1.7259887457],"label_name":"SLECHT","labels":4},{"embeddings":[2.0506618023,-0.6483230591,-0.3273056746,-0.3010364473,0.7094726562,-0.6218143106,0.8341499567,1.2267067432,-0.7880901694,0.5094982982,0.6816885471,0.0052928254,-0.3501030803,-0.4190554619,1.4454393387,-0.3397325277,-1.1730351448,-0.7228116989,-0.6595985889,-0.5640858412,-2.228014946,1.1441670656,0.4543311596,0.2308201641,-0.5053201318,1.4609318972,0.8542574644,-2.0964467525,1.6341533661,-1.3241717815,-0.0518127047,-0.4005402327],"label_name":"JA","labels":6},{"embeddings":[1.660764575,-1.8768292665,0.2271265388,-1.2089437246,1.0412933826,-0.4167228639,-0.9394641519,0.1054168791,-1.0125745535,0.6405429244,-0.0947991908,0.481924504,-0.4822843671,1.365391016,1.5167646408,-0.2598196864,-1.036909461,-0.2030622959,-1.1816568375,-0.0446872152,-1.5075594187,0.8312978148,0.2272631079,-0.6285690069,-0.9418247342,0.7659118176,0.6146068573,-1.9298975468,1.1978228092,-0.6513991952,0.0542894043,0.8048211336],"label_name":"SMAKELIJK","labels":8},{"embeddings":[-0.1566810757,0.1239906698,1.3380715847,0.5029073358,-1.1814090014,1.2189004421,-0.8247828484,-0.6928793788,0.9138635397,-1.1027685404,0.8368576169,0.3293106258,-1.7654424906,-0.372431308,0.3560033143,-0.2727555037,0.6635092497,-0.9130882621,-1.6370096207,2.2470695972,-0.7196953297,-1.0467096567,1.0456302166,-0.1755075306,-0.0646871924,-0.0131160114,0.4295301139,0.3039763272,1.010602355,-0.2884487808,-0.50747931,-1.8149186373],"label_name":"SLECHT","labels":4},{"embeddings":[-1.1093276739,0.6491648555,1.3807663918,0.0650914982,-1.5941668749,-0.9875054955,-0.4165605009,0.9483509064,-0.0766204074,0.4464470446,1.5497338772,0.76862818,-0.4664947391,-0.272366643,0.3910744786,0.2736556232,-1.2812651396,-1.4403091669,-1.0558876991,0.3359127045,-1.1904498339,1.1092474461,0.1172028184,-0.5446878672,0.9181300998,0.147849977,0.1996727288,2.6608264446,-1.108980298,0.8687556982,-0.3691963255,0.2194180787],"label_name":"GOEDENACHT","labels":2},{"embeddings":[1.4207897186,-1.3993393183,0.4409970641,-0.6574571729,1.2964093685,0.5329087377,0.3915100098,-0.207599476,-0.2284884453,0.4277477562,0.9929258823,0.4937030971,-0.5605093837,0.0718593597,0.9512236118,-0.4073783457,-0.6420279741,-0.7840849757,-1.0919482708,1.03406775,-0.2675053477,0.6807495952,1.8455286026,-0.8498456478,-0.658180356,1.416981101,1.4321178198,-0.5317707658,0.5481826067,-0.2451825142,-0.7340289354,0.2658241987],"label_name":"LINKS","labels":13},{"embeddings":[1.8213115931,-1.0877350569,0.3783456087,-0.9786010385,0.0054026451,0.2415256053,-0.3429962993,0.4614260197,0.4902126193,0.4663865268,1.1884496212,0.8227789998,-1.8408819437,-0.0474126898,0.9230147004,-1.1384643316,-0.4473569095,-0.8632409573,-1.7373834848,0.8038472533,-1.2270947695,0.6543703079,1.4420268536,-0.5941177607,-1.001183033,1.3040409088,1.531162262,-2.0509312153,1.3614114523,-0.218171984,-0.0112313889,-0.4440345168],"label_name":"JA","labels":6},{"embeddings":[-1.5609784126,1.2078311443,0.1735106111,1.2775886059,-1.2561736107,-0.6811051369,-1.4897202253,-0.7875193357,-0.5480111837,-1.0945672989,-1.6339305639,-0.3377057016,1.7284188271,1.4764990807,0.3233945668,0.2040691674,0.4899930656,-1.4789005518,0.399705112,-0.3089680076,-0.3881782889,0.2557441592,-1.2449202538,1.0648845434,0.9070806503,-1.9294000864,-1.2838168144,1.2033201456,0.5310505033,-0.3831630945,-0.6413698792,-0.8180915117],"label_name":"SORRY","labels":7},{"embeddings":[-0.1862953752,-1.1427534819,0.6310139298,0.7277802229,-0.5097031593,1.1021639109,-0.199277252,-0.4516659379,0.6959517002,-0.6700055003,0.7460276484,0.5731016994,-1.5737687349,-0.0985113084,0.6849079728,-0.4879109263,0.9302133322,-1.8588562012,-1.9571551085,2.1026546955,-1.4972794056,-0.6068314314,0.7691982985,-0.5964977741,0.1059337258,0.4080667794,0.6101683974,-0.2977593243,1.4775686264,-0.0412387922,-0.8296777606,-2.0281326771],"label_name":"SLECHT","labels":4},{"embeddings":[1.9963052273,-2.2242796421,-1.2263602018,-0.8963831067,1.2394366264,-0.9004484415,0.6723440886,0.8956601024,-0.6057508588,0.8826566339,0.6424711943,0.5118813515,0.2422770411,0.6987210512,1.3784521818,-0.7148151398,-0.8734423518,-0.8202095628,-1.1387404203,-0.1615911126,-2.4025509357,1.2271765471,0.2485394329,0.1122488678,-1.0604405403,0.9727162123,0.4450138509,-2.5210082531,1.4231464863,-0.7920578718,0.4151357412,-0.2431577444],"label_name":"JA","labels":6},{"embeddings":[1.4363396168,-1.000395298,0.2864934206,-0.3942466974,0.7229038477,0.8649944067,0.4258811474,-0.2241860479,0.0499655381,0.4451258481,0.7221418619,0.5970428586,-0.6916741133,-0.2041925192,0.4386098981,-0.3185321987,-0.481348604,-0.952526629,-0.74320364,1.4439212084,-0.1978658736,0.8299888968,2.5526509285,-0.9327352047,-0.8781411052,1.3628218174,1.3168259859,-0.0927501842,0.5232653618,-0.0844540671,-0.7932350039,0.0957169533],"label_name":"LINKS","labels":13},{"embeddings":[1.6222033501,-2.6416039467,-1.0987555981,-0.4008184671,1.685628891,-0.1348235756,0.6648471355,0.149780795,-0.4774826169,0.4845748246,0.3011706471,0.5058957934,1.0280252695,1.2357896566,1.2845418453,-0.3002966046,-0.3269697726,-0.6959720254,-1.3324598074,0.0510016643,-2.1105885506,1.0388070345,-0.2180883437,-0.0304073989,-0.784196794,0.7458236217,0.0660361573,-1.2823898792,0.883718431,-0.2115828693,0.4072711766,-0.5354357362],"label_name":"JA","labels":6},{"embeddings":[-0.5961825848,-0.722555995,0.5264210105,-0.8140957952,-1.1312866211,0.1635097414,-1.3492106199,-1.3449854851,1.1013284922,0.0312258638,0.6856180429,0.825963676,-0.3012909293,1.4919915199,-0.2487504035,-0.6653610468,0.9920038581,-1.0116233826,-2.39965868,1.9716428518,0.4042309523,0.0015622601,0.8222219348,-1.0515317917,-0.3399860859,-0.4938497841,0.2805640399,0.8816174269,-0.2876040339,1.935739994,-0.0678723454,-0.9027423859],"label_name":"SALUUT","labels":11},{"embeddings":[1.6206579208,-2.5234806538,-0.9654811621,-0.2348748893,1.8717492819,1.2007844448,-0.1778743416,-1.1097540855,-0.9838000536,-0.2753811479,-1.0186860561,0.1196120009,-0.0531472638,1.2720893621,1.0496377945,-0.4852166176,0.3594139814,-0.4630508423,-0.3715806305,0.2908822894,-0.6949978471,-0.6789780259,0.0684220642,-0.1650894731,-0.9298600554,0.3948025107,0.3303039074,-2.4334709644,1.6018072367,-0.7464275956,-0.0551798008,-0.3982646167],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[0.9262535572,-3.1242542267,0.2908684611,-1.7588222027,0.7720181942,-0.3594640791,-0.9759832621,-0.0969010144,-0.0552095249,0.6895074248,1.0640605688,1.0745446682,-1.0743985176,1.4371402264,1.1732913256,0.028968893,-0.5483997464,-0.3496703506,-2.7066752911,1.6231896877,-1.3979592323,1.2553751469,-0.0923605114,-0.960264802,-0.6561626196,0.2659901679,0.4081152976,-1.0996562243,0.547524333,0.3487759829,0.8533521295,0.1304494739],"label_name":"BEDANKEN","labels":12},{"embeddings":[1.6053899527,-3.8118851185,-0.7364150882,-1.420959115,1.8952894211,1.1041324139,-0.2465654165,-1.5308312178,-0.0450307056,0.9196932912,0.2465675622,1.1910637617,0.1638994962,1.6407548189,0.6402156949,-0.5109223127,0.7855126858,-0.6341230869,-2.0097651482,1.3209344149,0.2872782946,0.0707583949,0.9268628955,-0.7669158578,-1.2494783401,0.1462224424,0.6315212846,-0.9398101568,0.1964413524,1.5160605907,0.0630050302,0.069548443],"label_name":"RECHTS","labels":9},{"embeddings":[2.1671130657,-0.6063656807,0.1676112711,-0.7494283319,0.4168218672,1.2591785192,-0.8200836778,-1.6192684174,0.4575533867,0.2619988024,-0.1384658515,0.9715071321,-0.0100244824,1.8950389624,0.0371041708,-0.4235801995,0.7970139384,-0.9095663428,-0.6498733163,0.8845460415,0.9525150657,0.8077421784,2.5378949642,-0.8324017525,-1.6816375256,1.1060355902,1.3029261827,-0.2098173797,0.3274749219,1.4734520912,-0.5516585708,0.3207197487],"label_name":"RECHTS","labels":9},{"embeddings":[-1.3029344082,0.7152322531,1.4093639851,-0.3617694676,-2.2093672752,-0.5655220151,-1.6846774817,0.4931447506,0.6806323528,-0.0951443315,1.7534028292,0.5803740621,-0.9984320998,-0.093983829,0.5618700981,-0.36325261,-0.7226852775,-1.2561894655,-2.0247306824,1.5039578676,-1.1744939089,0.7434263229,-0.4710041285,-0.3537274003,0.6538197398,-0.0018092487,0.2000108063,1.4695022106,-0.6743500233,1.0952017307,0.0508924462,-1.1830837727],"label_name":"GOEDENACHT","labels":2},{"embeddings":[-2.078524828,2.2002723217,0.4604895115,1.1946359873,-1.7059197426,-1.1152820587,-1.3556989431,0.1220846027,-0.8614839911,-0.7364472151,-1.6655868292,-0.410888046,1.7704271078,0.9784228802,-0.3585703075,-0.0251320973,0.1910127401,-0.565140903,1.1463466883,-1.4501199722,0.4445797801,-0.0176971629,-1.7172493935,0.64684093,1.3163144588,-1.7217305899,-1.5240149498,1.6001850367,-0.5505430698,-0.4912003279,-0.1593913138,-0.1952040195],"label_name":"SORRY","labels":7},{"embeddings":[1.4691674709,-0.5747481585,0.5203205943,-0.2622934878,0.9602253437,0.4740041792,0.3905122876,-0.201126948,-0.5850197673,0.1621589065,0.7175378203,-0.020257473,-0.33942765,-0.1423997283,0.6274990439,-0.0338622108,-0.8750681281,-0.8640547395,-0.3533247709,1.092607379,-0.2573240697,0.949028194,2.0608606339,-0.863945961,-0.6300590634,1.5351628065,1.6725367308,-0.6707058549,0.9067646265,-0.5313168764,-0.6219599247,0.4633997679],"label_name":"LINKS","labels":13},{"embeddings":[-0.4160581827,0.5845933557,1.9535266161,-0.2068514079,-1.121416688,-0.2947232425,-1.7601288557,0.9395233989,-0.0480217412,-0.0140986405,1.8019497395,0.2733851969,-1.6017118692,-0.2345493734,1.26423347,-0.5928215981,-1.5020126104,-0.9204183817,-1.4859235287,0.7975273728,-1.7001314163,1.0882892609,-0.1502476484,-0.2690781355,-0.142087087,0.6321917176,0.679944396,0.0807211474,0.8918170929,-1.1004066467,0.3023171425,-0.7839923501],"label_name":"NEE","labels":3},{"embeddings":[1.0056402683,-1.4113084078,-0.5928146243,0.104607515,0.99284482,0.2929976285,0.2352526784,0.3638643622,-0.916467905,-0.2268252075,-0.4140824378,-0.1908897161,-0.1394447684,0.0710898489,1.3859001398,0.0197413489,-0.5417346358,-0.3904007971,-0.2498419583,0.2157479078,-1.7040679455,0.0606141761,-0.3587763309,-0.0825056285,-0.1875366271,0.2210161835,0.1738604605,-1.9369773865,1.6674271822,-1.2327809334,0.1932046711,-0.2012812644],"label_name":"SLECHT","labels":4},{"embeddings":[-0.4798736572,-1.1781491041,-0.257606715,0.7354534268,-0.3501226008,1.3404486179,0.0331526883,-1.4610813856,0.9598044157,-1.5932797194,-0.5009811521,0.4435034692,0.0296946671,0.8739877939,-1.0111507177,-0.245675236,2.2740345001,-1.3971350193,-1.7603656054,2.1482577324,0.0263617076,-1.6240254641,0.5703697205,-0.4270652533,0.448690176,-1.2785992622,-0.7802094221,1.1619505882,0.2984057963,0.9571959972,-0.4464937449,-1.6608654261],"label_name":"GOEDEMIDDAG","labels":14},{"embeddings":[-1.260281682,-0.7794718146,1.3428337574,-0.4979516864,-1.4196581841,-0.3860776424,-1.1334964037,0.429315567,-0.2083984017,0.2943966091,1.5350608826,0.6486660838,-0.7973849177,0.0766494125,0.3774951994,0.7084934711,-1.0682548285,-0.6525195837,-2.0671672821,0.4847089648,-0.6815748215,0.9956719279,-0.7087996602,-0.7517391443,0.782472074,-0.3454580605,-0.1722488999,2.4654934406,-1.1900459528,1.0848448277,-0.1747769564,-0.3006069064],"label_name":"GOEDENACHT","labels":2},{"embeddings":[-1.0431996584,-0.8088724613,0.7645891905,0.1788230091,-0.5115479827,-1.0790703297,0.4794172645,1.3242383003,-1.3047479391,0.9459457994,0.5324721336,0.0826597437,0.5644634366,-0.4987143278,1.1637773514,0.9453078508,-1.546569705,-0.7839172482,-0.8877834678,-0.6113809347,-0.9585145712,1.4614646435,-1.2769662142,-0.3263583183,1.5445618629,-0.5038685799,0.1441000104,2.2838625908,-0.8909308314,0.4325480759,-0.2876957655,0.7725775242],"label_name":"GOEDENACHT","labels":2},{"embeddings":[-0.5088537931,0.51207304,1.2121725082,-0.1281433553,-1.4791804552,-0.1463834792,-2.8716180325,-0.4177615643,0.6272329092,-1.0067732334,-0.0325272717,0.6812650561,-0.8307662606,1.2961761951,0.2600431442,-0.4425374568,0.1927269995,-0.5135862231,-1.4437469244,1.0349974632,-0.1758394241,-0.0446187928,-0.4254797101,0.0115100592,0.1627055854,-0.7428570986,-0.3092258573,-0.4944090247,0.0228573829,-0.0653536692,0.2366762459,-1.0824869871],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[0.072434321,-2.4023663998,-0.0952812955,-0.4089530706,0.1090329811,0.1047674119,0.2224729061,0.7112924457,-0.5546315908,0.9475108385,0.9830397367,0.7496472597,0.01906172,0.1927329153,1.2990852594,0.1273088753,-0.53491503,-1.6862586737,-1.9799464941,0.406003058,-1.3853489161,0.9458736777,-0.7064155936,-0.5406856537,0.8847363591,0.1180479601,0.2478861213,1.3158544302,-0.1731136143,1.2377613783,-0.2623122633,0.1887382716],"label_name":"GOEDENACHT","labels":2},{"embeddings":[0.2461067885,-1.1488437653,0.8425289989,-0.1412454396,-0.5431841016,1.5683368444,-1.1973255873,-1.6390361786,1.1260703802,-0.8678498268,0.4319519401,0.9618242383,-0.9660627246,1.4776358604,-0.3987645805,-0.5655292273,1.5814706087,-1.5583684444,-2.2524790764,2.7026803493,0.4181757569,-0.3600820601,1.8159998655,-0.9335685968,-0.338128686,0.1245855168,0.8078721762,0.5525969267,0.045873113,1.3244946003,-0.790381074,-1.2074488401],"label_name":"GOEDEMIDDAG","labels":14},{"embeddings":[-1.8617429733,2.2024168968,0.1034380272,1.072676301,-1.719506979,-1.5404914618,-1.2052679062,0.2804399133,-0.4979322255,-0.4237099588,-1.2442400455,-0.623459518,1.7511968613,0.4428401589,-0.0254212506,0.1357840598,-0.4967883527,-0.8465158939,1.343438983,-1.2690442801,-0.4497126937,0.5240873694,-1.8307653666,0.8452304006,1.4582850933,-1.6205884218,-1.396507144,1.2898863554,0.1110754088,-0.4930150807,-0.1036714166,-0.2817195654],"label_name":"SORRY","labels":7},{"embeddings":[1.9467012882,-1.6509357691,0.5823934674,-1.3366979361,0.7007918358,0.9626652598,-0.7271335721,-0.8937724233,0.4071372151,0.9068394303,0.9162296653,1.2687054873,-1.1670876741,1.4063570499,0.3880507052,-0.7159123421,0.5145077109,-0.107891731,-1.6235102415,0.981690228,0.4857836366,0.6400185227,1.7844486237,-0.740293622,-1.6377754211,1.1448472738,1.3771878481,-1.1516817808,-0.2935738266,1.8958404064,0.2847577333,0.3042603135],"label_name":"RECHTS","labels":9},{"embeddings":[0.3364012837,-2.1715502739,0.516733408,-1.0155180693,-0.2365139574,0.6599988341,-1.0925598145,-1.0078088045,0.8562113047,-0.1780438125,1.0675979853,1.0775924921,-0.8167930245,1.4140529633,0.5276389718,-0.4025237858,0.8203529119,-1.6463665962,-2.9666752815,2.7020423412,-0.562094152,0.4410931468,1.2464838028,-1.1035189629,-0.7293773293,0.4288165867,0.9137125611,-0.2566196918,0.2743513882,1.0775885582,0.0020495988,-0.9991642237],"label_name":"GOEDEMIDDAG","labels":14},{"embeddings":[1.2544176579,-2.4061052799,-1.7094181776,-0.5602628589,1.1911849976,-0.4428007305,1.0402399302,0.2514165044,-0.6167131066,1.0837751627,0.3115618229,0.7428987622,1.7267451286,1.4894328117,0.5764768124,-0.4022051096,-0.7142445445,-0.796890974,-0.8897251487,-0.334949255,-1.3104714155,1.2565374374,0.1557065696,0.0444366485,-0.8628937602,0.4624704421,0.1474160552,-0.2823320329,0.0072553828,0.7667551041,0.147831291,0.4293137491],"label_name":"GOED","labels":1},{"embeddings":[0.8912099004,-3.0620188713,-0.3821283579,-1.0713145733,0.6710837483,-0.4371332824,-0.1006411314,0.5055698156,-0.1155117229,1.0478411913,1.1255310774,0.8139116168,-0.1887963563,0.8359702229,1.3639783859,-0.5182265639,-0.9191358685,-0.6671848893,-2.7228195667,1.0437318087,-1.9959665537,1.2317137718,-0.6026232839,-0.6158717871,-0.4267222583,0.4594137371,0.3416568637,-0.6249595881,0.4166335762,0.0373710617,0.7556945086,-0.3203964829],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[0.4743942618,-1.7031718493,-0.1569562554,0.3894507885,-0.1438532323,0.8335146308,-0.5666239858,-0.321859479,0.0396948904,-0.6435653567,0.1043648124,0.5233063698,-1.0621585846,0.3050976098,1.0000305176,-0.4573661089,0.4668022692,-1.0535582304,-1.619302392,1.494063735,-1.7593199015,-0.747954905,-0.5795633197,-0.1929434091,0.3582180142,-0.0097250137,0.2500526607,-0.9899238348,1.5073467493,-0.285754472,0.1025598347,-1.478857398],"label_name":"SLECHT","labels":4},{"embeddings":[1.5915669203,-2.9613568783,-1.1507827044,-0.9559200406,0.7630559802,-0.3997887075,0.4467016459,0.7924650311,0.1501566768,1.6245458126,0.812430799,0.7349191308,-1.0778509378,0.1939938068,0.7841953635,-0.7178678513,-0.9663185477,0.0278290883,-1.9128540754,0.5489709973,-1.1148663759,1.0323549509,-0.7001283169,-0.342541635,-0.4221321046,0.2760884464,0.484967649,-1.9078671932,-0.0074913427,1.012778759,1.291762948,0.1618231684],"label_name":"NEE","labels":3},{"embeddings":[-0.0651148111,-1.0380442142,0.5341015458,0.3211420178,-0.8644557595,0.3395103514,-1.3242177963,-0.2920624018,0.4352745712,-0.6784830689,0.2797077894,0.3587807715,-1.772634387,0.0544879399,1.0482698679,-0.0262551829,0.1623915434,-0.3741618395,-1.5509874821,1.850004077,-1.2228518724,-0.4645590484,-0.8088877797,-0.4611817598,0.6468991637,-0.5368503332,0.290633142,-0.6176861525,0.9475548267,-0.2678032517,0.4147425294,-1.1663985252],"label_name":"SLECHT","labels":4},{"embeddings":[0.7166922688,-1.1700451374,0.9639645219,-1.7791560888,-1.0759171247,-0.228062585,-2.2789022923,0.1665772796,0.566491127,0.2214944661,1.0382020473,1.0676909685,-1.7013142109,0.759398818,0.8535627723,-0.3031604588,-0.5820178986,-0.379088819,-2.726401329,1.8069357872,-0.7471967936,0.9410249591,0.0592481494,-0.7020041347,-0.2038124949,0.2693387866,0.8577828407,-0.6689642668,0.0970741883,0.484847337,0.688631773,-0.1993905604],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[2.220123291,-2.6785204411,-1.305757165,-1.0514662266,2.1775922775,0.6209470034,0.1607408226,-0.5360367298,-1.2709027529,0.368835181,-0.6211271882,0.4076227248,0.3773144186,1.4612381458,0.7820033431,-0.5589441061,0.0392009541,-0.3631880283,-0.5969539285,-0.1576622576,-1.231970787,-0.3074113429,0.0462996215,-0.0824283957,-0.7880256176,0.4244269431,0.0401692018,-2.4924714565,1.3894356489,-0.5750916004,0.0573258735,0.2581627369],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[-0.21587421,-1.3516356945,0.5524209738,-0.1740070879,-0.7576493621,0.8867078424,-1.4870616198,-1.5666437149,1.1628401279,-0.9246320128,0.3936657906,1.0786594152,-0.8911816478,1.3997597694,-0.0087157823,-0.0393662527,1.2975295782,-1.2949081659,-2.5019650459,2.8615820408,-0.1123642176,-0.3095559478,1.1904606819,-0.8645325303,-0.1283298731,-0.4270812869,0.3134595156,0.5077898502,-0.0167010501,1.5191891193,-0.2071870565,-1.5065186024],"label_name":"GOEDEMIDDAG","labels":14},{"embeddings":[-1.7625840902,2.0559146404,0.292542398,1.1371883154,-1.8160967827,-1.3262921572,-1.6813111305,0.0886906162,-0.592423439,-0.8590291142,-1.4623857737,-0.5569258332,1.2802666426,0.8700170517,0.1784029901,-0.07719744,-0.2249802947,-0.4856469929,0.7911145687,-0.9969341755,-0.582467556,-0.0221751705,-1.8010234833,0.5956750512,1.0196202993,-1.6391065121,-1.5895334482,0.6839348078,0.2229778469,-0.4200064838,-0.013544973,-0.8158524036],"label_name":"SORRY","labels":7},{"embeddings":[1.5445697308,-0.4693396688,0.4305694103,-0.3846929669,-0.5810064673,-0.3483249843,0.2242585123,1.3517341614,0.571524024,0.5910536051,1.6618534327,0.5275133848,-1.8085186481,-0.9528399706,1.1940891743,-0.7395846844,-1.2190755606,-0.7136471272,-1.6592024565,0.7398456931,-2.1290435791,1.0845381021,0.9257856011,-0.0531415716,-0.5492536426,1.2371758223,1.1248112917,-1.4007915258,1.2269438505,-0.579105556,0.2031646669,-0.7815110683],"label_name":"JA","labels":6},{"embeddings":[1.6389485598,-0.170853734,0.1502921283,-0.4472462833,0.2003094852,1.0701014996,-0.24735111,-0.8378197551,1.2454307079,0.5797900558,1.1574287415,1.0844843388,-1.8434940577,0.1347971559,-0.8265996575,-0.9566766024,0.722125411,0.3187887073,-1.0540502071,1.2434408665,1.2703034878,-0.0832130983,2.0246460438,-0.5430378914,-1.7731819153,1.1055644751,1.5111635923,-1.0628029108,-0.4142693579,1.5980186462,0.107065618,0.2894289494],"label_name":"RECHTS","labels":9},{"embeddings":[1.1403560638,-4.1098380089,-0.6202000976,-1.1064268351,1.3402051926,0.9261247516,0.0472226776,-0.6884048581,0.1557905674,0.4625349939,0.5839444995,1.2035065889,-0.8371828794,1.1036987305,1.4083701372,-0.6691137552,0.2860744894,-0.9637956619,-2.5680971146,1.7531601191,-1.3642827272,0.4637821913,0.2637818456,-0.6579229832,-0.9722828269,0.6700131893,0.6353011131,-1.7151747942,0.8264404535,0.6561828852,0.2843305767,-0.6270343661],"label_name":"NEE","labels":3},{"embeddings":[1.1089813709,-1.3958351612,0.8140979409,-1.9622350931,-0.3520599604,-0.2854502499,-1.9494966269,0.2996667624,0.0715947673,0.0165800489,1.0692706108,0.8588443995,-1.5033022165,1.0250867605,1.2176690102,-0.0191406459,-0.9658226967,-0.0821571872,-2.5630736351,1.4803262949,-0.9997004271,1.0747998953,0.2013383061,-0.8694177866,-0.7005875707,0.4870954752,0.6808624864,-1.2341496944,0.2599333823,0.1311502159,0.9218999743,0.2233204842],"label_name":"BEDANKEN","labels":12},{"embeddings":[1.5657904148,-2.6827685833,-1.3753038645,-1.25938797,1.4512343407,-0.5891268849,0.4921979308,0.0189354271,-0.3966706693,1.2718749046,0.5033837557,0.8575664759,1.0207189322,1.2438781261,0.5537702441,-0.5068078637,-0.7169360518,-0.5594445467,-1.2874451876,-0.3171745837,-0.9548820257,1.1352341175,-0.3741486073,-0.2597293258,-1.2844592333,0.4799630642,0.2946079969,-0.9451255798,0.1118123606,0.8259338737,0.5742548704,0.5859423876],"label_name":"GOED","labels":1},{"embeddings":[1.5998668671,-1.8658026457,-0.1591380835,-1.2780119181,0.0718723461,0.7909062505,-0.7484935522,-1.190377593,0.4076903462,0.5676837564,0.9088472724,1.5879803896,0.0085696038,1.8571665287,0.1966472864,-0.7543110847,0.8979917169,-1.3458939791,-2.2001562119,1.6964336634,0.1262186319,0.760637641,1.7282323837,-0.7436805964,-1.1800928116,0.8808904886,1.2675815821,-0.0408998206,-0.0777712688,1.9903259277,-0.2986646593,-0.1190204024],"label_name":"RECHTS","labels":9},{"embeddings":[1.3561753035,-0.842985034,0.5104580522,-0.5276412368,0.1959199309,1.44297719,-0.3272622526,-1.6664931774,1.2377128601,0.2957341373,0.3892049789,1.0439832211,-1.7069164515,0.5254795551,-0.8299131989,-0.8289862275,1.304926753,0.2319044471,-1.2180280685,1.0768964291,1.7534152269,-0.6538850069,1.9610950947,-0.9308578968,-1.3475677967,0.52741611,1.1772116423,-1.1173064709,-0.2154909372,1.2561564445,-0.0460013784,-0.3219682574],"label_name":"RECHTS","labels":9},{"embeddings":[-1.1011271477,-0.9772579074,0.4372953176,-0.0375392064,-0.6953413486,0.6525155306,-0.9474647641,-1.9033193588,1.4673746824,-0.807936728,-0.2916262448,0.5818560719,-0.5774801373,1.4798152447,-0.9682897925,-0.3382734954,1.5348273516,-0.4459248185,-1.7372151613,2.2572245598,0.7349085808,-1.1088947058,0.5545724034,-1.1614643335,-0.1615347415,-1.264236331,-0.5577474833,0.7088924646,-0.0744316652,1.3468053341,0.261885345,-1.1104273796],"label_name":"SALUUT","labels":11},{"embeddings":[1.4795876741,-2.9103522301,-1.7496556044,-0.7885714173,1.9387037754,-0.5591660738,0.9371461868,-0.0044636577,-0.8651897907,0.7869836688,-0.1680927724,0.4782199562,0.9157057405,1.4550819397,0.7197988629,-0.5402700901,-0.547226429,-0.5219038725,-0.7820299864,-0.3578692675,-1.3540779352,1.4640241861,-0.3384414315,-0.4092158079,-0.7800979018,0.4261341989,-0.2759478092,-1.6496565342,0.5561407208,0.3870562613,0.7022271752,-0.1613363624],"label_name":"GOED","labels":1},{"embeddings":[0.6700725555,-1.1030521393,-1.3583703041,-0.2083732933,0.6080118418,-0.5067856312,1.2031553984,0.3405390382,-0.527918756,1.04340446,0.2770016789,0.2936190069,1.6203914881,0.731508255,0.31095469,0.2304055989,-0.6295539141,-0.760961175,-0.1220219508,-0.7210428119,-0.6255012751,1.9364870787,0.1654086262,-0.3144241571,-0.4955208898,0.4201510847,0.0521643981,0.9124310017,-0.5413686037,1.0867993832,0.1238919795,0.6456818581],"label_name":"GOED","labels":1},{"embeddings":[1.8271304369,-2.0491833687,0.1008049771,-1.3365439177,1.3281106949,0.2430131286,-0.8158917427,-0.6723228693,-0.647152245,0.1175522208,-0.4211879373,0.5793644786,-1.0769895315,1.3748207092,0.991832912,0.0127168223,-0.4503854215,-0.1338804364,-1.145118475,0.5737627149,-0.4069696963,0.370641768,0.8204607368,-0.6597849727,-1.3842436075,0.5157709718,0.6669888496,-2.1849629879,1.2726441622,-0.5237670541,-0.2870216966,0.4971405566],"label_name":"SMAKELIJK","labels":8},{"embeddings":[-2.811081171,2.4711549282,1.0246320963,1.3739321232,-1.8293194771,-1.0736197233,-0.9905291796,0.2271899581,-0.4397520423,-1.0528008938,-1.123080492,-0.8490032554,1.0850070715,0.3209899068,-0.4311739802,0.2746550441,-0.457126081,-0.5702827573,1.2310891151,-1.0086804628,0.0125373751,-0.2558607161,-1.5596369505,0.4848678112,1.8149521351,-2.072437048,-1.4423098564,2.1574242115,-0.539619565,-0.2820991874,-0.3516949713,-0.0113413623],"label_name":"SORRY","labels":7},{"embeddings":[-0.9189520478,-0.4253560901,0.4321053624,0.4651253819,-0.290379405,1.3499567509,0.2496159971,-1.960824728,1.3510626554,-1.3531008959,-0.0929327905,0.0640316084,-1.0858561993,0.0131899677,-1.9354071617,-0.55697155,2.3759455681,0.2271006703,-1.4266629219,1.8726365566,1.3910938501,-2.3071024418,0.9135907292,-0.9865869284,-0.098341614,-0.7898700237,-0.0874472633,0.2449969947,-0.0631339476,0.8954271674,-0.0524779223,-1.4427088499],"label_name":"SALUUT","labels":11},{"embeddings":[0.8279601336,-3.8312528133,-1.3764404058,-0.8079349995,1.2959953547,-0.3025415838,0.5930716991,-0.0231782347,-0.4659243822,1.0063079596,0.3615587056,0.6756053567,0.1422905922,0.4741036892,1.0598697662,-0.2027668357,-0.1675073504,-0.4681994915,-2.0264201164,0.3856253624,-1.5247198343,0.5505365729,-1.867284894,-0.1593502462,0.2130084634,-0.6136506796,-0.1257476211,-1.1753562689,0.4159092009,0.4246229827,0.7986581326,-0.2394164205],"label_name":"NEE","labels":3},{"embeddings":[0.8555717468,-3.1136994362,-0.8806211352,-0.5354878306,1.2817145586,-0.4474779069,0.6785437465,0.1870979518,-0.5301758051,0.6628031135,0.6150060892,0.4034002125,0.1112184152,0.9250500798,0.8766428828,-0.4194190502,-0.3780352473,-0.8710180521,-1.6860913038,0.6197763085,-1.8411655426,1.1708102226,-0.5469404459,-0.5120323896,-0.3758557439,0.445241183,-0.1283111572,-1.5645810366,1.0301966667,0.0423752591,0.5453941822,-0.3995986879],"label_name":"GOED","labels":1},{"embeddings":[2.1377687454,-1.1484495401,-0.124267973,-1.1156302691,0.2952097058,0.5743851066,-0.3876443505,-0.0534146875,0.7969687581,1.2749215364,1.3785524368,1.4362602234,-0.9461361766,0.6595677137,0.1647454351,-0.884163022,0.2617510855,-0.476128757,-1.6112221479,0.651322186,0.1708343327,0.6711580157,1.5137746334,-0.5568677187,-1.6985924244,1.1974728107,1.4352208376,-1.1775556803,-0.119211562,1.6222896576,0.4014507532,-0.0523312688],"label_name":"RECHTS","labels":9},{"embeddings":[0.4680483341,-1.7780770063,0.8508812785,-0.3904982507,-0.2894155383,1.4261585474,-1.0845602751,-0.9998556972,1.1687487364,-0.5975102186,1.1435158253,1.143892169,-1.4461317062,1.0863742828,0.2831650078,-0.4887859821,1.2212063074,-1.5758671761,-2.5936470032,2.7428584099,-0.229329437,-0.389603436,1.7350695133,-1.2043156624,-0.7421538234,0.3029466569,0.8612282872,-0.0834050998,0.2030391395,0.8227552176,-0.3548989296,-1.1460231543],"label_name":"GOEDEMIDDAG","labels":14},{"embeddings":[0.2901828587,-0.395108819,1.383400321,-0.6304724813,-0.8955520391,1.1806876659,-1.5365905762,-0.4503076077,1.0759688616,-1.3568353653,0.7676076889,0.455198735,-2.8536875248,-0.2380567491,-0.4117926657,-0.0724226162,0.8584230542,-0.4356083274,-1.9570533037,2.5025844574,0.2932230234,-1.4309936762,1.5563232899,-0.7692012191,-0.1620441526,0.4942698479,1.0286616087,-0.7017740607,0.4634580314,0.3952507079,-0.5866600871,-0.6587221622],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[1.7605428696,-2.4260087013,-1.482431531,-0.548671782,1.5475426912,-0.4385904372,0.8592748046,0.0813936144,-0.9069672823,0.6734924912,-0.1026928276,0.5630794168,1.9087303877,1.4436627626,1.0650987625,-0.4969312251,-0.5896536112,-1.3249261379,-0.8278877735,-0.6708358526,-1.9167151451,1.2404854298,-0.0132331997,-0.000243634,-0.9424806237,0.7463270426,0.1446157694,-0.6173071861,0.8917159438,-0.0435415134,-0.0014652573,-0.0961826444],"label_name":"JA","labels":6},{"embeddings":[1.9912821054,-0.9989757538,0.6975376606,-1.2568616867,0.4870985746,0.3428549469,-1.2184873819,-0.0996937007,-0.6338102221,0.0457255878,0.1066929996,0.4981256425,-1.0048042536,0.8749547601,1.5036081076,-0.3256342113,-1.0640192032,-0.5225778818,-0.8911327124,0.5106431842,-0.8217747808,0.8569199443,1.411318779,-0.7829915285,-1.0065386295,1.1871727705,1.1058954,-1.6956993341,1.3258136511,-0.4377182126,-0.2559981942,0.730425477],"label_name":"SMAKELIJK","labels":8},{"embeddings":[0.7982581854,-1.1113966703,1.2511035204,-1.4396328926,-0.8462084532,-0.1019179374,-2.1697990894,-0.1450117379,0.781026721,-0.2349323034,0.8821247816,1.1793586016,-2.4031944275,0.7766382694,0.8944439292,-0.2271891832,-0.1692965031,-0.0545699522,-2.5937144756,2.108455658,-0.4777494669,0.2054370046,0.9648528099,-1.0122613907,-0.3160938025,0.3378894925,0.8341205716,-1.0365093946,0.4853925407,0.3781219423,0.4111597538,0.0337696075],"label_name":"BEDANKEN","labels":12},{"embeddings":[-0.2347139567,-1.2881046534,0.6248508096,0.3108128011,-0.3003144562,1.3436903954,-0.476213783,-1.7415895462,1.4037806988,-0.6367880106,0.4067997336,0.5973840356,-1.6554762125,0.4223738611,-0.9898761511,-0.3686188161,1.6296092272,0.4741703272,-1.780315876,1.8760750294,0.7254971266,-1.9289085865,0.559982121,-1.0559632778,-0.1119010597,-0.556374073,0.0524869263,-0.1953140199,-0.1637656987,0.8267508149,0.4548651278,-1.587279439],"label_name":"SALUUT","labels":11},{"embeddings":[-0.1076109558,-1.106996417,0.6254186034,-0.0358493403,0.0114704724,1.3642106056,-0.7031056881,-1.6063666344,1.6965368986,-0.597545445,0.9163026214,0.6822523475,-1.5991169214,0.0116337501,-1.2434831858,-0.4515008628,1.7109724283,0.5731452703,-1.8520945311,1.9171446562,1.2969176769,-2.0864591599,0.7654111981,-1.2839428186,-0.4784918427,-0.4935276806,0.306881249,-0.4096702337,-0.3388717473,0.8192034364,0.4934841096,-1.157346487],"label_name":"SALUUT","labels":11},{"embeddings":[-0.0594669431,0.2342664152,0.9441397786,-0.3850688338,-1.4267008305,-0.9729154706,-1.7117189169,0.6885328293,-0.0841129795,0.2695682645,1.0817859173,0.9009469151,0.0670971274,0.9103481174,1.5640919209,-0.6222720742,-1.3498553038,-1.3355398178,-1.844362855,0.6333813071,-1.6882579327,1.8992279768,0.0972958356,-0.0482391864,0.0564546473,0.6765743494,0.4970834851,0.5886451006,0.2460167706,0.6470917463,0.4193798304,-0.4276686907],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[1.9672827721,0.1150698215,0.1954622269,-0.663910985,0.0303714629,0.6517217159,-0.5478231907,-1.0542854071,0.4115178585,0.0564169772,0.4895731807,0.9827528596,-0.2493106276,1.428172946,-0.5992714763,-0.4680002034,0.3313647211,-0.8691290617,-0.3663966656,0.7870158553,1.0555756092,0.9717034698,2.7810573578,-0.567563653,-1.4148612022,1.5038949251,1.2877318859,0.3690710962,-0.5861331224,1.431496501,-0.4870097637,0.4971293211],"label_name":"RECHTS","labels":9},{"embeddings":[0.9114455581,-1.5156943798,-1.7687946558,-0.6280976534,1.2583265305,-0.6720610261,1.1320132017,0.3209421039,-0.7958257198,0.9991816878,0.1347908825,0.3156915903,1.8989614248,1.1632860899,0.3997282088,0.2870483696,-0.7552466989,-0.4197814465,-0.3465972245,-0.809093833,-0.9322807789,1.5676867962,-0.4551707506,-0.0746059418,-0.2877568007,0.331897229,-0.1900188327,0.8697679043,-0.5101428628,1.1903995275,0.138152048,0.6283803582],"label_name":"GOED","labels":1},{"embeddings":[1.6427285671,-3.0611360073,-1.5585814714,-0.6547477245,2.6028280258,-0.294729054,0.9421572089,-0.16912283,-1.5022732019,0.289564997,-0.7270693779,-0.0097526684,1.3834217787,1.212801218,0.9925946593,-0.5177117586,-0.3613036573,-0.1895712614,-0.4523590207,-0.4430740476,-1.3687995672,0.4516216516,-0.593061626,-0.2052664012,-0.6131491065,0.1785864532,-0.0885051861,-2.0601005554,0.9082585573,-0.704031229,0.4506321847,0.1279117316],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[0.6617440581,-1.3355093002,0.8097417951,-1.087381959,-0.6839312315,0.643155992,-1.8485714197,-0.7206698656,0.8707331419,-0.5790708065,0.4083092213,1.1386288404,-1.9317117929,1.1345117092,0.0441398732,0.073172234,0.9794842601,-0.7469453216,-2.1761453152,1.8139172792,0.3291388154,0.0016915649,1.2758204937,-0.9755692482,-0.716824472,-0.0738666281,0.6958972216,-0.3356342316,0.3581828475,1.0343232155,-0.1718677878,0.2613447309],"label_name":"SMAKELIJK","labels":8},{"embeddings":[-0.7752486467,0.1413311511,1.5549174547,-0.5388780832,-1.6105420589,-0.4251005948,-2.9376447201,-0.166236341,0.5903831124,-0.7429352403,0.1280288398,0.6098408699,-1.3994139433,0.9825886488,0.3193300068,-0.255797565,-0.2076788843,-0.3077679276,-1.7022913694,1.360850215,-0.2790775895,0.0018076822,-0.5481382608,-0.5600588322,0.3248047531,-0.7700229883,-0.4597753286,-0.3643617034,-0.3541488349,0.1374767125,0.8442318439,-0.4763315022],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[0.0977350622,-2.1497447491,0.0925678834,0.0766337141,0.1099822745,1.484454751,-0.2210755646,-1.8195297718,1.3553290367,-1.1244431734,-0.1042317748,0.9088995457,-0.6598368287,1.1650276184,-1.007101655,-0.1963579357,2.5102977753,-1.009508729,-2.5320529938,2.3569414616,0.2588658333,-1.6607667208,1.0366694927,-1.0016676188,-0.4829702973,-0.4636674225,0.2054647207,0.1162196472,0.334770292,1.1684942245,-0.3513652086,-1.7282105684],"label_name":"GOEDEMIDDAG","labels":14},{"embeddings":[1.1984665394,-3.2183291912,0.0442480817,-1.4980452061,0.8216492534,-0.3670753539,-0.7161800265,0.1484896988,-0.2329840958,0.9708798528,0.7362258434,0.9576665759,-0.4087621272,1.1423784494,1.3768670559,-0.3596215248,-0.8263576031,-0.5410223007,-2.6981532574,1.1620111465,-1.8675398827,1.1403536797,-0.4657720327,-0.7061643004,-0.7125753164,0.1935228407,0.5233812928,-1.4587410688,0.6379209757,0.093553029,0.8340163231,-0.0573077798],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[1.2365829945,-2.7152502537,0.1053636447,-1.6160224676,0.797524929,0.2369288653,-0.8510378599,-0.2656186819,-0.2864488661,0.8818004727,0.6769018173,1.3061220646,-0.5221985579,1.4946894646,1.3611438274,-0.5803503394,-0.6000036001,-0.9662269354,-2.2582988739,1.4078520536,-1.0596250296,1.0007442236,0.4932251573,-0.8389053345,-0.8365634084,0.6758910418,0.8142892718,-0.9444531202,0.5351159573,0.6770862341,0.5257074833,0.0608248115],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[-0.667726934,-0.468890667,0.6330350637,0.1235800907,-0.0055421535,0.7808289528,0.044512976,-1.9603662491,1.5335441828,-0.4420033693,0.6207444668,0.3159079254,-1.5590788126,0.1536081731,-1.7635641098,-0.5352234244,1.4640536308,0.7332783341,-1.2495783567,1.5146131516,1.6519066095,-1.3840923309,0.9565122724,-1.3252843618,-0.3348338604,-0.5504606962,0.1266429722,-0.0558082089,-0.7622789145,1.1109719276,0.2832546234,-0.6279986501],"label_name":"SALUUT","labels":11},{"embeddings":[1.5631536245,-3.4887783527,-1.0676620007,-1.2911491394,2.0570595264,0.1603160948,-0.0418555699,-0.2460096925,-1.2865945101,0.7571195364,-0.5394097567,0.4590606987,1.3613212109,1.968691349,1.0209276676,0.0792708322,-0.1838067174,-0.9198367,-0.9729639888,-0.1101716161,-0.9473152757,0.4628754258,-0.4921404123,-0.5028130412,-0.9762484431,-0.2002860904,-0.0509788319,-1.286765933,0.6659519672,-0.0647727773,-0.0242690258,0.7460544109],"label_name":"SMAKELIJK","labels":8},{"embeddings":[-1.6768126488,0.5061770678,0.6585043073,0.9661487341,-1.2391501665,0.2585721612,-1.0202310085,-1.2142429352,-0.071059294,-1.2053202391,-0.8014341593,0.0988216624,0.8099890351,1.1914350986,-1.0790899992,0.3061358333,1.6221865416,-1.889980793,-0.7076405883,1.0228408575,0.5539466739,-0.7458346486,0.295514226,-0.3908412457,0.756572783,-1.3460725546,-0.7132747173,2.5114202499,-0.5404971242,1.2962355614,-1.2796251774,-0.4738515913],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[1.3653607368,-1.7878774405,0.5105116367,-1.6833900213,-0.0277916733,0.7068427205,-1.667752862,-1.1168513298,0.5572106242,-0.3163228631,0.5542266369,1.3310258389,-0.7010017037,1.7089111805,0.6709245443,-0.1123980135,0.4684494436,-1.2271207571,-2.5561132431,1.7783764601,-0.1547897756,0.4412565827,1.6253478527,-1.0970145464,-1.0571122169,0.8690849543,1.0443731546,-0.2429617047,0.6171476245,1.2152893543,-0.3166344166,-0.1680170298],"label_name":"BEDANKEN","labels":12},{"embeddings":[1.6767098904,-3.1501340866,-1.6364593506,-0.7062250972,2.2407751083,0.2332556993,0.7031983733,-0.3850318193,-1.3209693432,0.5949185491,-1.0277783871,0.0900581703,1.0122361183,1.5704532862,0.9354844093,-0.201418221,0.0153928921,-0.146145016,-0.5456399322,-0.5061003566,-0.9543356895,0.1160464808,-0.4307586551,-0.3308952451,-0.8671659231,-0.1103540584,-0.0655200556,-1.7177832127,0.8654662371,-0.1019477025,0.1075145006,0.0711694062],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[1.5347409248,-3.1490442753,-1.0232864618,-1.0826941729,0.9619139433,-0.2528872788,0.5991671085,0.3659200668,0.0139308348,1.233958602,0.8740362525,0.8240023255,-0.448068738,0.3851770163,1.7345887423,-0.5234130025,-0.5621760488,-0.2610932589,-1.8926643133,0.4025318325,-2.2486848831,1.3688559532,-0.6081578135,-0.1376804262,-0.6172806025,0.526941061,0.3610912263,-1.8746702671,0.6377168298,0.2543975115,0.8914221525,-0.4909898639],"label_name":"NEE","labels":3},{"embeddings":[1.5648431778,-3.8501160145,-1.6873595715,-0.7093840241,2.033623457,0.018774597,0.7907653451,-0.1153388172,-0.6880719662,0.6416109204,0.2798525691,0.6331602335,0.6229249835,1.0394937992,0.9563648105,-0.5586287379,-0.0674760118,-0.8870567679,-1.649181962,0.3998440206,-1.8096290827,0.6925727725,-0.6709136367,-0.2074162215,-0.3379349709,0.4419163167,0.0945184454,-1.8080130816,0.7120165825,0.0632908121,0.6100639105,-0.823141098],"label_name":"GOED","labels":1},{"embeddings":[0.3543048501,-1.5687087774,0.8397532701,-1.5218403339,-0.7593782544,-0.6359201074,-1.4431498051,0.3415755033,0.1820482016,0.3011804521,1.4149514437,0.8870592117,-1.4344265461,0.3849734366,1.215867877,0.2743439674,-0.9565507174,-0.0730218813,-2.8231444359,2.0138275623,-1.3147774935,1.4893740416,-0.4295045137,-1.0213509798,-0.2540479004,0.0627216175,0.2912478447,-0.616153419,0.0571547225,-0.0290767029,1.2696412802,-0.4202666581],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[-1.3163392544,1.4408937693,0.645837009,0.7142480016,-1.4702106714,-0.1199409515,-1.5537831783,-1.0099899769,-0.214561224,-1.6228724718,-1.3863587379,-0.1259550452,1.2332596779,1.6166808605,-1.0687391758,0.0652473494,1.2579544783,-1.7126177549,-0.1523700356,0.7832124233,0.9382990003,-0.3782668114,0.4156886339,-0.1772711724,0.4963117242,-1.1754750013,-0.9457534552,2.0202043056,-0.4208409786,0.1493668258,-1.3727325201,-0.6732714772],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[-0.9263313413,-0.749479413,0.631257534,0.4451532364,-0.5518378019,0.9701091647,-0.4150764346,-2.0715594292,1.2244977951,-0.8271479011,-0.1308416873,0.5685043931,-0.1904838681,0.9602401257,-1.2133431435,-0.3429995179,2.1234326363,-0.3584356606,-1.5717340708,1.9817835093,0.5957908034,-1.9415148497,0.4970135093,-0.9648871422,-0.2080916017,-1.3046771288,-0.3553020358,0.4995210171,-0.1867502928,1.1574349403,-0.0562605523,-1.4859803915],"label_name":"SALUUT","labels":11},{"embeddings":[-0.1064022779,1.483520627,1.3915089369,0.2841564119,-0.6413732767,0.659224987,-2.6739609241,-0.6292272806,-0.3376676738,-1.2474194765,-0.980260253,0.4705211818,0.3887449205,1.5087308884,-0.2690548301,-0.2463541329,0.7247659564,-0.3274093866,0.1424213946,0.6333227158,1.0686956644,-0.249823153,0.5249879956,0.0106081516,-0.1826972514,-0.3958419859,-0.0469712541,0.0860985741,-0.2001604736,-0.1186322644,-0.6813026071,-0.673756361],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[1.0317053795,-1.9131826162,1.0893157721,-1.6546188593,-0.2209107131,0.0502172559,-1.9069620371,-0.3926337957,0.3004898131,0.5112013221,1.1173307896,1.2949439287,-1.2513762712,1.2244240046,1.066473484,-0.2044398785,-0.5400593281,-0.5240037441,-2.6913948059,1.8835792542,-0.8004854918,0.9323740602,0.5205458403,-0.9052911997,-1.0199213028,0.3907800615,0.889876008,-0.861895442,0.3344128132,0.5396119356,0.3830939829,-0.1220623553],"label_name":"BEDANKEN","labels":12},{"embeddings":[2.4191019535,1.413959384,-0.2192221582,-0.3468822539,-0.3511198163,-0.0524206161,0.0691416413,0.2834867835,0.1910281181,0.4783236086,0.5309274197,0.8242455721,0.2174420208,0.682269454,-0.1891919374,-0.7266844511,-0.5628507733,-0.4679184556,0.7851893306,-0.9199690819,0.3076860011,1.5056380033,2.0014150143,-0.1862403005,-1.4299595356,2.1113605499,0.9686152935,-0.284111768,-0.4168307483,0.6782062054,-0.0990892053,0.7281214595],"label_name":"RECHTS","labels":9},{"embeddings":[2.2900192738,0.6369414926,0.1616233885,-0.9217720032,-0.3460924923,0.1108873785,-0.3078722358,0.1810605973,0.3688078523,0.3192056417,0.8708406687,1.2795864344,0.06916859,0.8676925302,-0.3752496839,-0.4462328851,-0.4556798339,-0.6757531762,-0.582431972,-0.0127787106,-0.1797136813,1.2164378166,2.0831594467,-0.3436460495,-1.5243231058,1.5353409052,1.2065116167,0.2996192575,-0.2136036158,1.0108761787,-0.2601542771,0.2309935689],"label_name":"RECHTS","labels":9},{"embeddings":[0.7150757313,-4.4200463295,-1.2330749035,-1.0002385378,1.8215142488,0.1766215116,0.7718030214,-0.0805350691,-0.7104004622,1.008228898,0.1447851658,0.7486588955,0.2330764681,0.9484858513,1.4824597836,-0.3870480359,-0.0029081628,-0.6616838574,-2.050942421,0.4887721539,-1.4632765055,0.1914951503,-1.2982956171,-0.4768328071,-0.0940843225,-0.3290350735,0.162276566,-1.3214616776,0.4362189472,0.422128886,0.766882658,0.1370538473],"label_name":"NEE","labels":3},{"embeddings":[2.011752367,-2.1285853386,-1.0509575605,-0.4910706878,1.4949600697,-0.3038480878,0.8258503079,0.7789233327,-0.8052885532,0.5373025537,0.3623917401,0.373809427,0.9365975261,0.8969854712,1.3235875368,-0.3719996512,-0.6235597134,-1.0689866543,-1.1644154787,-0.2135006785,-2.0972690582,1.352284193,0.1150758713,0.1456894726,-0.7772784829,0.8671292067,0.4361795187,-1.5626528263,1.2595853806,-0.8216290474,0.0236920156,-0.4009577036],"label_name":"JA","labels":6},{"embeddings":[1.1393492222,-2.2124724388,0.2548405528,-2.1515817642,0.2958961129,-0.3040580451,-1.3645579815,-0.523938477,-0.1420322657,0.4660367072,0.3816045225,0.9270313382,-0.4180254638,1.7177773714,0.9980016351,0.1764137745,-0.5734149814,-0.1200430915,-2.0800180435,0.8619081378,-0.7815243006,1.0432915688,0.0584607273,-0.8064701557,-0.9134293199,0.0525528565,0.3655392528,-0.7789729834,0.3720983863,0.593931973,0.5476720929,0.5295277834],"label_name":"SMAKELIJK","labels":8},{"embeddings":[-1.2507271767,-0.617872417,1.3602149487,-0.1280548424,-1.2210828066,-0.1509277076,-0.8064951897,0.064544946,0.3046652377,0.2613224387,1.9954609871,0.6189518571,-1.1910539865,-0.675193429,0.5918149948,-0.0043260381,0.0354016796,-1.4667882919,-2.692481041,1.5978206396,-0.9244478345,0.0023591146,-0.4183418751,-0.667275548,0.966696918,-0.0461339429,0.2044991851,1.9643269777,-0.8652048111,0.5548508763,-0.3414876461,-1.1840112209],"label_name":"GOEDENACHT","labels":2},{"embeddings":[0.0799331367,-0.9394229054,0.7811260223,0.1653629988,-0.3109187782,1.8212449551,-1.015530467,-1.8266977072,1.1842195988,-1.2082058191,-0.1027207375,0.7323434949,-1.1176354885,1.1877067089,-0.7529739141,-0.2126215696,2.0287401676,-1.5234736204,-1.7772960663,2.9229078293,0.9863626957,-0.9558600783,1.810791254,-0.8360787034,-0.4356257319,-0.3646596968,0.4336875379,0.2790612876,0.2486412525,1.0735661983,-0.9563201666,-1.4935671091],"label_name":"GOEDEMIDDAG","labels":14},{"embeddings":[-0.461781621,-0.6635539532,1.2727555037,-1.3214204311,-1.5888559818,-0.3400017023,-2.278387785,0.1841010898,1.0439027548,-0.491679877,1.4755786657,0.6322336793,-1.9740203619,0.1927975416,0.2832971513,0.1655856669,-0.473000735,-0.0402129218,-2.8584775925,2.1115992069,-0.7851530313,0.2268613577,-0.6268841624,-0.6561439037,0.3518068194,-0.1558756232,0.1946249604,-0.0644080564,-0.2924818397,0.4478391707,1.15100348,-0.6151875257],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[0.7327497602,-2.0994808674,0.9007805586,-1.4919147491,-0.5591157675,0.5028833747,-1.2215758562,-0.2387561649,0.9588532448,-0.0067465194,1.5389745235,1.3981770277,-1.916233182,0.6229615808,0.4380166233,-0.4421450794,0.1685298681,-0.9460998178,-3.2333426476,2.6102561951,-0.9714308381,0.1957556605,0.9532073736,-1.1708009243,-0.4028735161,0.3312188089,0.7879101038,-0.6174192429,-0.0444572791,0.7335267663,0.5145636201,-0.4705931842],"label_name":"GOEDEMORGEN","labels":5},{"embeddings":[1.8713225126,-2.4141385555,-0.2711114585,-1.4762134552,0.5892920494,0.8050827384,-0.7950384021,-0.7711595893,0.2242899537,0.8721539974,0.8032122254,1.4865745306,-0.0342564806,1.7933046818,0.644359231,-0.7447586656,0.5735035539,-1.318236351,-2.1820650101,1.3022074699,-0.3246715665,0.5307074785,1.0395573378,-0.6504569054,-1.5399173498,0.942774415,1.0061672926,-0.9840686321,0.0565903708,1.6750965118,0.107054323,-0.3656654954],"label_name":"RECHTS","labels":9},{"embeddings":[2.1066701412,-1.4694904089,-0.7656716704,-1.1011446714,0.6839277744,-0.1392919868,0.3851031661,0.7299112678,0.2608380318,1.2289838791,0.815828979,0.8947069049,-1.2885531187,-0.0230190642,0.6241721511,-1.3312451839,-0.16841501,0.5843185782,-0.9270589948,-0.5478476882,-0.5234279633,0.2869252563,0.5103096962,-0.0131230652,-1.3498039246,1.4262363911,1.0782004595,-2.9290893078,0.4700137675,0.7045129538,0.9970371127,0.1721162945],"label_name":"NEE","labels":3},{"embeddings":[2.0272862911,-0.2919104099,0.3989092112,-0.2196819633,0.0598203763,0.4211632311,0.3630975485,0.6417626739,0.276786387,0.0579316206,1.2892317772,0.3495110571,-1.8838368654,-0.613725245,0.8388839364,-0.2376483381,-0.5134657025,-0.7225244641,-1.1475030184,0.6673973203,-1.9390729666,0.5535754561,1.6685245037,-0.0448965132,-0.7467417121,1.6715735197,1.1125398874,-1.5057201385,1.8066684008,-1.0367511511,-0.4218322337,-0.8418801427],"label_name":"JA","labels":6},{"embeddings":[1.9232261181,-2.9881803989,-1.0392811298,-0.7659660578,2.1892302036,0.7125504017,-0.034054812,-1.1407188177,-1.1462150812,0.2078772783,-0.8810620308,0.3880327344,0.736948669,1.7506260872,1.0824195147,-0.3775083423,0.1936951578,-0.4480980933,-0.7193272114,0.2753172815,-0.8148771524,-0.2214242518,-0.041581884,-0.5125843287,-1.0322654247,0.2631525099,0.2164177895,-2.0609145164,1.1665198803,-0.3626940548,-0.1534637511,0.3004137576],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[1.4815731049,-0.7080050707,-0.000664033,-0.2855625153,1.0831702948,1.0639659166,0.4035166204,-0.5837698579,-0.1860634685,-0.2799884677,0.4815603495,0.2653966546,-0.6949570775,0.0714109242,0.267480582,-0.3550526798,-0.2410364449,-0.7533734441,-0.3883480728,1.294680953,0.2047913373,0.284232527,2.5587909222,-0.8354819417,-0.9969819188,1.3504680395,1.5499817133,-0.6940696239,0.8739279509,-0.316678077,-0.9353868961,0.2350141704],"label_name":"LINKS","labels":13},{"embeddings":[-2.0611252785,1.4910336733,0.7243439555,1.3990586996,-1.5999298096,-0.1396510601,-1.1657505035,-0.9554670453,-0.1722370386,-1.4244271517,-1.4238808155,-0.5647466183,0.7702129483,0.8231929541,-0.3037793338,0.2781998813,0.781394124,-0.7362897396,0.3203444183,0.3984464705,0.1062378585,-0.5592203736,-0.8458194733,0.227444008,1.4425492287,-2.0862152576,-1.3279838562,1.761952281,-0.0392179117,-0.0713498294,-0.609449029,-1.038606286],"label_name":"SORRY","labels":7},{"embeddings":[-2.1463317871,2.2787482738,0.2828021646,1.349326849,-1.8990309238,-1.1486501694,-1.1497349739,0.2686442733,-0.6706218719,-0.9031828642,-1.3418040276,-0.7469679713,1.4595634937,0.6909826994,-0.1710053086,0.0822892711,-0.0737196729,-0.7571897507,1.3004468679,-0.9880854487,-0.1314745992,-0.0707284883,-1.737863183,0.7552682161,1.6242688894,-1.8734455109,-1.5855828524,1.6677695513,-0.4270348847,-0.3339511454,-0.2978926897,-0.0570014119],"label_name":"SORRY","labels":7},{"embeddings":[0.2752947807,-1.2264016867,0.961399138,-0.8327803016,-0.8041260242,0.9538612366,-1.4132641554,-0.9569568038,1.246773243,-0.6090918183,0.517662406,1.1383156776,-2.054110527,0.8563326597,0.0660019666,-0.1764167547,0.7400695682,-0.7481872439,-2.7120091915,2.7345743179,-0.3113714457,-0.5064353347,1.3037714958,-0.8166549206,-0.0189448111,0.0075350162,0.5164452195,-0.4660737514,0.7499424219,0.8188574314,0.2936993837,-1.0006463528],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[1.5228230953,-2.9986526966,-1.4515668154,-0.6937122941,2.3954870701,-0.3253533244,0.8432660699,-0.1064103991,-1.4293833971,0.5987090468,-0.3441489935,0.4422238767,1.5194815397,1.4533766508,0.96008569,-0.511348784,-0.5564262867,-0.3903594911,-0.5484102368,-0.506890595,-1.4758154154,0.716434598,-0.6161976457,-0.1452332884,-0.7021009326,0.3392807841,-0.2604466677,-1.9043900967,0.7719162107,-0.6385600567,0.3918694556,0.2419649959],"label_name":"TOT-ZIENS","labels":0},{"embeddings":[0.5041852593,-1.0193021297,1.3757001162,-1.2275713682,-1.1281369925,-0.2442056686,-1.8131371737,0.3172206879,0.8375633359,-0.3756369352,1.6238641739,0.9096524119,-2.5898473263,0.1170815527,0.7271458507,-0.13647753,-0.6352108121,-0.2891793549,-3.0627527237,1.8596694469,-0.9741520882,0.5239673853,0.2815949917,-0.9466477633,-0.2253378183,0.4614507258,0.6802899837,-0.6680192947,0.4086615145,0.3167316616,0.5987631083,-0.4038567841],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[-1.4591249228,1.860142827,0.3325965405,1.2203270197,-1.6403272152,-0.8413307667,-1.2617787123,-0.3930705786,-0.6791994572,-1.2286471128,-1.7605695724,-0.7454581261,1.6631965637,0.891335845,0.1623604,0.1297566593,0.1917251945,-1.1140253544,0.8995596766,-0.6688318849,-0.7772649527,-0.135849297,-1.4118468761,0.7689548135,0.9918349385,-1.5201309919,-1.4569816589,0.8905629516,0.555814147,-0.5756325722,-0.5530716181,-0.9594218731],"label_name":"SORRY","labels":7},{"embeddings":[0.0385579318,-0.9154083729,0.332285136,-0.2287483364,-0.5307860374,0.5951045752,-1.3798874617,-1.5703709126,0.9812933207,-0.9816859365,0.1094539016,0.7211708426,-0.0618176535,1.226790905,-0.6834499836,-0.0769299343,1.4086192846,-1.3319404125,-2.1033005714,1.9947987795,0.2592122555,-1.005059123,0.3317759633,-0.7542120814,-0.3443410397,-0.7424008846,-0.1642354429,0.5855841041,0.4009587765,1.1799840927,-0.0707522929,-1.5210253],"label_name":"SALUUT","labels":11},{"embeddings":[1.1475539207,-0.6485084295,0.1641145349,-0.1522802263,1.0989215374,1.3602879047,0.2905203104,-0.8767233491,0.3546050489,-0.3537590206,0.4050426781,0.1842044294,-0.6389862895,0.3149474561,-0.0670410693,-0.5998560786,0.1470285058,-0.8609958887,-0.3926658034,1.2415859699,0.5658166409,-0.2113135755,2.4451649189,-0.8220761418,-0.8318122029,1.3271417618,1.4593998194,-0.317137748,0.4716895521,-0.0643726736,-0.906629324,-0.1401690394],"label_name":"LINKS","labels":13},{"embeddings":[-0.8443439603,-0.4248021245,0.7591850162,-0.2221844345,-1.3892179728,-0.8868915439,-0.2151456177,0.9171951413,0.2173657715,0.6181064248,1.5585631132,0.7608369589,-0.5187848806,0.0836634189,0.6664733887,0.1345000565,-1.286157608,-0.8915279508,-1.6301544905,0.2788890302,-1.3925323486,1.6478916407,-0.3100701571,-0.3167073727,0.5659659505,0.1443595588,-0.28642717,1.7955495119,-0.8616241217,0.8375310302,0.4441736937,-0.1036912575],"label_name":"GOEDENACHT","labels":2},{"embeddings":[-0.5477452278,-1.0817928314,1.3502467871,-0.8700778484,-1.4312978983,-0.048524335,-1.7284547091,-0.1423572451,1.1913198233,-0.5304102898,1.2570313215,0.9929479957,-2.2014660835,0.5393192172,0.2236096561,-0.0395681411,-0.0713706315,-0.6084550023,-2.9386081696,2.7426891327,-0.9263067245,0.2520747185,0.1337481737,-1.0613926649,0.1831465662,-0.2058886886,0.1051088646,0.0650420263,-0.0705194399,0.5037938952,0.7759755254,-0.9096867442],"label_name":"BEDANKEN","labels":12},{"embeddings":[1.5997974873,-0.4557048678,0.5698676705,-0.3729009926,0.6464906335,1.1204773188,0.3779421747,-0.2536934614,0.3939200342,-0.0645434707,0.7876169682,0.2998420596,-1.0416895151,-0.1882171035,-0.1304481626,-0.4447427094,0.07910157,-0.5516439676,-0.4004528224,0.9849736094,0.5369621515,-0.0698545277,2.7818641663,-0.7452640533,-0.6574359536,1.615962863,1.1206778288,-0.6107518077,0.1721747816,0.0337728634,-0.2839643955,0.1217760444],"label_name":"LINKS","labels":13},{"embeddings":[1.944709301,0.2404042929,0.4647479653,-1.0185340643,-0.0132815484,0.8964191079,-0.4242891669,-0.767336905,0.8529546261,1.0127754211,0.7358632088,0.9480819106,-1.2208877802,0.5545948744,-0.6325765848,-0.9707622528,0.5440499187,0.2548266649,-0.4520415664,0.4079186022,1.5934349298,0.1923921108,2.0507240295,-0.4490491748,-1.6375408173,1.1318172216,1.3084102869,-1.0181363821,-0.4941306412,1.3792381287,0.1759850532,0.1261177659],"label_name":"RECHTS","labels":9},{"embeddings":[1.7522194386,-0.4450699687,0.4749447107,0.133951053,1.1151342392,1.2544665337,0.3423513472,-0.3224904537,0.1064856574,-0.3729566038,0.7964804173,0.38181144,-1.2191524506,-0.1779451072,0.4351961911,-0.5723146796,-0.3849808574,-0.6374486089,-0.410687387,1.197046876,-0.0441408418,0.2460650802,2.6313166618,-0.7422525883,-0.9062651396,1.7074745893,1.4657894373,-0.7399516106,0.8587938547,-0.7782648206,-0.8900444508,-0.2988831997],"label_name":"LINKS","labels":13},{"embeddings":[-1.6541600227,2.6057288647,0.4192391038,1.1025239229,-1.5230233669,-1.1075640917,-1.352402091,0.0924202055,-0.6723098159,-0.9252879024,-1.6102133989,-0.8113862276,1.5550905466,0.6475204229,-0.1876230389,-0.0119110122,-0.0472481772,-0.0869366303,1.5141621828,-1.6765944958,0.3333857954,-0.0376456156,-1.7192201614,0.6537153721,1.1662919521,-1.5156891346,-1.497343421,1.12568748,-0.6089224219,-0.7781364322,0.1077364981,-0.1140430272],"label_name":"SORRY","labels":7},{"embeddings":[-0.1039704233,-1.1622661352,0.8576498032,-0.3345803022,-1.0834118128,0.2693609297,-0.6860142946,0.3671794534,0.6702125072,0.2022749186,2.0438702106,1.0521866083,-1.122246623,-0.1735830903,1.1960265636,-0.7135281563,-0.095079951,-1.9875981808,-2.9303269386,2.0723221302,-2.0256953239,0.5010605454,0.3720539212,-0.462372005,0.4960094094,0.9432120919,0.7096562982,0.526024878,0.288643688,0.3682425618,0.2946210504,-1.7813621759],"label_name":"GOEDENACHT","labels":2},{"embeddings":[0.7900741696,-2.5448300838,-0.3475931883,-1.0431190729,1.1405220032,-0.7483494878,0.3489995897,0.2093232125,-1.0242050886,1.209764719,0.2181803584,0.4384423196,0.8668712974,1.111738205,1.2580206394,0.2986517847,-1.0278862715,-0.9614880681,-1.264493227,0.1894913912,-0.9695560336,1.5544600487,0.0281735808,-0.9024848342,-0.5817625523,-0.0086042229,0.3910245299,-0.2005084753,0.7726597786,-0.2329240143,0.0546318926,0.9725298285],"label_name":"SMAKELIJK","labels":8},{"embeddings":[-0.2376932055,-0.9664093256,0.6584198475,0.3676478863,-0.8390433788,0.6165112853,-0.8175423741,-0.649089098,0.6837370396,-0.5595556498,0.7218324542,0.4069053829,-1.6804573536,-0.5136996508,0.3920041025,-0.1527504623,0.5947883725,-0.2514773905,-1.4192067385,1.6447118521,-0.9759600163,-1.0756316185,-0.3180780411,-0.6337602139,0.3299262524,-0.1987767518,0.0660155937,-0.7080416083,0.957018733,-0.5221000314,0.6598495245,-1.8271124363],"label_name":"SLECHT","labels":4},{"embeddings":[0.2553694844,-1.7618118525,0.9050605297,-1.3369916677,-0.7310680151,0.2490427941,-1.4841476679,-0.1008718163,0.5697535276,-0.1240225136,1.1010127068,0.9220556617,-2.1310997009,0.6801899672,0.6310063004,-0.6481317282,0.4055933952,-1.0130089521,-2.9102230072,2.5284368992,-1.0511065722,-0.0952550396,0.249069646,-1.0481420755,-0.0768393427,-0.004098827,0.234875083,-1.3609019518,0.6634150743,0.4126209617,0.5805782676,-0.8509420156],"label_name":"GOEDENAVOND","labels":10},{"embeddings":[-0.1282932311,-1.1370514631,0.7023268342,-0.2063976228,-0.9467524886,1.1755273342,-1.1649364233,-1.3016856909,1.3565036058,-1.1231809855,0.7629699707,0.8325015306,-1.3491829634,0.879558742,-0.2209141552,-0.3395940363,1.4737195969,-1.173791647,-2.6603593826,2.8207085133,-0.1441461146,-1.1145348549,1.1561892033,-0.9230673909,-0.0850161165,0.0196123626,0.5905880928,0.5479632616,0.0022266582,1.429199934,-0.2198354006,-1.4029437304],"label_name":"GOEDEMIDDAG","labels":14},{"embeddings":[-1.4075777531,-0.9916970134,1.0630320311,-0.2743300498,-1.363871336,-0.8843834996,-1.1732023954,0.7190712094,-0.0109762326,0.429256171,1.3596737385,0.6604902148,-0.5010294914,0.2982709408,0.9121376872,0.5483174324,-0.893076539,-1.3858314753,-2.1044785976,0.7240879536,-1.1468245983,1.1205534935,-0.8031173944,-0.6888789535,0.887526691,-0.2862012982,-0.0598328933,1.8968037367,-0.8432896733,1.048876524,-0.0915411711,-0.2390471399],"label_name":"GOEDENACHT","labels":2},{"embeddings":[1.7715466022,-0.9107513428,-0.0033298731,-0.4660504162,1.1988885403,1.031355381,1.1015861034,-0.1246043742,0.0927308723,0.2776193917,1.0358498096,0.7004230618,-0.7063210607,-0.2646833658,0.1728593409,-0.3935287297,-0.5064507127,-1.1752384901,-0.5110754371,1.3132864237,-0.193187356,0.3623009622,2.853541851,-0.7414342761,-0.7771595716,1.7120233774,1.3052670956,-0.3230531216,0.487945348,-0.4184959829,-0.7429103851,0.2355286181],"label_name":"LINKS","labels":13}] \ No newline at end of file diff --git a/Packages/com.unity.barracuda/package.json.meta b/Assets/Common/Models/BasicSigns/embeddings.json.meta similarity index 60% rename from Packages/com.unity.barracuda/package.json.meta rename to Assets/Common/Models/BasicSigns/embeddings.json.meta index 800282d..8294af0 100644 --- a/Packages/com.unity.barracuda/package.json.meta +++ b/Assets/Common/Models/BasicSigns/embeddings.json.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 73ae2d877fd444b04b5b6ef591d3fa0e -PackageManifestImporter: +guid: 4e303164823194bc4be87f4c9550cfd0 +TextScriptImporter: externalObjects: {} userData: assetBundleName: diff --git a/Assets/Common/Models/FingerSpelling/model_A-L.onnx.meta b/Assets/Common/Models/FingerSpelling/model_A-L.onnx.meta index f7cf75b..d644be1 100644 --- a/Assets/Common/Models/FingerSpelling/model_A-L.onnx.meta +++ b/Assets/Common/Models/FingerSpelling/model_A-L.onnx.meta @@ -7,10 +7,4 @@ ScriptedImporter: userData: assetBundleName: assetBundleVariant: - script: {fileID: 11500000, guid: 683b6cb6d0a474744822c888b46772c9, type: 3} - optimizeModel: 1 - forceArbitraryBatchSize: 1 - treatErrorsAsWarnings: 0 - importMode: 1 - weightsTypeMode: 0 - activationTypeMode: 0 + script: {fileID: 11500000, guid: 8264490bef67c46f2982e6dd3f5e46cd, type: 3} diff --git a/Assets/Common/Models/FingerSpelling/model_A-Z-CML.mlmodel b/Assets/Common/Models/FingerSpelling/model_A-Z-CML.mlmodel new file mode 100644 index 0000000..75f7bdd Binary files /dev/null and b/Assets/Common/Models/FingerSpelling/model_A-Z-CML.mlmodel differ diff --git a/Assets/Common/Models/FingerSpelling/model_A-Z-CML.mlmodel.meta b/Assets/Common/Models/FingerSpelling/model_A-Z-CML.mlmodel.meta new file mode 100644 index 0000000..ddb1b7b --- /dev/null +++ b/Assets/Common/Models/FingerSpelling/model_A-Z-CML.mlmodel.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: be31548ec7e7544fe9828b14657bb40b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 3e882272056fc4ddfa14de161aaba2ba, type: 3} diff --git a/Assets/Common/Models/FingerSpelling/model_A-Z2.onnx b/Assets/Common/Models/FingerSpelling/model_A-Z2.onnx new file mode 100644 index 0000000..19893c4 Binary files /dev/null and b/Assets/Common/Models/FingerSpelling/model_A-Z2.onnx differ diff --git a/Assets/Common/Models/FingerSpelling/model_A-Z2.onnx.meta b/Assets/Common/Models/FingerSpelling/model_A-Z2.onnx.meta new file mode 100644 index 0000000..719df69 --- /dev/null +++ b/Assets/Common/Models/FingerSpelling/model_A-Z2.onnx.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: fdbf401e965a6bf4a87637cd519f2715 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8264490bef67c46f2982e6dd3f5e46cd, type: 3} diff --git a/Assets/Common/PlayModeTests/BackButtonTests.cs b/Assets/Common/PlayModeTests/BackButtonTests.cs index 52fac01..07bcefe 100644 --- a/Assets/Common/PlayModeTests/BackButtonTests.cs +++ b/Assets/Common/PlayModeTests/BackButtonTests.cs @@ -1,13 +1,9 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; using UnityEngine.TestTools; -using UnityEngine.SceneManagement; - public class BackButtonTests { @@ -15,14 +11,13 @@ public class BackButtonTests [UnitySetUp] public IEnumerator SetupFunction() { - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } - + File.WriteAllText(path, oneUser); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SystemController.GetInstance().LoadNextScene("Common/Scenes/MainMenuScreen"); yield return new WaitForSeconds(0.2f); SystemController.GetInstance().LoadNextScene("Common/Scenes/ListMinigamesScreen"); @@ -33,11 +28,11 @@ public class BackButtonTests public IEnumerator BackTest() { - var backButton = (BackButton) GameObject.FindObjectOfType(typeof(BackButton)); + var backButton = (BackButton)GameObject.FindObjectOfType(typeof(BackButton)); backButton.Back(); yield return new WaitForSeconds(0.2f); - var mainMenuScreen = (MainMenuScreen) GameObject.FindObjectOfType(typeof(MainMenuScreen)); + var mainMenuScreen = (MainMenuScreen)GameObject.FindObjectOfType(typeof(MainMenuScreen)); Assert.IsNotNull(mainMenuScreen); } } diff --git a/Assets/Common/PlayModeTests/CommonPlayModeTests.asmdef b/Assets/Common/PlayModeTests/CommonPlayModeTests.asmdef index 9e75bf8..efc27fc 100644 --- a/Assets/Common/PlayModeTests/CommonPlayModeTests.asmdef +++ b/Assets/Common/PlayModeTests/CommonPlayModeTests.asmdef @@ -8,7 +8,9 @@ "CommonScripts", "InterfacesScripts", "Unity.TextMeshPro", - "AccountsScripts" + "AccountsScripts", + "SignPredictor", + "ArchitectureScripts" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Common/PlayModeTests/CourseActivityTests.cs b/Assets/Common/PlayModeTests/CourseActivityTests.cs index 1d20c5a..4eb81ac 100644 --- a/Assets/Common/PlayModeTests/CourseActivityTests.cs +++ b/Assets/Common/PlayModeTests/CourseActivityTests.cs @@ -1,13 +1,9 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; using UnityEngine.TestTools; -using UnityEngine.SceneManagement; - public class CourseActivityTests { @@ -15,14 +11,13 @@ public class CourseActivityTests [UnitySetUp] public IEnumerator SetupFunction() { - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(path, oneUser); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SystemController.GetInstance().LoadNextScene("Common/Scenes/CourseActivityScreen"); yield return new WaitForSeconds(0.2f); } @@ -30,11 +25,11 @@ public class CourseActivityTests [UnityTest] public IEnumerator StartCoursesTests() { - var courseActivityScreen = (CourseActivityScreen) GameObject.FindObjectOfType(typeof(CourseActivityScreen)); + var courseActivityScreen = (CourseActivityScreen)GameObject.FindObjectOfType(typeof(CourseActivityScreen)); courseActivityScreen.StartCourse(); yield return new WaitForSeconds(0.2f); - var templateCourse = (TemplateCourse) GameObject.FindObjectOfType(typeof(TemplateCourse)); + var templateCourse = (CoursesController)GameObject.FindObjectOfType(typeof(CoursesController)); Assert.IsNotNull(templateCourse); } } diff --git a/Assets/Common/PlayModeTests/CourseMenuScreenTests.cs b/Assets/Common/PlayModeTests/CourseMenuScreenTests.cs index 8f5a89d..ce2a517 100644 --- a/Assets/Common/PlayModeTests/CourseMenuScreenTests.cs +++ b/Assets/Common/PlayModeTests/CourseMenuScreenTests.cs @@ -1,13 +1,9 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; using UnityEngine.TestTools; -using UnityEngine.SceneManagement; - public class CourseMenuScreenTest { @@ -15,14 +11,13 @@ public class CourseMenuScreenTest [UnitySetUp] public IEnumerator SetupFunction() { - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(path, oneUser); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SystemController.GetInstance().LoadNextScene("Common/Scenes/CoursesMenuScreen"); yield return new WaitForSeconds(0.2f); } @@ -30,7 +25,7 @@ public class CourseMenuScreenTest [UnityTest] public IEnumerator GotoListOfCoursesTest() { - var courseMenuScreen = (CourseMenuScreen) GameObject.FindObjectOfType(typeof(CourseMenuScreen)); + var courseMenuScreen = (CourseMenuScreen)GameObject.FindObjectOfType(typeof(CourseMenuScreen)); courseMenuScreen.GotoListOfCourses(); yield return new WaitForSeconds(0.2f); diff --git a/Assets/Common/PlayModeTests/ListCoursesScreenTests.cs b/Assets/Common/PlayModeTests/ListCoursesScreenTests.cs index 552906a..0efcd63 100644 --- a/Assets/Common/PlayModeTests/ListCoursesScreenTests.cs +++ b/Assets/Common/PlayModeTests/ListCoursesScreenTests.cs @@ -1,13 +1,9 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; using UnityEngine.TestTools; -using UnityEngine.SceneManagement; - public class ListCoursesScreenTest { @@ -15,14 +11,13 @@ public class ListCoursesScreenTest [UnitySetUp] public IEnumerator SetupFunction() { - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(path, oneUser); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SystemController.GetInstance().LoadNextScene("Common/Scenes/ListCoursesScreen"); yield return new WaitForSeconds(0.2f); } diff --git a/Assets/Common/PlayModeTests/MainMenuScreenTests.cs b/Assets/Common/PlayModeTests/MainMenuScreenTests.cs index 5e48d47..1517265 100644 --- a/Assets/Common/PlayModeTests/MainMenuScreenTests.cs +++ b/Assets/Common/PlayModeTests/MainMenuScreenTests.cs @@ -1,12 +1,10 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; -using UnityEngine.TestTools; using UnityEngine.SceneManagement; +using UnityEngine.TestTools; public class MainMenuScreenTests @@ -15,14 +13,13 @@ public class MainMenuScreenTests [UnitySetUp] public IEnumerator SetupFunction() { - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(path, oneUser); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SceneManager.LoadScene("Common/Scenes/MainMenuScreen"); yield return new WaitForSeconds(0.2f); } @@ -42,28 +39,28 @@ public class MainMenuScreenTests [UnityTest] public IEnumerator GotoMiniGamesTest() { - var mainMenuScreen = (MainMenuScreen) GameObject.FindObjectOfType(typeof(MainMenuScreen)); + var mainMenuScreen = (MainMenuScreen)GameObject.FindObjectOfType(typeof(MainMenuScreen)); mainMenuScreen.GotoMinigames(); yield return new WaitForSeconds(0.2f); - var listMinigamesScreen = (ListMinigamesScreen) GameObject.FindObjectOfType(typeof(ListMinigamesScreen)); + var listMinigamesScreen = (ListMinigamesScreen)GameObject.FindObjectOfType(typeof(ListMinigamesScreen)); Assert.IsNotNull(listMinigamesScreen); } -/* [UnityTest] - public IEnumerator GotoSettingsTest() - { - Arrange - SceneManager.LoadScene("Common/Scenes/MainMenuScreen"); + /* [UnityTest] + public IEnumerator GotoSettingsTest() + { + Arrange + SceneManager.LoadScene("Common/Scenes/MainMenuScreen"); - yield return new WaitForSeconds(1f); - var mainMenuScreen = (MainMenuScreen)GameObject.FindObjectOfType(typeof(MainMenuScreen)); - mainMenuScreen.GotoSettings(); - yield return new WaitForSeconds(1f); + yield return new WaitForSeconds(1f); + var mainMenuScreen = (MainMenuScreen)GameObject.FindObjectOfType(typeof(MainMenuScreen)); + mainMenuScreen.GotoSettings(); + yield return new WaitForSeconds(1f); - var minigameActivityScreen = (MinigameActivityScreen)GameObject.FindObjectOfType(typeof(MinigameActivityScreen)); - Assert.IsNotNull(minigameActivityScreen); - }*/ + var minigameActivityScreen = (MinigameActivityScreen)GameObject.FindObjectOfType(typeof(MinigameActivityScreen)); + Assert.IsNotNull(minigameActivityScreen); + }*/ } diff --git a/Assets/Common/PlayModeTests/MinigameActivityScreenTests.cs b/Assets/Common/PlayModeTests/MinigameActivityScreenTests.cs index 8896662..59e5ac5 100644 --- a/Assets/Common/PlayModeTests/MinigameActivityScreenTests.cs +++ b/Assets/Common/PlayModeTests/MinigameActivityScreenTests.cs @@ -1,12 +1,9 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; using UnityEngine.TestTools; -using UnityEngine.SceneManagement; public class MiniGameActivityScreenTests @@ -15,14 +12,13 @@ public class MiniGameActivityScreenTests [UnitySetUp] public IEnumerator SetupFunction() { - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(path, oneUser); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SystemController.GetInstance().LoadNextScene("Common/Scenes/CoursesMenuScreen"); yield return new WaitForSeconds(0.2f); } diff --git a/Assets/Common/PlayModeTests/StartGameTests.cs b/Assets/Common/PlayModeTests/StartGameTests.cs index ccc5eda..e8c9ecc 100644 --- a/Assets/Common/PlayModeTests/StartGameTests.cs +++ b/Assets/Common/PlayModeTests/StartGameTests.cs @@ -1,36 +1,31 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; -using UnityEngine.TestTools; using UnityEngine.SceneManagement; +using UnityEngine.TestTools; public class StartGamesTests { - - [UnityTest] public IEnumerator BootWithUsersTest() { - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(path, oneUser); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SceneManager.LoadScene("Common/Scenes/Boot"); yield return new WaitForSeconds(1); - var userCreationScreen = (UserCreationScreen) GameObject.FindObjectOfType(typeof(UserCreationScreen)); - var bootScreen = (BootScreen) GameObject.FindObjectOfType(typeof(BootScreen)); - var mainMenuScreen = (MainMenuScreen) GameObject.FindObjectOfType(typeof(MainMenuScreen)); + var userCreationScreen = (UserCreationScreen)GameObject.FindObjectOfType(typeof(UserCreationScreen)); + var bootScreen = (BootScreen)GameObject.FindObjectOfType(typeof(BootScreen)); + var mainMenuScreen = (MainMenuScreen)GameObject.FindObjectOfType(typeof(MainMenuScreen)); // yield return Application.RequestUserAuthorization(UserAuthorization.WebCam); // if (Application.HasUserAuthorization(UserAuthorization.WebCam)) @@ -42,41 +37,37 @@ public class StartGamesTests // Assert.AreEqual(bootScreen.errorText.text, "Zorg ervoor dat deze applicatie toegang heeft tot je webcam!"); // } // else - if(0 >= WebCamTexture.devices.Length){ - Debug.Log("no webcam"); - Assert.IsNull(userCreationScreen); + if (0 >= WebCamTexture.devices.Length) + { Assert.IsNull(mainMenuScreen); Assert.IsNotNull(bootScreen); Assert.AreEqual(bootScreen.errorText.text, "Zorg ervoor dat je webcam correct is aangesloten!"); } - else + else { - Debug.Log("everything is there"); Assert.IsNull(bootScreen); - Assert.IsNull(userCreationScreen); Assert.IsNotNull(mainMenuScreen); } + Assert.IsNull(userCreationScreen); } [UnityTest] public IEnumerator BootWithoutUsersTest() { - // Arrange - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string noUsers = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"; + File.WriteAllText(path, noUsers); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SceneManager.LoadScene("Common/Scenes/Boot"); yield return new WaitForSeconds(1); - var userCreationScreen = (UserCreationScreen) GameObject.FindObjectOfType(typeof(UserCreationScreen)); - var bootScreen = (BootScreen) GameObject.FindObjectOfType(typeof(BootScreen)); - var mainMenuScreen = (MainMenuScreen) GameObject.FindObjectOfType(typeof(MainMenuScreen)); + var userCreationScreen = (UserCreationScreen)GameObject.FindObjectOfType(typeof(UserCreationScreen)); + var bootScreen = (BootScreen)GameObject.FindObjectOfType(typeof(BootScreen)); + var mainMenuScreen = (MainMenuScreen)GameObject.FindObjectOfType(typeof(MainMenuScreen)); // yield return Application.RequestUserAuthorization(UserAuthorization.WebCam); // if (Application.HasUserAuthorization(UserAuthorization.WebCam)) @@ -88,19 +79,18 @@ public class StartGamesTests // Assert.AreEqual(bootScreen.errorText.text, "Zorg ervoor dat deze applicatie toegang heeft tot je webcam!"); // } // else - if(0 >= WebCamTexture.devices.Length){ - Debug.Log("no webcam"); + if (0 >= WebCamTexture.devices.Length) + { Assert.IsNull(userCreationScreen); - Assert.IsNull(mainMenuScreen); Assert.IsNotNull(bootScreen); Assert.AreEqual(bootScreen.errorText.text, "Zorg ervoor dat je webcam correct is aangesloten!"); - } else + } + else { - Debug.Log("no users"); Assert.IsNull(bootScreen); - Assert.IsNull(mainMenuScreen); Assert.IsNotNull(userCreationScreen); } + Assert.IsNull(mainMenuScreen); } } diff --git a/Assets/Common/PlayModeTests/UserButtonTests.cs b/Assets/Common/PlayModeTests/UserButtonTests.cs index 40a324c..271b7cb 100644 --- a/Assets/Common/PlayModeTests/UserButtonTests.cs +++ b/Assets/Common/PlayModeTests/UserButtonTests.cs @@ -1,12 +1,9 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; using UnityEngine.TestTools; -using UnityEngine.SceneManagement; public class UserButtonTests @@ -15,28 +12,27 @@ public class UserButtonTests [UnitySetUp] public IEnumerator SetupFunction() { - string path = $"{Application.persistentDataPath}/users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(path, oneUser); + PersistentDataController.PATH = path; + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); SystemController.GetInstance().LoadNextScene("Common/Scenes/CoursesMenuScreen"); yield return new WaitForSeconds(0.2f); } -/* [UnityTest] - public IEnumerator OpenProgressCallbackTest() - { - var userButton = (UserButton)GameObject.FindObjectOfType(typeof(UserButton)); - userButton.OpenProgressCallback(); - yield return new WaitForSeconds(0.2f); + /* [UnityTest] + public IEnumerator OpenProgressCallbackTest() + { + var userButton = (UserButton)GameObject.FindObjectOfType(typeof(UserButton)); + userButton.OpenProgressCallback(); + yield return new WaitForSeconds(0.2f); - var listCoursesScreen = (ListCoursesScreen)GameObject.FindObjectOfType(typeof(ListCoursesScreen)); - Assert.IsNotNull(listCoursesScreen); - }*/ + var listCoursesScreen = (ListCoursesScreen)GameObject.FindObjectOfType(typeof(ListCoursesScreen)); + Assert.IsNotNull(listCoursesScreen); + }*/ [UnityTest] public IEnumerator ChangeUserCallbackTest() diff --git a/Assets/Common/Prefabs/ButtonBack.prefab b/Assets/Common/Prefabs/ButtonBack.prefab index c63cee4..2b46bd2 100644 --- a/Assets/Common/Prefabs/ButtonBack.prefab +++ b/Assets/Common/Prefabs/ButtonBack.prefab @@ -1,142 +1,5 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: ---- !u!1 &8299246692439904509 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 8299246692439904498} - - component: {fileID: 8299246692439904496} - - component: {fileID: 8299246692439904499} - m_Layer: 5 - m_Name: Text (TMP) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &8299246692439904498 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8299246692439904509} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 8299246693487308515} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &8299246692439904496 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8299246692439904509} - m_CullTransparentMesh: 1 ---- !u!114 &8299246692439904499 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8299246692439904509} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: '< Terug - -' - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 48 - m_fontSizeBase: 48 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &8299246693487308514 GameObject: m_ObjectHideFlags: 0 @@ -147,6 +10,7 @@ GameObject: m_Component: - component: {fileID: 8299246693487308515} - component: {fileID: 8299246693487308518} + - component: {fileID: 54433152227066563} - component: {fileID: 8299246693487308512} - component: {fileID: 4518652150503380115} m_Layer: 5 @@ -167,15 +31,14 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 8299246692439904498} + m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 300, y: 120} + m_AnchoredPosition: {x: 10, y: -10} + m_SizeDelta: {x: 50, y: 50} m_Pivot: {x: 0, y: 1} --- !u!222 &8299246693487308518 CanvasRenderer: @@ -185,6 +48,36 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 8299246693487308514} m_CullTransparentMesh: 1 +--- !u!114 &54433152227066563 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8299246693487308514} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: b35e8d4a1c2d02544bb23e9c6a440998, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 --- !u!114 &8299246693487308512 MonoBehaviour: m_ObjectHideFlags: 0 @@ -225,7 +118,7 @@ MonoBehaviour: m_SelectedTrigger: Selected m_DisabledTrigger: Disabled m_Interactable: 1 - m_TargetGraphic: {fileID: 0} + m_TargetGraphic: {fileID: 54433152227066563} m_OnClick: m_PersistentCalls: m_Calls: diff --git a/Assets/Common/Prefabs/ButtonUser.prefab b/Assets/Common/Prefabs/ButtonUser.prefab index 1183e29..3435dea 100644 --- a/Assets/Common/Prefabs/ButtonUser.prefab +++ b/Assets/Common/Prefabs/ButtonUser.prefab @@ -68,7 +68,7 @@ MonoBehaviour: m_Calls: [] m_text: Progressie m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} @@ -132,7 +132,7 @@ MonoBehaviour: m_margin: {x: 0, y: 0, z: 0, w: 0} m_isUsingLegacyAnimationComponent: 0 m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 + m_hasFontAssetChanged: 1 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &879769956311181956 @@ -387,7 +387,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 7b8b159dda1a6104793946dc46f84f3a, type: 3} m_Name: m_EditorClassIdentifier: - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} avatar: {fileID: 692645475575553623} username: {fileID: 2823887524728706580} dropdownBox: {fileID: 5251791132896734340} @@ -459,8 +458,8 @@ MonoBehaviour: m_Calls: [] m_text: Gebruiker m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -905,8 +904,8 @@ MonoBehaviour: m_Calls: [] m_text: Veranderen van gebruiker m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] diff --git a/Assets/Common/Prefabs/Course Item.prefab b/Assets/Common/Prefabs/Course Item.prefab index 8783e8b..1ea5dc0 100644 --- a/Assets/Common/Prefabs/Course Item.prefab +++ b/Assets/Common/Prefabs/Course Item.prefab @@ -1,6 +1,6 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: ---- !u!1 &4959898007472841756 +--- !u!1 &3971139188485731716 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -8,8 +8,9 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 4959898007472841755} - - component: {fileID: 4959898007472841754} + - component: {fileID: 3562628571261849392} + - component: {fileID: 964317949513701677} + - component: {fileID: 7598711171284142173} m_Layer: 5 m_Name: Slider m_TagString: Untagged @@ -17,79 +18,59 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &4959898007472841755 +--- !u!224 &3562628571261849392 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898007472841756} + m_GameObject: {fileID: 3971139188485731716} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 4959898007929492911} - - {fileID: 4959898007984173683} - m_Father: {fileID: 1417749870311553741} - m_RootOrder: 1 + m_Children: [] + m_Father: {fileID: 9089886807003329865} + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: -20, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &4959898007472841754 +--- !u!222 &964317949513701677 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3971139188485731716} + m_CullTransparentMesh: 1 +--- !u!114 &7598711171284142173 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898007472841756} + m_GameObject: {fileID: 3971139188485731716} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 67db9e8f0e2ae9c40bc1e2b64352a6b4, type: 3} + m_Script: {fileID: 11500000, guid: b69b55aa2ac2e0e4592740cf1269d52c, type: 3} m_Name: m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 0 - m_Colors: - m_NormalColor: {r: 1, g: 0, b: 0, a: 1} - m_HighlightedColor: {r: 0.016251326, g: 1, b: 0, a: 1} - m_PressedColor: {r: 1, g: 0.8441375, b: 0, a: 1} - m_SelectedColor: {r: 0, g: 0.21683073, b: 1, a: 1} - m_DisabledColor: {r: 1, g: 0, b: 0.92438126, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 0 - m_TargetGraphic: {fileID: 0} - m_FillRect: {fileID: 4959898008359015389} - m_HandleRect: {fileID: 0} - m_Direction: 0 - m_MinValue: 0 - m_MaxValue: 1 - m_WholeNumbers: 0 - m_Value: 1 - m_OnValueChanged: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 02283f528ead8084db69c7d8a459f0af, type: 3} + m_FillDirection: 0 + m_FillAmount: 0 + m_FillCenter: 1 + m_PixelsPerUnitMultiplier: 1 --- !u!1 &4959898007614330357 GameObject: m_ObjectHideFlags: 0 @@ -103,6 +84,7 @@ GameObject: - component: {fileID: 4959898007614330354} - component: {fileID: 4959898007614330355} - component: {fileID: 4959898007614330352} + - component: {fileID: 5637671876400780781} m_Layer: 5 m_Name: Course Item m_TagString: Untagged @@ -124,7 +106,8 @@ RectTransform: m_Children: - {fileID: 4959898009379617329} - {fileID: 2813955202388678150} - - {fileID: 1417749870311553741} + - {fileID: 9089886807003329865} + - {fileID: 5378512836556066408} m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -154,14 +137,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 0.7529412, g: 0.7529412, b: 0.7529412, a: 1} + m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -193,7 +176,7 @@ MonoBehaviour: m_Transition: 1 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_HighlightedColor: {r: 0.88235295, g: 0.88235295, b: 0.88235295, a: 1} m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} @@ -233,197 +216,28 @@ MonoBehaviour: thumbnail: {fileID: 4959898009379617328} title: {fileID: 4959898009362012447} button: {fileID: 4959898007614330355} - slider: {fileID: 4959898007472841756} + slider: {fileID: 3971139188485731716} completed: {fileID: 8032316393302770855} ---- !u!1 &4959898007929492944 -GameObject: +--- !u!95 &5637671876400780781 +Animator: + serializedVersion: 5 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4959898007929492911} - - component: {fileID: 4959898007929492909} - - component: {fileID: 4959898007929492910} - m_Layer: 5 - m_Name: Background - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &4959898007929492911 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898007929492944} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 4959898007472841755} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0.25} - m_AnchorMax: {x: 1, y: 0.75} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &4959898007929492909 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898007929492944} - m_CullTransparentMesh: 1 ---- !u!114 &4959898007929492910 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898007929492944} + m_GameObject: {fileID: 4959898007614330357} m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!1 &4959898007984173684 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4959898007984173683} - m_Layer: 5 - m_Name: Fill Area - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &4959898007984173683 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898007984173684} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 4959898008359015389} - m_Father: {fileID: 4959898007472841755} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0.25} - m_AnchorMax: {x: 1, y: 0.75} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!1 &4959898008359015390 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4959898008359015389} - - component: {fileID: 4959898008359015387} - - component: {fileID: 4959898008359015388} - m_Layer: 5 - m_Name: Fill - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &4959898008359015389 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898008359015390} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 4959898007984173683} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &4959898008359015387 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898008359015390} - m_CullTransparentMesh: 1 ---- !u!114 &4959898008359015388 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898008359015390} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 0, g: 0.7529412, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 7f13ed5d552355e419355775df689c02, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1 &4959898009362012417 GameObject: m_ObjectHideFlags: 0 @@ -492,15 +306,15 @@ MonoBehaviour: m_Calls: [] m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -517,8 +331,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 30 - m_fontSizeBase: 30 + m_fontSize: 35 + m_fontSizeBase: 35 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 @@ -595,7 +409,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -100} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &4959898009379617295 CanvasRenderer: @@ -627,6 +441,83 @@ MonoBehaviour: m_Calls: [] m_Sprite: {fileID: 0} m_Type: 0 + m_PreserveAspect: 1 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &5742510687904928776 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9089886807003329865} + - component: {fileID: 5151021879949427368} + - component: {fileID: 1750847728492947398} + m_Layer: 5 + m_Name: Progress + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9089886807003329865 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5742510687904928776} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 3562628571261849392} + m_Father: {fileID: 4959898007614330356} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 20} + m_SizeDelta: {x: -40, y: 25} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &5151021879949427368 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5742510687904928776} + m_CullTransparentMesh: 1 +--- !u!114 &1750847728492947398 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5742510687904928776} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 42d6d4c291d8a8a46bd0d545fd445c3d, type: 3} + m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 4 @@ -671,7 +562,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: -10} + m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: -20, y: 64} m_Pivot: {x: 0.5, y: 1} --- !u!222 &7918167783998757471 @@ -689,7 +580,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5811962218190726816} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: @@ -742,13 +633,13 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 1417749870311553741} - m_RootOrder: 0 + m_Father: {fileID: 4959898007614330356} + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 50} + m_AnchoredPosition: {x: 0, y: 10} + m_SizeDelta: {x: -20, y: 50} m_Pivot: {x: 0.5, y: 0} --- !u!222 &664234899589649762 CanvasRenderer: @@ -778,17 +669,17 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: '* COMPLETED *' + m_text: '* VOLTOOID *' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4294950912 - m_fontColor: {r: 0, g: 0.7529412, b: 1, a: 1} + rgba: 4279873015 + m_fontColor: {r: 0.96862745, g: 0.6784314, b: 0.09803922, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -844,84 +735,6 @@ MonoBehaviour: m_margin: {x: 0, y: 0, z: 0, w: 0} m_isUsingLegacyAnimationComponent: 0 m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 + m_hasFontAssetChanged: 1 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!1 &8124493043442100213 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1417749870311553741} - - component: {fileID: 6308727626875428689} - - component: {fileID: 8474656946490788667} - m_Layer: 5 - m_Name: Progress - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1417749870311553741 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8124493043442100213} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 5378512836556066408} - - {fileID: 4959898007472841755} - m_Father: {fileID: 4959898007614330356} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 0} - m_AnchoredPosition: {x: 0, y: 10} - m_SizeDelta: {x: -20, y: 50} - m_Pivot: {x: 0.5, y: 0} ---- !u!222 &6308727626875428689 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8124493043442100213} - m_CullTransparentMesh: 1 ---- !u!114 &8474656946490788667 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8124493043442100213} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.5019608} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 0} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 diff --git a/Assets/Common/Prefabs/Minigame Item.prefab b/Assets/Common/Prefabs/Minigame Item.prefab index 26def4a..e1b5c11 100644 --- a/Assets/Common/Prefabs/Minigame Item.prefab +++ b/Assets/Common/Prefabs/Minigame Item.prefab @@ -1,5 +1,140 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &425409310702691282 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7578001082699649381} + - component: {fileID: 1032168323822911732} + - component: {fileID: 814674078455998583} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7578001082699649381 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 425409310702691282} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4484781637876518546} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1032168323822911732 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 425409310702691282} + m_CullTransparentMesh: 1 +--- !u!114 &814674078455998583 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 425409310702691282} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 35 + m_fontSizeBase: 35 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &4959898007614330357 GameObject: m_ObjectHideFlags: 0 @@ -63,14 +198,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 0.7529412, g: 0.7529412, b: 0.7529412, a: 1} + m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -102,7 +237,7 @@ MonoBehaviour: m_Transition: 1 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_HighlightedColor: {r: 0.88235295, g: 0.88235295, b: 0.88235295, a: 1} m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} @@ -139,143 +274,8 @@ MonoBehaviour: minigame: {fileID: 0} thumbnail: {fileID: 4959898009379617328} minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} - title: {fileID: 4959898009362012447} + title: {fileID: 814674078455998583} button: {fileID: 4959898007614330355} ---- !u!1 &4959898009362012417 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4959898009362012416} - - component: {fileID: 4959898009362012446} - - component: {fileID: 4959898009362012447} - m_Layer: 5 - m_Name: Text (TMP) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &4959898009362012416 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898009362012417} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 4484781637876518546} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &4959898009362012446 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898009362012417} - m_CullTransparentMesh: 1 ---- !u!114 &4959898009362012447 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4959898009362012417} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 30 - m_fontSizeBase: 30 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &4959898009379617330 GameObject: m_ObjectHideFlags: 0 @@ -311,8 +311,8 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: -20} + m_SizeDelta: {x: -20, y: -60} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &4959898009379617295 CanvasRenderer: @@ -382,13 +382,13 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 4959898009362012416} + - {fileID: 7578001082699649381} m_Father: {fileID: 4959898007614330356} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: -10} + m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: -20, y: 64} m_Pivot: {x: 0.5, y: 1} --- !u!222 &7404719235506382604 @@ -406,7 +406,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6222436643885153819} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: diff --git a/Assets/Common/Prefabs/Theme Item.prefab b/Assets/Common/Prefabs/Theme Item.prefab index ffc0594..53f4a80 100644 --- a/Assets/Common/Prefabs/Theme Item.prefab +++ b/Assets/Common/Prefabs/Theme Item.prefab @@ -68,15 +68,15 @@ MonoBehaviour: m_Calls: [] m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4282795590 - m_fontColor: {r: 0.27450982, g: 0.27450982, b: 0.27450982, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -204,15 +204,15 @@ MonoBehaviour: m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4282795590 - m_fontColor: {r: 0.27450982, g: 0.27450982, b: 0.27450982, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -237,7 +237,7 @@ MonoBehaviour: m_fontSizeMax: 72 m_fontStyle: 0 m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 + m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 m_wordSpacing: 0 @@ -334,14 +334,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 0.62352943, g: 0.90588236, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 diff --git a/Assets/Common/Prefabs/UserInfoHS.prefab b/Assets/Common/Prefabs/UserInfoHS.prefab index 88e1a2c..41994ff 100644 --- a/Assets/Common/Prefabs/UserInfoHS.prefab +++ b/Assets/Common/Prefabs/UserInfoHS.prefab @@ -68,8 +68,8 @@ MonoBehaviour: m_Calls: [] m_text: Score 1 m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -358,15 +358,15 @@ MonoBehaviour: m_Calls: [] m_text: Dries m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4292118016 - m_fontColor: {r: 0, g: 0.5254902, b: 0.8313726, a: 1} + rgba: 4290616898 + m_fontColor: {r: 0.25882354, g: 0.61960787, b: 0.7411765, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: diff --git a/Assets/Common/Scenes/Boot.unity b/Assets/Common/Scenes/Boot.unity index bd3e0a4..f0a8103 100644 --- a/Assets/Common/Scenes/Boot.unity +++ b/Assets/Common/Scenes/Boot.unity @@ -218,7 +218,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -260,14 +259,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 0, g: 0, b: 0, a: 1} + m_Color: {r: 0.0627451, g: 0.0627451, b: 0.0627451, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -285,19 +284,52 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 +--- !u!1 &1427583093 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1427583095} + - component: {fileID: 1427583094} + m_Layer: 0 + m_Name: BootController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1427583094 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} + m_GameObject: {fileID: 1427583093} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: f8891598d17bbfb439850bda8d767724, type: 3} m_Name: m_EditorClassIdentifier: errorText: {fileID: 1663223260} + sprites: {fileID: 11400000, guid: 017ec1af3b6cc4d4ab2b506911a4edad, type: 2} +--- !u!4 &1427583095 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1427583093} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1663223258 GameObject: m_ObjectHideFlags: 0 @@ -358,8 +390,8 @@ MonoBehaviour: m_Calls: [] m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -481,10 +513,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -527,7 +559,7 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 1 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} diff --git a/Assets/Common/Scenes/CourseActivityScreen.unity b/Assets/Common/Scenes/CourseActivityScreen.unity index cf70ce7..7ed9e0c 100644 --- a/Assets/Common/Scenes/CourseActivityScreen.unity +++ b/Assets/Common/Scenes/CourseActivityScreen.unity @@ -123,6 +123,141 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &54642280 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 54642281} + - component: {fileID: 54642283} + - component: {fileID: 54642282} + m_Layer: 5 + m_Name: Button Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &54642281 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 54642280} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1230251433} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 117.808, y: 0} + m_SizeDelta: {x: -235.617, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &54642282 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 54642280} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Begin + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 250 + m_fontSizeBase: 250 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &54642283 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 54642280} + m_CullTransparentMesh: 1 --- !u!1 &129643495 GameObject: m_ObjectHideFlags: 0 @@ -191,6 +326,158 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &192988723 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 192988724} + - component: {fileID: 192988726} + - component: {fileID: 192988725} + m_Layer: 5 + m_Name: Button Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &192988724 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 192988723} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.3, y: 1.3, z: 1.3} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 2135419030} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1388, y: 497} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &192988725 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 192988723} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 46578af6a9f38ea46bf4f53f79e8fca8, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &192988726 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 192988723} + m_CullTransparentMesh: 1 +--- !u!1 &322684578 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 322684579} + - component: {fileID: 322684581} + - component: {fileID: 322684580} + m_Layer: 5 + m_Name: Button Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &322684579 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 322684578} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.3, y: 1.3, z: 1.3} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1230251433} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1388, y: 497} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &322684580 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 322684578} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 46578af6a9f38ea46bf4f53f79e8fca8, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &322684581 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 322684578} + m_CullTransparentMesh: 1 --- !u!1 &339096154 GameObject: m_ObjectHideFlags: 0 @@ -228,6 +515,194 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &491907973 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 491907974} + - component: {fileID: 491907976} + - component: {fileID: 491907975} + m_Layer: 5 + m_Name: Button Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &491907974 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 491907973} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2135419030} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 117.808, y: 0} + m_SizeDelta: {x: -235.617, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &491907975 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 491907973} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Herstart + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 250 + m_fontSizeBase: 250 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &491907976 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 491907973} + m_CullTransparentMesh: 1 +--- !u!1 &492331920 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 492331921} + - component: {fileID: 492331922} + m_Layer: 0 + m_Name: Director EnterFrom CourseMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &492331921 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 492331920} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2029692578} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &492331922 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 492331920} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 3912059771208757551, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 1211177270} + - key: {fileID: -7222763729682898453, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 1394044036} + m_ExposedReferences: + m_References: [] --- !u!1 &507029406 GameObject: m_ObjectHideFlags: 0 @@ -258,12 +733,12 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 906197777} - m_RootOrder: 5 + m_Father: {fileID: 1135894725} + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 150, y: -100} + m_AnchoredPosition: {x: 0, y: 60} m_SizeDelta: {x: 400, y: 64} m_Pivot: {x: 0, y: 0.5} --- !u!114 &507029408 @@ -288,15 +763,15 @@ MonoBehaviour: m_Calls: [] m_text: Vooruitgang m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -313,14 +788,14 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 52 - m_fontSizeBase: 52 + m_fontSize: 60 + m_fontSizeBase: 60 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 1 - m_HorizontalAlignment: 1 + m_fontStyle: 0 + m_HorizontalAlignment: 2 m_VerticalAlignment: 512 m_textAlignment: 65535 m_characterSpacing: 0 @@ -363,6 +838,82 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 507029406} m_CullTransparentMesh: 1 +--- !u!1 &519124401 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 519124402} + - component: {fileID: 519124404} + - component: {fileID: 519124403} + m_Layer: 5 + m_Name: Button Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &519124402 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 519124401} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2135419030} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -550, y: 0} + m_SizeDelta: {x: 280, y: 280} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &519124403 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 519124401} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: c503be644b0f16f43beb5cd454225ad1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &519124404 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 519124401} + m_CullTransparentMesh: 1 --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -498,16 +1049,16 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 0.6} + m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 + m_Sprite: {fileID: 21300000, guid: 42d6d4c291d8a8a46bd0d545fd445c3d, type: 3} + m_Type: 0 + m_PreserveAspect: 1 m_FillCenter: 1 m_FillMethod: 4 m_FillAmount: 1 @@ -523,6 +1074,217 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 599238321} m_CullTransparentMesh: 1 +--- !u!1 &633609943 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 633609944} + - component: {fileID: 633609946} + - component: {fileID: 633609945} + m_Layer: 5 + m_Name: Button Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &633609944 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 633609943} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1422147255} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -550, y: 0} + m_SizeDelta: {x: 280, y: 280} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &633609945 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 633609943} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 20d0d5f265af8554887f17fc0271b1be, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &633609946 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 633609943} + m_CullTransparentMesh: 1 +--- !u!1 &671173612 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 671173613} + - component: {fileID: 671173615} + - component: {fileID: 671173614} + m_Layer: 5 + m_Name: Button Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &671173613 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 671173612} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1422147255} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 117.808, y: 0} + m_SizeDelta: {x: -235.617, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &671173614 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 671173612} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Preview + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 250 + m_fontSizeBase: 250 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 1 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &671173615 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 671173612} + m_CullTransparentMesh: 1 --- !u!1 &755030129 GameObject: m_ObjectHideFlags: 0 @@ -550,16 +1312,16 @@ RectTransform: m_GameObject: {fileID: 755030129} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 + m_LocalScale: {x: 1.6, y: 1.6, z: 1.6} + m_ConstrainProportionsScale: 1 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 3 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 150, y: 150} - m_SizeDelta: {x: 400, y: 400} + m_AnchoredPosition: {x: 100, y: 90} + m_SizeDelta: {x: 256, y: 164} m_Pivot: {x: 0, y: 0.5} --- !u!114 &755030131 MonoBehaviour: @@ -581,9 +1343,9 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 8f5216ce0bfcecc4da0340703872c4ff, type: 3} + m_Sprite: {fileID: 21300000, guid: 5387f0486602abf479f049d9afa9d3cb, type: 3} m_Type: 0 - m_PreserveAspect: 0 + m_PreserveAspect: 1 m_FillCenter: 1 m_FillMethod: 4 m_FillAmount: 1 @@ -610,7 +1372,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -630,16 +1391,19 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: + - {fileID: 1644610031} - {fileID: 1168097235} - {fileID: 1990031299} - {fileID: 1903244524} - {fileID: 755030130} - - {fileID: 8656706101895896162} - - {fileID: 507029407} + - {fileID: 1230251433} + - {fileID: 1422147255} - {fileID: 1135894725} + - {fileID: 2135419030} + - {fileID: 1211177269} - {fileID: 1774458253} - {fileID: 1804488336} - - {fileID: 1796657467} + - {fileID: 1394044035} m_Father: {fileID: 1768150806} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -661,14 +1425,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -686,26 +1450,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4ee87f3cdcccf934b82f9531c90f3457, type: 3} - m_Name: - m_EditorClassIdentifier: - playButton: {fileID: 8656706101895896161} - previewButton: {fileID: 1796657466} - courseList: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - title: {fileID: 1168097236} - description: {fileID: 1990031300} - courseImage: {fileID: 755030131} - progressBar: {fileID: 1135894726} --- !u!1 &1135894724 GameObject: m_ObjectHideFlags: 0 @@ -737,12 +1481,13 @@ RectTransform: m_Children: - {fileID: 599238322} - {fileID: 339096155} + - {fileID: 507029407} m_Father: {fileID: 906197777} - m_RootOrder: 6 + m_RootOrder: 7 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 150, y: -180} + m_AnchoredPosition: {x: 100, y: -180} m_SizeDelta: {x: 400, y: 100} m_Pivot: {x: 0, y: 0.5} --- !u!114 &1135894726 @@ -792,7 +1537,7 @@ MonoBehaviour: m_MinValue: 0 m_MaxValue: 1 m_WholeNumbers: 0 - m_Value: 0 + m_Value: 0.672 m_OnValueChanged: m_PersistentCalls: m_Calls: [] @@ -827,7 +1572,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} @@ -856,16 +1601,16 @@ MonoBehaviour: m_Calls: [] m_text: Title of the course m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4292118016 - m_fontColor: {r: 0, g: 0.5254902, b: 0.8313726, a: 1} - m_enableVertexGradient: 1 + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: topLeft: {r: 0.11764707, g: 0.6745098, b: 1, a: 1} @@ -887,7 +1632,7 @@ MonoBehaviour: m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 1 + m_fontStyle: 0 m_HorizontalAlignment: 2 m_VerticalAlignment: 512 m_textAlignment: 65535 @@ -931,6 +1676,829 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1168097234} m_CullTransparentMesh: 1 +--- !u!1 &1211177268 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1211177269} + - component: {fileID: 1211177272} + - component: {fileID: 1211177271} + - component: {fileID: 1211177270} + m_Layer: 5 + m_Name: Circle (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1211177269 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1211177268} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 270, y: 100} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &1211177270 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1211177268} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 47b8ff2adcd4fa64981587b8490f907b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &1211177271 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1211177268} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1211177272 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1211177268} + m_CullTransparentMesh: 1 +--- !u!1 &1230251432 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1230251433} + - component: {fileID: 1230251435} + - component: {fileID: 1230251434} + m_Layer: 5 + m_Name: Start Course + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1230251433 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1230251432} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.29999998, y: 0.29999998, z: 0.29999998} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 322684579} + - {fileID: 54642281} + - {fileID: 1318079679} + m_Father: {fileID: 906197777} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -71.2, y: -410} + m_SizeDelta: {x: 1524, y: 378} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1230251434 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1230251432} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 2 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_PressedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_SelectedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 322684580} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1451507144} + m_TargetAssemblyTypeName: CourseActivityScreen, CommonScripts + m_MethodName: StartCourse + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!222 &1230251435 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1230251432} + m_CullTransparentMesh: 1 +--- !u!1 &1318079678 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1318079679} + - component: {fileID: 1318079681} + - component: {fileID: 1318079680} + m_Layer: 5 + m_Name: Button Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1318079679 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1318079678} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1230251433} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -550, y: 0} + m_SizeDelta: {x: 280, y: 280} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1318079680 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1318079678} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 20d0d5f265af8554887f17fc0271b1be, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1318079681 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1318079678} + m_CullTransparentMesh: 1 +--- !u!1 &1394044034 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1394044035} + - component: {fileID: 1394044038} + - component: {fileID: 1394044037} + - component: {fileID: 1394044036} + m_Layer: 5 + m_Name: Circle (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1394044035 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1394044034} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 12 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 230, y: -215} + m_SizeDelta: {x: 360, y: 360} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &1394044036 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1394044034} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &1394044037 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1394044034} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1394044038 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1394044034} + m_CullTransparentMesh: 1 +--- !u!1 &1397926485 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1397926486} + - component: {fileID: 1397926487} + m_Layer: 0 + m_Name: Director ExitTo CourseMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1397926486 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1397926485} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2029692578} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &1397926487 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1397926485} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 3912059771208757551, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 0} + - key: {fileID: -7222763729682898453, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: -7222763729682898453, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 1394044036} + - key: {fileID: 3912059771208757551, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 1211177270} + - key: {fileID: -7898205786510554628, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 1451507146} + m_ExposedReferences: + m_References: [] +--- !u!1 &1422147252 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1422147255} + - component: {fileID: 1422147254} + - component: {fileID: 1422147253} + m_Layer: 5 + m_Name: PreviewButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!114 &1422147253 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1422147252} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 2 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_PressedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_SelectedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1431887647} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1451507144} + m_TargetAssemblyTypeName: CourseActivityScreen, CommonScripts + m_MethodName: StartCourse + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!222 &1422147254 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1422147252} + m_CullTransparentMesh: 1 +--- !u!224 &1422147255 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1422147252} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.29999998, y: 0.29999998, z: 0.29999998} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 1431887649} + - {fileID: 671173613} + - {fileID: 633609944} + m_Father: {fileID: 906197777} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -71.2, y: -410} + m_SizeDelta: {x: 1524, y: 378} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1431887646 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1431887649} + - component: {fileID: 1431887648} + - component: {fileID: 1431887647} + m_Layer: 5 + m_Name: Button Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1431887647 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1431887646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.9607843, g: 0.28627452, b: 0.23921569, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 46578af6a9f38ea46bf4f53f79e8fca8, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1431887648 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1431887646} + m_CullTransparentMesh: 1 +--- !u!224 &1431887649 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1431887646} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.3, y: 1.3, z: 1.3} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1422147255} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1388, y: 497} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1451507143 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1451507145} + - component: {fileID: 1451507144} + - component: {fileID: 1451507146} + m_Layer: 0 + m_Name: CourseActivityController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1451507144 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1451507143} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4ee87f3cdcccf934b82f9531c90f3457, type: 3} + m_Name: + m_EditorClassIdentifier: + playButton: {fileID: 1230251432} + previewButton: {fileID: 1422147252} + restartButton: {fileID: 2135419029} + courseList: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} + title: {fileID: 1168097236} + description: {fileID: 1990031300} + courseImage: {fileID: 755030131} + progressBar: {fileID: 1135894726} + progressObject: {fileID: 1135894724} + completedObject: {fileID: 1644610030} + directorEnterFromCourseMenu: {fileID: 492331922} +--- !u!4 &1451507145 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1451507143} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1451507146 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1451507143} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e52de21a22b6dd44c9cc19f810c65059, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Events: + m_Signals: [] + m_Events: [] +--- !u!1 &1644610030 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1644610031} + - component: {fileID: 1644610033} + - component: {fileID: 1644610032} + m_Layer: 5 + m_Name: Completed + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1644610031 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1644610030} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -660, y: 446} + m_SizeDelta: {x: -1684, y: 50} + m_Pivot: {x: 0.5, y: 0} +--- !u!114 &1644610032 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1644610030} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: '* VOLTOOID *' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4279873015 + m_fontColor: {r: 0.96862745, g: 0.6784314, b: 0.09803922, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1644610033 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1644610030} + m_CullTransparentMesh: 1 --- !u!1 &1768150802 GameObject: m_ObjectHideFlags: 0 @@ -979,10 +2547,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -1025,7 +2593,7 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -1039,10 +2607,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 906197777} m_Modifications: - - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument - value: Common/Scenes/ListCoursesScreen - objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name value: ButtonBack @@ -1057,7 +2621,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_RootOrder - value: 7 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchorMax.x @@ -1077,11 +2641,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -1113,11 +2677,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -1138,141 +2702,6 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} m_PrefabInstance: {fileID: 1774458252} m_PrefabAsset: {fileID: 0} ---- !u!1 &1796657466 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1796657467} - - component: {fileID: 1796657470} - - component: {fileID: 1796657469} - - component: {fileID: 1796657468} - m_Layer: 5 - m_Name: TEMPORARY PreviewButton - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1796657467 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1796657466} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: - - {fileID: 1927889859} - - {fileID: 1917544326} - m_Father: {fileID: 906197777} - m_RootOrder: 9 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 1, y: 0} - m_AnchorMax: {x: 1, y: 0} - m_AnchoredPosition: {x: -20, y: 20} - m_SizeDelta: {x: 500, y: 145} - m_Pivot: {x: 1, y: 0} ---- !u!114 &1796657468 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1796657466} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 2 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_PressedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_SelectedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1796657469} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: CourseActivityScreen, CommonScripts - m_MethodName: StartCourse - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!114 &1796657469 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1796657466} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: aa6b260f6addb6746be3dac4f14e3689, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1796657470 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1796657466} - m_CullTransparentMesh: 1 --- !u!1001 &1804488335 PrefabInstance: m_ObjectHideFlags: 0 @@ -1318,7 +2747,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_RootOrder - value: 8 + value: 11 objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_AnchorMax.x @@ -1450,11 +2879,11 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 250, y: -100} + m_AnchoredPosition: {x: 200, y: -100} m_SizeDelta: {x: 1000, y: 400} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1903244525 @@ -1486,8 +2915,8 @@ MonoBehaviour: Je hebt ook de optie een gebaar over te slaan. Je vooruitgang wordt opgeslagen, je kan dus stoppen tijdens een les en hem later hervatten.' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -1511,8 +2940,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 40 - m_fontSizeBase: 40 + m_fontSize: 45 + m_fontSizeBase: 45 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 @@ -1561,217 +2990,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1903244523} m_CullTransparentMesh: 1 ---- !u!1 &1917544325 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1917544326} - - component: {fileID: 1917544328} - - component: {fileID: 1917544327} - m_Layer: 5 - m_Name: Image - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1917544326 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1917544325} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 1796657467} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0.5} - m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 20, y: 0} - m_SizeDelta: {x: 100, y: 100} - m_Pivot: {x: 0, y: 0.5} ---- !u!114 &1917544327 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1917544325} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 43db869a07cf51f45a411b6e4a417743, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1917544328 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1917544325} - m_CullTransparentMesh: 1 ---- !u!1 &1927889858 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1927889859} - - component: {fileID: 1927889861} - - component: {fileID: 1927889860} - m_Layer: 5 - m_Name: Text (TMP) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1927889859 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1927889858} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 1796657467} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1927889860 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1927889858} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: PREVIEW - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4278190335 - m_fontColor: {r: 1, g: 0, b: 0, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 80 - m_fontSizeBase: 80 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 150.5354, y: 26.162018, z: 37.023926, w: 27.4693} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1927889861 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1927889858} - m_CullTransparentMesh: 1 --- !u!1 &1931916397 GameObject: m_ObjectHideFlags: 0 @@ -1823,19 +3041,19 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 0, g: 0.5254902, b: 0.8313726, a: 1} + m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 + m_Sprite: {fileID: 21300000, guid: 02283f528ead8084db69c7d8a459f0af, type: 3} + m_Type: 3 + m_PreserveAspect: 1 m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 + m_FillMethod: 0 + m_FillAmount: 0.672 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -1879,11 +3097,11 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 1 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 250, y: 200} + m_AnchoredPosition: {x: 200, y: 200} m_SizeDelta: {x: 1000, y: 200} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1990031300 @@ -1908,15 +3126,15 @@ MonoBehaviour: m_Calls: [] m_text: This is a description of the following course m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} + rgba: 4290616898 + m_fontColor: {r: 0.25882354, g: 0.61960787, b: 0.7411765, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -1933,13 +3151,13 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 52 - m_fontSizeBase: 52 + m_fontSize: 55 + m_fontSizeBase: 55 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 1 + m_fontStyle: 0 m_HorizontalAlignment: 1 m_VerticalAlignment: 512 m_textAlignment: 65535 @@ -1983,7 +3201,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1990031298} m_CullTransparentMesh: 1 ---- !u!1 &8656706101895896161 +--- !u!1 &2029692577 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1991,46 +3209,79 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 8656706101895896162} - - component: {fileID: 8656706101895896477} - - component: {fileID: 8656706101895896476} - - component: {fileID: 8656706101895896163} - m_Layer: 5 - m_Name: Play Button + - component: {fileID: 2029692578} + m_Layer: 0 + m_Name: SceneTransitions m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &8656706101895896162 +--- !u!4 &2029692578 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2029692577} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 492331921} + - {fileID: 1397926486} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2135419029 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2135419030} + - component: {fileID: 2135419032} + - component: {fileID: 2135419031} + m_Layer: 5 + m_Name: Reload Course + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2135419030 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706101895896161} + m_GameObject: {fileID: 2135419029} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} + m_LocalScale: {x: 0.29999998, y: 0.29999998, z: 0.29999998} m_ConstrainProportionsScale: 1 m_Children: - - {fileID: 8656706103192357353} - - {fileID: 8656706101947925524} + - {fileID: 192988724} + - {fileID: 491907974} + - {fileID: 519124402} m_Father: {fileID: 906197777} - m_RootOrder: 4 + m_RootOrder: 8 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 1, y: 0} - m_AnchorMax: {x: 1, y: 0} - m_AnchoredPosition: {x: -20, y: 20} - m_SizeDelta: {x: 500, y: 145} - m_Pivot: {x: 1, y: 0} ---- !u!114 &8656706101895896163 + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 440.8, y: -410} + m_SizeDelta: {x: 1524, y: 378} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2135419031 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706101895896161} + m_GameObject: {fileID: 2135419029} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} @@ -2053,9 +3304,9 @@ MonoBehaviour: m_ColorMultiplier: 1 m_FadeDuration: 0.1 m_SpriteState: - m_HighlightedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_PressedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_SelectedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} + m_HighlightedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_PressedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_SelectedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} m_DisabledSprite: {fileID: 0} m_AnimationTriggers: m_NormalTrigger: Normal @@ -2064,13 +3315,13 @@ MonoBehaviour: m_SelectedTrigger: Selected m_DisabledTrigger: Disabled m_Interactable: 1 - m_TargetGraphic: {fileID: 8656706101895896476} + m_TargetGraphic: {fileID: 192988725} m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 906197780} + - m_Target: {fileID: 1451507144} m_TargetAssemblyTypeName: CourseActivityScreen, CommonScripts - m_MethodName: StartCourse + m_MethodName: ResetCourseProgress m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} @@ -2080,252 +3331,11 @@ MonoBehaviour: m_StringArgument: m_BoolArgument: 0 m_CallState: 2 ---- !u!114 &8656706101895896476 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706101895896161} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: aa6b260f6addb6746be3dac4f14e3689, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &8656706101895896477 +--- !u!222 &2135419032 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706101895896161} - m_CullTransparentMesh: 1 ---- !u!224 &8656706101947925524 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706101947925531} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 8656706101895896162} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0.5} - m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 20, y: 0} - m_SizeDelta: {x: 100, y: 100} - m_Pivot: {x: 0, y: 0.5} ---- !u!114 &8656706101947925525 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706101947925531} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 43db869a07cf51f45a411b6e4a417743, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &8656706101947925526 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706101947925531} - m_CullTransparentMesh: 1 ---- !u!1 &8656706101947925531 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 8656706101947925524} - - component: {fileID: 8656706101947925526} - - component: {fileID: 8656706101947925525} - m_Layer: 5 - m_Name: Image - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!1 &8656706103192357352 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 8656706103192357353} - - component: {fileID: 8656706103192357355} - - component: {fileID: 8656706103192357354} - m_Layer: 5 - m_Name: Text (TMP) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &8656706103192357353 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706103192357352} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 8656706101895896162} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &8656706103192357354 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706103192357352} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: Begin - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 80 - m_fontSizeBase: 80 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 150.5354, y: 26.162018, z: 37.023926, w: 27.4693} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &8656706103192357355 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8656706103192357352} + m_GameObject: {fileID: 2135419029} m_CullTransparentMesh: 1 diff --git a/Assets/Common/Scenes/CoursesMenuScreen.unity b/Assets/Common/Scenes/CoursesMenuScreen.unity index 34133a6..8772b4e 100644 --- a/Assets/Common/Scenes/CoursesMenuScreen.unity +++ b/Assets/Common/Scenes/CoursesMenuScreen.unity @@ -123,6 +123,69 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &46889609 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 46889611} + - component: {fileID: 46889610} + m_Layer: 0 + m_Name: Director EnterFrom ListCourses+CourseActivity + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!320 &46889610 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 46889609} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 4675612037800af438b7fc34ec77fdf3, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: -3525077244693759028, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 546454010} + - key: {fileID: 8567462958465905521, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 160918651} + - key: {fileID: -916505273809897906, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 2004184481} + - key: {fileID: 2497902352991694537, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 731809079} + - key: {fileID: -4664426466800762542, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 8299246692221626396} + - key: {fileID: -6792405358425382423, guid: 4675612037800af438b7fc34ec77fdf3, type: 2} + value: {fileID: 286733261} + - key: {fileID: -4585668829722489210, guid: 4675612037800af438b7fc34ec77fdf3, type: 2} + value: {fileID: 465973278} + m_ExposedReferences: + m_References: [] +--- !u!4 &46889611 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 46889609} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 974086058} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &129643495 GameObject: m_ObjectHideFlags: 0 @@ -202,6 +265,7 @@ GameObject: - component: {fileID: 160918648} - component: {fileID: 160918650} - component: {fileID: 160918649} + - component: {fileID: 160918651} m_Layer: 5 m_Name: Recent m_TagString: Untagged @@ -222,7 +286,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} @@ -251,15 +315,15 @@ MonoBehaviour: m_Calls: [] m_text: Recente lessen m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4278190080 - m_fontColor: {r: 0, g: 0, b: 0, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -276,8 +340,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 60 - m_fontSizeBase: 60 + m_fontSize: 90 + m_fontSizeBase: 90 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 @@ -326,6 +390,414 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 160918647} m_CullTransparentMesh: 1 +--- !u!95 &160918651 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160918647} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: ef147e3ac03990149bd4a8660eeec218, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &286733259 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 286733260} + - component: {fileID: 286733263} + - component: {fileID: 286733262} + - component: {fileID: 286733261} + m_Layer: 5 + m_Name: Circle (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &286733260 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 286733259} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: -160, y: -250} + m_SizeDelta: {x: 535, y: 535} + m_Pivot: {x: 0, y: 0} +--- !u!95 &286733261 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 286733259} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 47b8ff2adcd4fa64981587b8490f907b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &286733262 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 286733259} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &286733263 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 286733259} + m_CullTransparentMesh: 1 +--- !u!1 &415768231 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 415768232} + - component: {fileID: 415768233} + m_Layer: 0 + m_Name: Director EnterFrom MainMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &415768232 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 415768231} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 974086058} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &415768233 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 415768231} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: -3525077244693759028, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 546454010} + - key: {fileID: 8567462958465905521, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 160918651} + - key: {fileID: -916505273809897906, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 2004184481} + - key: {fileID: 2497902352991694537, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 731809079} + - key: {fileID: -4664426466800762542, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 8299246692221626396} + m_ExposedReferences: + m_References: [] +--- !u!1 &429808816 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 429808817} + - component: {fileID: 429808819} + - component: {fileID: 429808818} + m_Layer: 5 + m_Name: Button Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &429808817 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 429808816} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 546454007} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 187, y: 0} + m_SizeDelta: {x: -374, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &429808818 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 429808816} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Alle Lessen + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 250 + m_fontSizeBase: 250 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &429808819 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 429808816} + m_CullTransparentMesh: 1 +--- !u!1 &465973276 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 465973277} + - component: {fileID: 465973280} + - component: {fileID: 465973279} + - component: {fileID: 465973278} + m_Layer: 5 + m_Name: Circle (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &465973277 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 465973276} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 260, y: -300} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 0, y: 0} +--- !u!95 &465973278 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 465973276} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &465973279 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 465973276} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &465973280 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 465973276} + m_CullTransparentMesh: 1 --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -410,6 +882,132 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &546454006 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 546454007} + - component: {fileID: 546454009} + - component: {fileID: 546454008} + - component: {fileID: 546454010} + m_Layer: 5 + m_Name: All Courses + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &546454007 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 546454006} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.29999998, y: 0.29999998, z: 0.29999998} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 1872102184} + - {fileID: 429808817} + - {fileID: 742011645} + m_Father: {fileID: 906197777} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -450} + m_SizeDelta: {x: 1524, y: 378} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &546454008 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 546454006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 2 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_PressedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_SelectedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1872102185} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1216747366} + m_TargetAssemblyTypeName: CourseMenuScreen, CommonScripts + m_MethodName: GotoListOfCourses + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!222 &546454009 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 546454006} + m_CullTransparentMesh: 1 +--- !u!95 &546454010 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 546454006} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1 &731809075 GameObject: m_ObjectHideFlags: 0 @@ -421,6 +1019,7 @@ GameObject: - component: {fileID: 731809076} - component: {fileID: 731809078} - component: {fileID: 731809077} + - component: {fileID: 731809079} m_Layer: 5 m_Name: Recommended m_TagString: Untagged @@ -441,7 +1040,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 3 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -470,15 +1069,15 @@ MonoBehaviour: m_Calls: [] m_text: Aanbevolen lessen m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4278190080 - m_fontColor: {r: 0, g: 0, b: 0, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -495,8 +1094,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 60 - m_fontSizeBase: 60 + m_fontSize: 90 + m_fontSizeBase: 90 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 @@ -545,6 +1144,102 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 731809075} m_CullTransparentMesh: 1 +--- !u!95 &731809079 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 731809075} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &742011644 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 742011645} + - component: {fileID: 742011647} + - component: {fileID: 742011646} + m_Layer: 5 + m_Name: Button Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &742011645 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 742011644} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 546454007} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -550, y: 0} + m_SizeDelta: {x: 280, y: 280} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &742011646 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 742011644} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 97d2ed59587b322479bc163554094dec, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &742011647 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 742011644} + m_CullTransparentMesh: 1 --- !u!1 &809758277 GameObject: m_ObjectHideFlags: 0 @@ -555,6 +1250,7 @@ GameObject: m_Component: - component: {fileID: 809758278} - component: {fileID: 809758279} + - component: {fileID: 809758280} m_Layer: 5 m_Name: Recommended Courses m_TagString: Untagged @@ -575,7 +1271,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 4 + m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -589,7 +1285,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 809758277} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} m_Name: @@ -608,6 +1304,26 @@ MonoBehaviour: m_ChildScaleWidth: 0 m_ChildScaleHeight: 0 m_ReverseArrangement: 0 +--- !u!95 &809758280 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 809758277} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1 &906197776 GameObject: m_ObjectHideFlags: 0 @@ -619,7 +1335,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -639,14 +1354,16 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: + - {fileID: 546454007} - {fileID: 160918648} - {fileID: 922270551} - {fileID: 1737823345} - {fileID: 731809076} - {fileID: 809758278} - - {fileID: 1709971555} - {fileID: 1301399289} - {fileID: 1782112234} + - {fileID: 286733260} + - {fileID: 465973277} m_Father: {fileID: 1768150806} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -668,14 +1385,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -693,24 +1410,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 00e2726fda637a1488461b7a43e46343, type: 3} - m_Name: - m_EditorClassIdentifier: - noRecentCourses: {fileID: 922270550} - recentCoursesContainer: {fileID: 1737823345} - recommendedCoursesContainer: {fileID: 809758278} - courseItem: {fileID: 4959898007614330357, guid: baf585123c6364d40a17b89676eb350d, type: 3} - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - courseList: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} --- !u!1 &922270550 GameObject: m_ObjectHideFlags: 0 @@ -742,7 +1441,7 @@ RectTransform: m_Children: - {fileID: 2004184478} m_Father: {fileID: 906197777} - m_RootOrder: 1 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} @@ -757,7 +1456,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 922270550} m_CullTransparentMesh: 1 ---- !u!1 &1048519161 +--- !u!1 &974086057 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -765,274 +1464,87 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1048519162} - - component: {fileID: 1048519164} - - component: {fileID: 1048519163} - m_Layer: 5 - m_Name: Text (TMP) + - component: {fileID: 974086058} + m_Layer: 0 + m_Name: SceneTransitions m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1048519162 -RectTransform: +--- !u!4 &974086058 +Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1048519161} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1709971555} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1048519163 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1048519161} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: 'Alle lessen - -' - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1048519164 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1048519161} - m_CullTransparentMesh: 1 ---- !u!224 &1301399289 stripped -RectTransform: - m_CorrespondingSourceObject: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - m_PrefabInstance: {fileID: 8299246692221626394} - m_PrefabAsset: {fileID: 0} ---- !u!1 &1709971554 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1709971555} - - component: {fileID: 1709971558} - - component: {fileID: 1709971557} - - component: {fileID: 1709971556} - m_Layer: 5 - m_Name: All Courses - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1709971555 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1709971554} + m_GameObject: {fileID: 974086057} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 1048519162} - m_Father: {fileID: 906197777} - m_RootOrder: 5 + - {fileID: 46889611} + - {fileID: 415768232} + m_Father: {fileID: 0} + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0} - m_AnchorMax: {x: 0.5, y: 0} - m_AnchoredPosition: {x: 0, y: 50} - m_SizeDelta: {x: 380, y: 120} - m_Pivot: {x: 0.5, y: 0} ---- !u!114 &1709971556 +--- !u!1 &1216747365 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1216747367} + - component: {fileID: 1216747366} + m_Layer: 0 + m_Name: CoursesMenuController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1216747366 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1709971554} + m_GameObject: {fileID: 1216747365} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Script: {fileID: 11500000, guid: 00e2726fda637a1488461b7a43e46343, type: 3} m_Name: m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1709971557} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: CourseMenuScreen, CommonScripts - m_MethodName: GotoListOfCourses - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!114 &1709971557 -MonoBehaviour: + noRecentCourses: {fileID: 922270550} + recentCoursesContainer: {fileID: 1737823345} + recommendedCoursesContainer: {fileID: 809758278} + courseItem: {fileID: 4959898007614330357, guid: baf585123c6364d40a17b89676eb350d, type: 3} + courseList: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} + directorEnterFromDefault: {fileID: 46889610} + directorEnterFromMainMenu: {fileID: 415768233} +--- !u!4 &1216747367 +Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1709971554} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1709971558 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} + m_GameObject: {fileID: 1216747365} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!224 &1301399289 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + m_PrefabInstance: {fileID: 8299246692221626394} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1709971554} - m_CullTransparentMesh: 1 --- !u!1 &1737823344 GameObject: m_ObjectHideFlags: 0 @@ -1043,6 +1555,7 @@ GameObject: m_Component: - component: {fileID: 1737823345} - component: {fileID: 1737823346} + - component: {fileID: 1737823347} m_Layer: 5 m_Name: Recent Courses m_TagString: Untagged @@ -1063,7 +1576,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} @@ -1096,6 +1609,26 @@ MonoBehaviour: m_ChildScaleWidth: 0 m_ChildScaleHeight: 0 m_ReverseArrangement: 0 +--- !u!95 &1737823347 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1737823344} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1 &1768150802 GameObject: m_ObjectHideFlags: 0 @@ -1144,10 +1677,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -1190,7 +1723,7 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -1347,6 +1880,82 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} m_PrefabInstance: {fileID: 1782112233} m_PrefabAsset: {fileID: 0} +--- !u!1 &1872102183 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1872102184} + - component: {fileID: 1872102186} + - component: {fileID: 1872102185} + m_Layer: 5 + m_Name: Button Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1872102184 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1872102183} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.3, y: 1.3, z: 1.3} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 546454007} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1388, y: 497} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1872102185 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1872102183} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 46578af6a9f38ea46bf4f53f79e8fca8, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1872102186 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1872102183} + m_CullTransparentMesh: 1 --- !u!1 &2004184477 GameObject: m_ObjectHideFlags: 0 @@ -1358,6 +1967,7 @@ GameObject: - component: {fileID: 2004184478} - component: {fileID: 2004184480} - component: {fileID: 2004184479} + - component: {fileID: 2004184481} m_Layer: 5 m_Name: Text (TMP) m_TagString: Untagged @@ -1407,8 +2017,8 @@ MonoBehaviour: m_Calls: [] m_text: Nog geen lessen gestart m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -1482,6 +2092,26 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2004184477} m_CullTransparentMesh: 1 +--- !u!95 &2004184481 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2004184477} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1001 &8299246692221626394 PrefabInstance: m_ObjectHideFlags: 0 @@ -1527,11 +2157,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -1563,11 +2193,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -1583,3 +2213,28 @@ PrefabInstance: objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} +--- !u!1 &8299246692221626395 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + m_PrefabInstance: {fileID: 8299246692221626394} + m_PrefabAsset: {fileID: 0} +--- !u!95 &8299246692221626396 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8299246692221626395} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: ca332ce2e8825e34f82740a12f57810c, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 diff --git a/Assets/Common/Scenes/ListCoursesScreen.unity b/Assets/Common/Scenes/ListCoursesScreen.unity index 38501ab..442f9fe 100644 --- a/Assets/Common/Scenes/ListCoursesScreen.unity +++ b/Assets/Common/Scenes/ListCoursesScreen.unity @@ -236,7 +236,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_RootOrder - value: 3 + value: 6 objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_AnchorMax.x @@ -341,246 +341,6 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} m_PrefabInstance: {fileID: 289602554} m_PrefabAsset: {fileID: 0} ---- !u!1 &316289682 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 316289683} - m_Layer: 5 - m_Name: Sliding Area - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &316289683 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 316289682} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1708714069} - m_Father: {fileID: 357869362} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: -20, y: -20} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!1 &357869361 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 357869362} - - component: {fileID: 357869365} - - component: {fileID: 357869364} - - component: {fileID: 357869363} - m_Layer: 5 - m_Name: Scrollbar Horizontal - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &357869362 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 357869361} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 316289683} - m_Father: {fileID: 1119454410} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 0} - m_AnchoredPosition: {x: 0, y: -20} - m_SizeDelta: {x: 0, y: 20} - m_Pivot: {x: 0, y: 0} ---- !u!114 &357869363 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 357869361} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1708714070} - m_HandleRect: {fileID: 1708714069} - m_Direction: 0 - m_Value: 0 - m_Size: 1 - m_NumberOfSteps: 0 - m_OnValueChanged: - m_PersistentCalls: - m_Calls: [] ---- !u!114 &357869364 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 357869361} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &357869365 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 357869361} - m_CullTransparentMesh: 1 ---- !u!1 &461792788 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 461792789} - - component: {fileID: 461792790} - - component: {fileID: 461792791} - m_Layer: 5 - m_Name: Content - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &461792789 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 461792788} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1181759420} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0, y: 1} ---- !u!114 &461792790 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 461792788} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Padding: - m_Left: 10 - m_Right: 10 - m_Top: 10 - m_Bottom: 10 - m_ChildAlignment: 0 - m_StartCorner: 0 - m_StartAxis: 0 - m_CellSize: {x: 256, y: 256} - m_Spacing: {x: 10, y: 10} - m_Constraint: 2 - m_ConstraintCount: 3 ---- !u!114 &461792791 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 461792788} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} - m_Name: - m_EditorClassIdentifier: - m_HorizontalFit: 2 - m_VerticalFit: 2 --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -821,6 +581,235 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 525645767} m_CullTransparentMesh: 1 +--- !u!1 &604063080 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 604063081} + m_Layer: 0 + m_Name: SceneTransitions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &604063081 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 604063080} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1888678211} + - {fileID: 620870057} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &620870056 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 620870057} + - component: {fileID: 620870058} + m_Layer: 0 + m_Name: Director ExitTo CourseMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &620870057 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 620870056} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 604063081} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &620870058 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 620870056} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 3912059771208757551, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 888670397} + - key: {fileID: -7222763729682898453, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 2034764083} + - key: {fileID: 0} + value: {fileID: 1417412677} + - key: {fileID: -7222763729682898453, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 2034764083} + - key: {fileID: 3912059771208757551, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 888670397} + - key: {fileID: -7898205786510554628, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 1417412677} + m_ExposedReferences: + m_References: [] +--- !u!1 &745485882 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 745485883} + - component: {fileID: 745485885} + - component: {fileID: 745485884} + m_Layer: 5 + m_Name: Recent + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &745485883 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745485882} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -30} + m_SizeDelta: {x: 540, y: 120} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &745485884 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745485882} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Alle lessen + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 90 + m_fontSizeBase: 90 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &745485885 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745485882} + m_CullTransparentMesh: 1 --- !u!1 &846528618 GameObject: m_ObjectHideFlags: 0 @@ -874,6 +863,103 @@ MonoBehaviour: m_EditorClassIdentifier: m_Padding: {x: -8, y: -5, z: -8, w: -5} m_Softness: {x: 0, y: 0} +--- !u!1 &888670395 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 888670396} + - component: {fileID: 888670399} + - component: {fileID: 888670398} + - component: {fileID: 888670397} + m_Layer: 5 + m_Name: Circle (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &888670396 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 888670395} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 270, y: 100} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &888670397 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 888670395} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 47b8ff2adcd4fa64981587b8490f907b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &888670398 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 888670395} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &888670399 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 888670395} + m_CullTransparentMesh: 1 --- !u!1 &906197776 GameObject: m_ObjectHideFlags: 0 @@ -885,7 +971,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -905,8 +990,11 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: + - {fileID: 745485883} + - {fileID: 888670396} + - {fileID: 2034764082} - {fileID: 1503088043} - - {fileID: 1119454410} + - {fileID: 1934345758} - {fileID: 1143402633} - {fileID: 289602555} m_Father: {fileID: 1768150806} @@ -930,14 +1018,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -955,22 +1043,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0fac0bf527487ad48835aff400b1f762, type: 3} - m_Name: - m_EditorClassIdentifier: - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - courseContainer: {fileID: 461792789} - courseItemPrefab: {fileID: 4959898007614330357, guid: baf585123c6364d40a17b89676eb350d, type: 3} - courseList: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} --- !u!1 &994710774 GameObject: m_ObjectHideFlags: 0 @@ -1106,115 +1178,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 994710774} m_CullTransparentMesh: 1 ---- !u!1 &1119454409 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1119454410} - - component: {fileID: 1119454413} - - component: {fileID: 1119454412} - - component: {fileID: 1119454411} - m_Layer: 5 - m_Name: Courses - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1119454410 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1119454409} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1181759420} - - {fileID: 357869362} - m_Father: {fileID: 906197777} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 1590, y: 808} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1119454411 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1119454409} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Content: {fileID: 461792789} - m_Horizontal: 1 - m_Vertical: 0 - m_MovementType: 2 - m_Elasticity: 0.1 - m_Inertia: 1 - m_DecelerationRate: 0.135 - m_ScrollSensitivity: 1 - m_Viewport: {fileID: 1181759420} - m_HorizontalScrollbar: {fileID: 357869363} - m_VerticalScrollbar: {fileID: 0} - m_HorizontalScrollbarVisibility: 0 - m_VerticalScrollbarVisibility: 0 - m_HorizontalScrollbarSpacing: -3 - m_VerticalScrollbarSpacing: -3 - m_OnValueChanged: - m_PersistentCalls: - m_Calls: [] ---- !u!114 &1119454412 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1119454409} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.39215687} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1119454413 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1119454409} - m_CullTransparentMesh: 1 --- !u!1001 &1143402632 PrefabInstance: m_ObjectHideFlags: 0 @@ -1223,8 +1186,16 @@ PrefabInstance: m_TransformParent: {fileID: 906197777} m_Modifications: - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument - value: Common/Scenes/CoursesScreen + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Target + value: + objectReference: {fileID: 620870058} + - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: Play + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: UnityEngine.Playables.PlayableDirector, UnityEngine objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name @@ -1240,7 +1211,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_RootOrder - value: 2 + value: 5 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchorMax.x @@ -1260,11 +1231,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -1296,11 +1267,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -1321,7 +1292,18 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} m_PrefabInstance: {fileID: 1143402632} m_PrefabAsset: {fileID: 0} ---- !u!1 &1181759419 +--- !u!114 &1143402634 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4518652150503380115, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + m_PrefabInstance: {fileID: 1143402632} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c3dd279b546423e4a8a1b28819a6c4a1, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1417412674 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1329,89 +1311,77 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1181759420} - - component: {fileID: 1181759423} - - component: {fileID: 1181759422} - - component: {fileID: 1181759421} - m_Layer: 5 - m_Name: Viewport + - component: {fileID: 1417412676} + - component: {fileID: 1417412675} + - component: {fileID: 1417412677} + m_Layer: 0 + m_Name: ListCoursesController m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1181759420 -RectTransform: +--- !u!114 &1417412675 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1181759419} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_GameObject: {fileID: 1417412674} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0fac0bf527487ad48835aff400b1f762, type: 3} + m_Name: + m_EditorClassIdentifier: + courseContainer: {fileID: 1934345758} + courseItemPrefab: {fileID: 4959898007614330357, guid: baf585123c6364d40a17b89676eb350d, type: 3} + courseList: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} + directorEnterFromCourseMenu: {fileID: 1888678212} +--- !u!4 &1417412676 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1417412674} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 461792789} - m_Father: {fileID: 1119454410} - m_RootOrder: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1181759421 +--- !u!114 &1417412677 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1181759419} + m_GameObject: {fileID: 1417412674} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Script: {fileID: 11500000, guid: e52de21a22b6dd44c9cc19f810c65059, type: 3} m_Name: m_EditorClassIdentifier: - m_ShowMaskGraphic: 0 ---- !u!114 &1181759422 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1181759419} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1181759423 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1181759419} - m_CullTransparentMesh: 1 + m_Events: + m_Signals: + - {fileID: 11400000, guid: 43d3b5349c78425499a459f42eed4e88, type: 2} + m_Events: + - m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1143402634} + m_TargetAssemblyTypeName: BackButton, CommonScripts + m_MethodName: Back + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 --- !u!1 &1503088042 GameObject: m_ObjectHideFlags: 0 @@ -1445,11 +1415,11 @@ RectTransform: m_Children: - {fileID: 846528619} m_Father: {fileID: 906197777} - m_RootOrder: 0 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} - m_AnchoredPosition: {x: 0, y: -50} + m_AnchoredPosition: {x: 0, y: -990} m_SizeDelta: {x: 600, y: 60} m_Pivot: {x: 0.5, y: 1} --- !u!114 &1503088044 @@ -1588,82 +1558,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1503088042} m_CullTransparentMesh: 1 ---- !u!1 &1708714068 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1708714069} - - component: {fileID: 1708714071} - - component: {fileID: 1708714070} - m_Layer: 5 - m_Name: Handle - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1708714069 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1708714068} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 316289683} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 20, y: 20} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1708714070 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1708714068} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1708714071 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1708714068} - m_CullTransparentMesh: 1 --- !u!1 &1768150802 GameObject: m_ObjectHideFlags: 0 @@ -1712,10 +1606,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -1758,10 +1652,221 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} +--- !u!1 &1888678210 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1888678211} + - component: {fileID: 1888678212} + m_Layer: 0 + m_Name: Director EnterFrom CourseMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1888678211 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1888678210} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 604063081} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &1888678212 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1888678210} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 3912059771208757551, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 888670397} + - key: {fileID: -7222763729682898453, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 2034764083} + m_ExposedReferences: + m_References: [] +--- !u!1 &1934345757 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1934345758} + - component: {fileID: 1934345759} + m_Layer: 5 + m_Name: Courses + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1934345758 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1934345757} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -20, y: 0} + m_SizeDelta: {x: -360, y: -320.00003} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1934345759 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1934345757} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 10 + m_Right: 10 + m_Top: 10 + m_Bottom: 10 + m_ChildAlignment: 4 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 350, y: 350} + m_Spacing: {x: 10, y: 10} + m_Constraint: 0 + m_ConstraintCount: 2 +--- !u!1 &2034764081 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2034764082} + - component: {fileID: 2034764085} + - component: {fileID: 2034764084} + - component: {fileID: 2034764083} + m_Layer: 5 + m_Name: Circle (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2034764082 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2034764081} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 230, y: -215} + m_SizeDelta: {x: 360, y: 360} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &2034764083 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2034764081} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &2034764084 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2034764081} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2034764085 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2034764081} + m_CullTransparentMesh: 1 diff --git a/Assets/Common/Scenes/ListMinigamesScreen.unity b/Assets/Common/Scenes/ListMinigamesScreen.unity index 01e71d4..0a3b602 100644 --- a/Assets/Common/Scenes/ListMinigamesScreen.unity +++ b/Assets/Common/Scenes/ListMinigamesScreen.unity @@ -239,10 +239,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -285,50 +285,13 @@ RectTransform: m_Children: - {fileID: 1380805077} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} ---- !u!1 &167820757 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 167820758} - m_Layer: 5 - m_Name: Sliding Area - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &167820758 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 167820757} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1486682951} - m_Father: {fileID: 1354622762} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: -20, y: -20} - m_Pivot: {x: 0.5, y: 0.5} --- !u!1001 &238926233 PrefabInstance: m_ObjectHideFlags: 0 @@ -336,6 +299,30 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 1380805077} m_Modifications: + - target: {fileID: 1769699556132214506, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1769699556132214506, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1769699556132214506, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1769699556132214506, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1769699556132214506, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1935285004959629519, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} - target: {fileID: 2823887524698191629, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_Name value: ButtonUser @@ -350,7 +337,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_RootOrder - value: 3 + value: 5 objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_AnchorMax.x @@ -428,6 +415,26 @@ PrefabInstance: propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument value: Common/Scenes/StartScreen objectReference: {fileID: 0} + - target: {fileID: 4001770636160324653, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4001770636160324653, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4001770636160324653, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4001770636160324653, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4001770636160324653, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} --- !u!224 &238926234 stripped @@ -488,6 +495,141 @@ MonoBehaviour: m_EditorClassIdentifier: m_Padding: {x: -8, y: -5, z: -8, w: -5} m_Softness: {x: 0, y: 0} +--- !u!1 &413373407 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 413373408} + - component: {fileID: 413373410} + - component: {fileID: 413373409} + m_Layer: 5 + m_Name: Recent + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &413373408 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 413373407} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1380805077} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -30} + m_SizeDelta: {x: 540, y: 120} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &413373409 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 413373407} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Spelletjes + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 90 + m_fontSizeBase: 90 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &413373410 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 413373407} + m_CullTransparentMesh: 1 --- !u!1 &455430114 GameObject: m_ObjectHideFlags: 0 @@ -572,6 +714,67 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1093369503 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1093369504} + - component: {fileID: 1093369505} + m_Layer: 0 + m_Name: Director ExitTo CourseMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1093369504 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1093369503} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1800407625} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &1093369505 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1093369503} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 3912059771208757551, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 0} + - key: {fileID: -7222763729682898453, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: -7222763729682898453, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 2141275318} + - key: {fileID: 3912059771208757551, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 2126874144} + - key: {fileID: -7898205786510554628, guid: 735f6e8af06d3724cb4bb8442e891944, type: 2} + value: {fileID: 1821407074} + m_ExposedReferences: + m_References: [] --- !u!1 &1097800606 GameObject: m_ObjectHideFlags: 0 @@ -761,7 +964,7 @@ RectTransform: m_Children: - {fileID: 294756597} m_Father: {fileID: 1380805077} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} @@ -904,224 +1107,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1099058600} m_CullTransparentMesh: 1 ---- !u!1 &1354622761 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1354622762} - - component: {fileID: 1354622765} - - component: {fileID: 1354622764} - - component: {fileID: 1354622763} - m_Layer: 5 - m_Name: Scrollbar Horizontal - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1354622762 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1354622761} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 167820758} - m_Father: {fileID: 1570876499} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 0} - m_AnchoredPosition: {x: 0, y: -20} - m_SizeDelta: {x: 0, y: 20} - m_Pivot: {x: 0, y: 0} ---- !u!114 &1354622763 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1354622761} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1486682952} - m_HandleRect: {fileID: 1486682951} - m_Direction: 0 - m_Value: 0 - m_Size: 1 - m_NumberOfSteps: 0 - m_OnValueChanged: - m_PersistentCalls: - m_Calls: [] ---- !u!114 &1354622764 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1354622761} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1354622765 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1354622761} - m_CullTransparentMesh: 1 ---- !u!1 &1379945946 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1379945947} - - component: {fileID: 1379945950} - - component: {fileID: 1379945949} - - component: {fileID: 1379945948} - m_Layer: 5 - m_Name: Viewport - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1379945947 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1379945946} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1832508913} - m_Father: {fileID: 1570876499} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1379945948 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1379945946} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} - m_Name: - m_EditorClassIdentifier: - m_ShowMaskGraphic: 0 ---- !u!114 &1379945949 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1379945946} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1379945950 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1379945946} - m_CullTransparentMesh: 1 --- !u!1 &1380805076 GameObject: m_ObjectHideFlags: 0 @@ -1133,7 +1118,6 @@ GameObject: - component: {fileID: 1380805077} - component: {fileID: 1380805080} - component: {fileID: 1380805079} - - component: {fileID: 1380805081} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -1153,10 +1137,13 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: + - {fileID: 413373408} - {fileID: 1099058601} - - {fileID: 1570876499} + - {fileID: 2146756454} + - {fileID: 2126874143} - {fileID: 1605366630} - {fileID: 238926234} + - {fileID: 2141275317} m_Father: {fileID: 79114699} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -1178,14 +1165,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1203,22 +1190,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1380805076} m_CullTransparentMesh: 1 ---- !u!114 &1380805081 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1380805076} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2dd453d411c3b3e458a7b133764c6b64, type: 3} - m_Name: - m_EditorClassIdentifier: - minigameContainer: {fileID: 1832508913} - minigameItemPrefab: {fileID: 4959898007614330357, guid: e5eaffcdbecf2ab48a94311753d10e09, type: 3} - minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} ---- !u!1 &1486682950 +--- !u!1 &1390425318 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1226,183 +1198,55 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1486682951} - - component: {fileID: 1486682953} - - component: {fileID: 1486682952} - m_Layer: 5 - m_Name: Handle + - component: {fileID: 1390425320} + - component: {fileID: 1390425319} + m_Layer: 0 + m_Name: Director EnterFrom MainMenu m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1486682951 -RectTransform: +--- !u!320 &1390425319 +PlayableDirector: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1486682950} + m_GameObject: {fileID: 1390425318} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: c9a1662ababacc549a2b60d2bddb6a11, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 3912059771208757551, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 0} + - key: {fileID: -7222763729682898453, guid: 17824baf0a53c5246bead5f5a446767d, type: 2} + value: {fileID: 0} + - key: {fileID: -7222763729682898453, guid: c9a1662ababacc549a2b60d2bddb6a11, type: 2} + value: {fileID: 2141275318} + - key: {fileID: 3912059771208757551, guid: c9a1662ababacc549a2b60d2bddb6a11, type: 2} + value: {fileID: 2126874144} + m_ExposedReferences: + m_References: [] +--- !u!4 &1390425320 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1390425318} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 167820758} + m_Father: {fileID: 1800407625} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 20, y: 20} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1486682952 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1486682950} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1486682953 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1486682950} - m_CullTransparentMesh: 1 ---- !u!1 &1570876498 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1570876499} - - component: {fileID: 1570876502} - - component: {fileID: 1570876501} - - component: {fileID: 1570876500} - m_Layer: 5 - m_Name: Courses - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1570876499 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1570876498} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1379945947} - - {fileID: 1354622762} - m_Father: {fileID: 1380805077} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 1590, y: 808} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1570876500 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1570876498} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Content: {fileID: 1832508913} - m_Horizontal: 1 - m_Vertical: 0 - m_MovementType: 2 - m_Elasticity: 0.1 - m_Inertia: 1 - m_DecelerationRate: 0.135 - m_ScrollSensitivity: 1 - m_Viewport: {fileID: 1379945947} - m_HorizontalScrollbar: {fileID: 1354622763} - m_VerticalScrollbar: {fileID: 0} - m_HorizontalScrollbarVisibility: 0 - m_VerticalScrollbarVisibility: 0 - m_HorizontalScrollbarSpacing: -3 - m_VerticalScrollbarSpacing: -3 - m_OnValueChanged: - m_PersistentCalls: - m_Calls: [] ---- !u!114 &1570876501 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1570876498} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.39215687} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1570876502 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1570876498} - m_CullTransparentMesh: 1 --- !u!1001 &1605366629 PrefabInstance: m_ObjectHideFlags: 0 @@ -1411,8 +1255,16 @@ PrefabInstance: m_TransformParent: {fileID: 1380805077} m_Modifications: - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument - value: Common/Scenes/StartScreen + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Target + value: + objectReference: {fileID: 1093369505} + - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: Play + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: UnityEngine.Playables.PlayableDirector, UnityEngine objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name @@ -1428,7 +1280,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_RootOrder - value: 2 + value: 4 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchorMax.x @@ -1448,11 +1300,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -1484,11 +1336,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -1509,6 +1361,17 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} m_PrefabInstance: {fileID: 1605366629} m_PrefabAsset: {fileID: 0} +--- !u!114 &1605366631 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4518652150503380115, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + m_PrefabInstance: {fileID: 1605366629} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c3dd279b546423e4a8a1b28819a6c4a1, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &1654299744 GameObject: m_ObjectHideFlags: 0 @@ -1644,7 +1507,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1654299744} m_CullTransparentMesh: 1 ---- !u!1 &1832508912 +--- !u!1 &1800407624 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1652,57 +1515,348 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1832508913} - - component: {fileID: 1832508915} - - component: {fileID: 1832508914} - m_Layer: 5 - m_Name: Content + - component: {fileID: 1800407625} + m_Layer: 0 + m_Name: SceneTransitions m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1832508913 +--- !u!4 &1800407625 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1800407624} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1390425320} + - {fileID: 1093369504} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1821407071 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1821407073} + - component: {fileID: 1821407072} + - component: {fileID: 1821407074} + m_Layer: 0 + m_Name: ListMinigamesController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1821407072 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1821407071} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2dd453d411c3b3e458a7b133764c6b64, type: 3} + m_Name: + m_EditorClassIdentifier: + minigameContainer: {fileID: 2146756454} + minigameItemPrefab: {fileID: 4959898007614330357, guid: e5eaffcdbecf2ab48a94311753d10e09, type: 3} + minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} + directorEnterFromMainMenu: {fileID: 1390425319} +--- !u!4 &1821407073 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1821407071} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1821407074 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1821407071} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e52de21a22b6dd44c9cc19f810c65059, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Events: + m_Signals: + - {fileID: 11400000, guid: 43d3b5349c78425499a459f42eed4e88, type: 2} + m_Events: + - m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1605366631} + m_TargetAssemblyTypeName: BackButton, CommonScripts + m_MethodName: Back + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!1 &2126874142 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2126874143} + - component: {fileID: 2126874146} + - component: {fileID: 2126874145} + - component: {fileID: 2126874144} + m_Layer: 5 + m_Name: Circle (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2126874143 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1832508912} + m_GameObject: {fileID: 2126874142} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 1379945947} - m_RootOrder: 0 + m_Father: {fileID: 1380805077} + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0, y: 1} ---- !u!114 &1832508914 + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 270, y: 100} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &2126874144 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2126874142} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 47b8ff2adcd4fa64981587b8490f907b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &2126874145 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1832508912} + m_GameObject: {fileID: 2126874142} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: m_EditorClassIdentifier: - m_HorizontalFit: 2 - m_VerticalFit: 2 ---- !u!114 &1832508915 + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2126874146 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2126874142} + m_CullTransparentMesh: 1 +--- !u!1 &2141275316 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2141275317} + - component: {fileID: 2141275320} + - component: {fileID: 2141275319} + - component: {fileID: 2141275318} + m_Layer: 5 + m_Name: Circle (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2141275317 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2141275316} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1380805077} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 230, y: -215} + m_SizeDelta: {x: 360, y: 360} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &2141275318 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2141275316} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &2141275319 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1832508912} + m_GameObject: {fileID: 2141275316} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2141275320 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2141275316} + m_CullTransparentMesh: 1 +--- !u!1 &2146756453 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2146756454} + - component: {fileID: 2146756455} + m_Layer: 5 + m_Name: Minigames + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2146756454 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2146756453} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1380805077} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -20, y: 0} + m_SizeDelta: {x: -360, y: -320} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2146756455 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2146756453} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} @@ -1713,10 +1867,10 @@ MonoBehaviour: m_Right: 10 m_Top: 10 m_Bottom: 10 - m_ChildAlignment: 0 + m_ChildAlignment: 4 m_StartCorner: 0 m_StartAxis: 0 - m_CellSize: {x: 256, y: 256} + m_CellSize: {x: 350, y: 350} m_Spacing: {x: 10, y: 10} - m_Constraint: 2 - m_ConstraintCount: 3 + m_Constraint: 0 + m_ConstraintCount: 2 diff --git a/Assets/Common/Scenes/MainMenuScreen.unity b/Assets/Common/Scenes/MainMenuScreen.unity index cad3aeb..c330f8e 100644 --- a/Assets/Common/Scenes/MainMenuScreen.unity +++ b/Assets/Common/Scenes/MainMenuScreen.unity @@ -123,7 +123,7 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} ---- !u!1 &37409563 +--- !u!1 &38021322 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -131,134 +131,220 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 37409564} - - component: {fileID: 37409566} - - component: {fileID: 37409565} - m_Layer: 5 - m_Name: Text (TMP) + - component: {fileID: 38021324} + - component: {fileID: 38021323} + m_Layer: 0 + m_Name: Director ExitTo Settings m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &37409564 -RectTransform: +--- !u!320 &38021323 +PlayableDirector: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 37409563} + m_GameObject: {fileID: 38021322} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + m_InitialState: 0 + m_WrapMode: 0 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 7960070878223035243, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 8745738078766204527, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 4350005768353392531, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 7595589887998305822, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -8582760416834872199, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 751230908} + - key: {fileID: 4179371391357151474, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1283325281} + - key: {fileID: -6461985129190707182, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 826778413} + - key: {fileID: -2701421434816263238, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -644108254300868384, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 0} + value: {fileID: 1181577740} + - key: {fileID: 0} + value: {fileID: 1140687292} + - key: {fileID: 0} + value: {fileID: 751230908} + - key: {fileID: 0} + value: {fileID: 1283325281} + - key: {fileID: 0} + value: {fileID: 826778413} + - key: {fileID: 0} + value: {fileID: 1676839002} + - key: {fileID: 0} + value: {fileID: 1747129309} + - key: {fileID: 8324031387123106780, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 2139126816910514718, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 0} + value: {fileID: 1562838012} + - key: {fileID: 4509904291432811175, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 61972070} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 3557235052885036117, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 2790252717313872206, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -5899776333742599432, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 751230908} + - key: {fileID: 0} + value: {fileID: 1283325281} + - key: {fileID: 0} + value: {fileID: 826778413} + - key: {fileID: 0} + value: {fileID: 1676839002} + - key: {fileID: 0} + value: {fileID: 1747129309} + - key: {fileID: 0} + value: {fileID: 1739303843} + - key: {fileID: 0} + value: {fileID: 1786639650} + - key: {fileID: -3010792027217435242, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 826778413} + - key: {fileID: 1173479326806649973, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1283325281} + - key: {fileID: 5908694173847546634, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1562838012} + - key: {fileID: 8085811114252437081, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -6441785808545757162, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 4790687436092278219, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1377361019} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: -9055057456132405614, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 1096787736882190270, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 883746247832735280, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 709750372542851707, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1140687292} + - key: {fileID: 909078281928674083, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 751230908} + - key: {fileID: -6616596139522403256, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1377361019} + - key: {fileID: 2514152892369494006, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1283325281} + - key: {fileID: 6079267839920973567, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 826778413} + - key: {fileID: 8267312918698752938, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1676839002} + - key: {fileID: 1394315781135015027, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1747129309} + - key: {fileID: -4940363129666359713, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 1562838012} + - key: {fileID: -6171563559054577944, guid: 70e33fe36bd6a1246b94c1356fa31623, type: 2} + value: {fileID: 61972070} + m_ExposedReferences: + m_References: [] +--- !u!4 &38021324 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 38021322} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 58824783} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &58824782 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 58824783} + m_Layer: 0 + m_Name: SceneTransitions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &58824783 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 58824782} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 1637175261} - m_RootOrder: 0 + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8444593018541939376} + - {fileID: 1009407391} + - {fileID: 1603401482} + - {fileID: 1038929892} + - {fileID: 38021324} + m_Father: {fileID: 0} + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 700, y: 0} - m_SizeDelta: {x: -1800, y: -640} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &37409565 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 37409563} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: Lessen - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 1000 - m_fontSizeBase: 1000 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &37409566 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 37409563} - m_CullTransparentMesh: 1 ---- !u!1 &108186280 +--- !u!1 &61972067 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -266,133 +352,107 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 108186281} - - component: {fileID: 108186284} - - component: {fileID: 108186283} - - component: {fileID: 108186282} - m_Layer: 5 - m_Name: Minigames + - component: {fileID: 61972069} + - component: {fileID: 61972068} + - component: {fileID: 61972070} + m_Layer: 0 + m_Name: MainMenuController m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &108186281 -RectTransform: +--- !u!114 &61972068 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 108186280} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_GameObject: {fileID: 61972067} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e7cdd358c46e3f94398d91b7118e6d39, type: 3} + m_Name: + m_EditorClassIdentifier: + directorEnterFromBoot: {fileID: 8444593018541939377} + directorEnterFromCourseMenu: {fileID: 1009407390} + directorEnterFromListMinigames: {fileID: 8444593018541939377} + directorEnterFromSettings: {fileID: 1009407390} +--- !u!4 &61972069 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 61972067} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0.085, y: 0.085, z: 0.85} - m_ConstrainProportionsScale: 1 - m_Children: - - {fileID: 766563566} - - {fileID: 2105029353} - m_Father: {fileID: 906197777} - m_RootOrder: 2 + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: -165} - m_SizeDelta: {x: 6434.104, y: 1862.9999} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &108186282 +--- !u!114 &61972070 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 108186280} + m_GameObject: {fileID: 61972067} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Script: {fileID: 11500000, guid: e52de21a22b6dd44c9cc19f810c65059, type: 3} m_Name: m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 2 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_PressedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_SelectedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 108186283} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: MainMenuScreen, Assembly-CSharp - m_MethodName: GotoMinigames - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: ListMinigamesScreen - m_BoolArgument: 0 - m_CallState: 2 ---- !u!114 &108186283 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 108186280} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: aa6b260f6addb6746be3dac4f14e3689, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &108186284 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 108186280} - m_CullTransparentMesh: 1 + m_Events: + m_Signals: + - {fileID: 11400000, guid: e7f8a994d20fc3f4e86b8c89d0985feb, type: 2} + - {fileID: 11400000, guid: 08675e63d7cce004b8d676459e6bd800, type: 2} + - {fileID: 11400000, guid: 93a1de2533e3bef448eeffa926ed86ac, type: 2} + m_Events: + - m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 61972068} + m_TargetAssemblyTypeName: MainMenuScreen, CommonScripts + m_MethodName: GotoCourses + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 61972068} + m_TargetAssemblyTypeName: MainMenuScreen, CommonScripts + m_MethodName: GotoMinigames + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 61972068} + m_TargetAssemblyTypeName: MainMenuScreen, CommonScripts + m_MethodName: GotoSettings + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 --- !u!1 &129643495 GameObject: m_ObjectHideFlags: 0 @@ -461,6 +521,82 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &427856473 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 427856474} + - component: {fileID: 427856476} + - component: {fileID: 427856475} + m_Layer: 5 + m_Name: Button Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &427856474 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 427856473} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 751230905} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -550, y: 0} + m_SizeDelta: {x: 280, y: 280} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &427856475 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 427856473} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 9ae27e558c598724ea9fd56afe36904c, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &427856476 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 427856473} + m_CullTransparentMesh: 1 --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -497,7 +633,7 @@ Camera: m_Enabled: 1 serializedVersion: 2 m_ClearFlags: 2 - m_BackGroundColor: {r: 1, g: 1, b: 1, a: 0} + m_BackGroundColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 @@ -545,7 +681,7 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &766563565 +--- !u!1 &751230904 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -553,133 +689,124 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 766563566} - - component: {fileID: 766563568} - - component: {fileID: 766563567} + - component: {fileID: 751230905} + - component: {fileID: 751230907} + - component: {fileID: 751230906} + - component: {fileID: 751230908} m_Layer: 5 - m_Name: Text (TMP) + m_Name: Settings m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &766563566 +--- !u!224 &751230905 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 766563565} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_GameObject: {fileID: 751230904} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} + m_LocalScale: {x: 0.3, y: 0.3, z: 0.3} m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 108186281} - m_RootOrder: 0 + m_Children: + - {fileID: 2087405562} + - {fileID: 1586632571} + - {fileID: 427856474} + m_Father: {fileID: 906197777} + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 700, y: 0} - m_SizeDelta: {x: -1800, y: -640} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -235} + m_SizeDelta: {x: 1524, y: 378} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &766563567 +--- !u!114 &751230906 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 766563565} + m_GameObject: {fileID: 751230904} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} m_Name: m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 2 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_PressedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_SelectedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2087405563} + m_OnClick: m_PersistentCalls: - m_Calls: [] - m_text: Spelletjes - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 1000 - m_fontSizeBase: 1000 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &766563568 + m_Calls: + - m_Target: {fileID: 38021323} + m_TargetAssemblyTypeName: UnityEngine.Playables.PlayableDirector, UnityEngine + m_MethodName: Play + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!222 &751230907 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 766563565} + m_GameObject: {fileID: 751230904} m_CullTransparentMesh: 1 +--- !u!95 &751230908 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 751230904} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 196bc314c0fd00a42aede7fc33ab93f5, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1001 &790881344 PrefabInstance: m_ObjectHideFlags: 0 @@ -745,7 +872,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_RootOrder - value: 4 + value: 1 objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_AnchorMax.x @@ -850,7 +977,7 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} m_PrefabInstance: {fileID: 790881344} m_PrefabAsset: {fileID: 0} ---- !u!1 &830464405 +--- !u!1 &826778409 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -858,46 +985,47 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 830464406} - - component: {fileID: 830464408} - - component: {fileID: 830464407} + - component: {fileID: 826778410} + - component: {fileID: 826778412} + - component: {fileID: 826778411} + - component: {fileID: 826778413} m_Layer: 5 - m_Name: Text (TMP) + m_Name: Circle (2) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &830464406 +--- !u!224 &826778410 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 830464405} + m_GameObject: {fileID: 826778409} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} + m_LocalScale: {x: -1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 1377361015} - m_RootOrder: 0 + m_Father: {fileID: 906197777} + m_RootOrder: 10 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &830464407 + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -730, y: -300} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 1, y: 0} +--- !u!114 &826778411 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 830464405} + m_GameObject: {fileID: 826778409} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} @@ -908,82 +1036,119 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: x - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 64 - m_fontSizeBase: 64 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &830464408 + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &826778412 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 830464405} + m_GameObject: {fileID: 826778409} + m_CullTransparentMesh: 1 +--- !u!95 &826778413 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 826778409} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 1871dbf4971f77743ad5c9793fe979f2, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &835293731 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 835293732} + - component: {fileID: 835293734} + - component: {fileID: 835293733} + m_Layer: 5 + m_Name: Button Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &835293732 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 835293731} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1140687289} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -550, y: 0} + m_SizeDelta: {x: 280, y: 280} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &835293733 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 835293731} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: f30c85a17f81cce4787aad3e86de4eac, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &835293734 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 835293731} m_CullTransparentMesh: 1 --- !u!1 &906197776 GameObject: @@ -996,7 +1161,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -1016,12 +1180,18 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 1733122252} - - {fileID: 1637175261} - - {fileID: 108186281} - - {fileID: 955994878} - - {fileID: 790881345} - {fileID: 1377361015} + - {fileID: 790881345} + - {fileID: 1181577736} + - {fileID: 1140687289} + - {fileID: 751230905} + - {fileID: 1739303840} + - {fileID: 1786639647} + - {fileID: 1676838999} + - {fileID: 1747129306} + - {fileID: 1283325278} + - {fileID: 826778410} + - {fileID: 1562838011} m_Father: {fileID: 1768150806} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -1043,14 +1213,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1068,20 +1238,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e7cdd358c46e3f94398d91b7118e6d39, type: 3} - m_Name: - m_EditorClassIdentifier: - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} ---- !u!1 &955994877 +--- !u!1 &921819063 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1089,46 +1246,471 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 955994878} - - component: {fileID: 955994881} - - component: {fileID: 955994880} - - component: {fileID: 955994879} + - component: {fileID: 921819064} + - component: {fileID: 921819066} + - component: {fileID: 921819065} m_Layer: 5 - m_Name: Settings + m_Name: Button Icon m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &955994878 +--- !u!224 &921819064 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 955994877} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_GameObject: {fileID: 921819063} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0.085, y: 0.085, z: 0.85} - m_ConstrainProportionsScale: 1 - m_Children: - - {fileID: 1966196597} - - {fileID: 991775368} - m_Father: {fileID: 906197777} - m_RootOrder: 3 + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1181577736} + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: -330} - m_SizeDelta: {x: 6434.104, y: 1862.9999} + m_AnchoredPosition: {x: -550, y: 0} + m_SizeDelta: {x: 280, y: 280} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &955994879 +--- !u!114 &921819065 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 955994877} + m_GameObject: {fileID: 921819063} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 46681a51b9abdeb4a959db1b53e0fab9, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &921819066 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 921819063} + m_CullTransparentMesh: 1 +--- !u!1 &1009407389 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1009407391} + - component: {fileID: 1009407390} + m_Layer: 0 + m_Name: Director EnterFrom CourseMenu+Settings + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!320 &1009407390 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1009407389} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + m_InitialState: 0 + m_WrapMode: 0 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 7960070878223035243, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 8745738078766204527, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 4350005768353392531, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 7595589887998305822, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -8582760416834872199, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 751230908} + - key: {fileID: 4179371391357151474, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1283325281} + - key: {fileID: -6461985129190707182, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 826778413} + - key: {fileID: -2701421434816263238, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -644108254300868384, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 0} + value: {fileID: 1181577740} + - key: {fileID: 0} + value: {fileID: 1140687292} + - key: {fileID: 0} + value: {fileID: 751230908} + - key: {fileID: 0} + value: {fileID: 1283325281} + - key: {fileID: 0} + value: {fileID: 826778413} + - key: {fileID: 0} + value: {fileID: 1676839002} + - key: {fileID: 0} + value: {fileID: 1747129309} + - key: {fileID: 8324031387123106780, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 2139126816910514718, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 0} + value: {fileID: 1562838012} + - key: {fileID: 4509904291432811175, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 0} + - key: {fileID: -3079976655630600166, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 0} + - key: {fileID: 4597266925128231051, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 0} + - key: {fileID: -2761539034690794932, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 1562838012} + - key: {fileID: 994782306206548664, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1562838012} + - key: {fileID: -3460374503973533952, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1377361019} + m_ExposedReferences: + m_References: [] +--- !u!4 &1009407391 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1009407389} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 58824783} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1038929891 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1038929892} + - component: {fileID: 1038929893} + m_Layer: 0 + m_Name: Director ExitTo ListMinigames + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1038929892 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1038929891} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 58824783} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &1038929893 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1038929891} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + m_InitialState: 0 + m_WrapMode: 0 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 7960070878223035243, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 8745738078766204527, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 4350005768353392531, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 7595589887998305822, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -8582760416834872199, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 751230908} + - key: {fileID: 4179371391357151474, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1283325281} + - key: {fileID: -6461985129190707182, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 826778413} + - key: {fileID: -2701421434816263238, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -644108254300868384, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 0} + value: {fileID: 1181577740} + - key: {fileID: 0} + value: {fileID: 1140687292} + - key: {fileID: 0} + value: {fileID: 751230908} + - key: {fileID: 0} + value: {fileID: 1283325281} + - key: {fileID: 0} + value: {fileID: 826778413} + - key: {fileID: 0} + value: {fileID: 1676839002} + - key: {fileID: 0} + value: {fileID: 1747129309} + - key: {fileID: 8324031387123106780, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 2139126816910514718, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 0} + value: {fileID: 1562838012} + - key: {fileID: 4509904291432811175, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 61972070} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 3557235052885036117, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 2790252717313872206, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -5899776333742599432, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 751230908} + - key: {fileID: 0} + value: {fileID: 1283325281} + - key: {fileID: 0} + value: {fileID: 826778413} + - key: {fileID: 0} + value: {fileID: 1676839002} + - key: {fileID: 0} + value: {fileID: 1747129309} + - key: {fileID: 0} + value: {fileID: 1739303843} + - key: {fileID: 0} + value: {fileID: 1786639650} + - key: {fileID: -3010792027217435242, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 826778413} + - key: {fileID: 1173479326806649973, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1283325281} + - key: {fileID: 5908694173847546634, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1562838012} + - key: {fileID: 8085811114252437081, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -6441785808545757162, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 4790687436092278219, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1377361019} + - key: {fileID: -7222763729682898453, guid: c9a1662ababacc549a2b60d2bddb6a11, type: 2} + value: {fileID: 0} + - key: {fileID: 3912059771208757551, guid: c9a1662ababacc549a2b60d2bddb6a11, type: 2} + value: {fileID: 0} + - key: {fileID: -7222763729682898453, guid: e807bc2046af3034b94c2e8c86ca9432, type: 2} + value: {fileID: 0} + - key: {fileID: 3912059771208757551, guid: e807bc2046af3034b94c2e8c86ca9432, type: 2} + value: {fileID: 0} + - key: {fileID: 4509904291432811175, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 61972070} + - key: {fileID: 8324031387123106780, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 2139126816910514718, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 3557235052885036117, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 2790252717313872206, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -5899776333742599432, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 751230908} + - key: {fileID: 4790687436092278219, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 1377361019} + - key: {fileID: 1173479326806649973, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 1283325281} + - key: {fileID: -3010792027217435242, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 826778413} + - key: {fileID: 8085811114252437081, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -6441785808545757162, guid: c38fe7d5e65deb849ad603272b6cb219, type: 2} + value: {fileID: 1747129309} + m_ExposedReferences: + m_References: [] +--- !u!1 &1054366574 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1054366575} + - component: {fileID: 1054366577} + - component: {fileID: 1054366576} + m_Layer: 5 + m_Name: Button Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1054366575 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054366574} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.3, y: 1.3, z: 1.3} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1181577736} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1388, y: 497} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1054366576 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054366574} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 46578af6a9f38ea46bf4f53f79e8fca8, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1054366577 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054366574} + m_CullTransparentMesh: 1 +--- !u!1 &1140687288 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1140687289} + - component: {fileID: 1140687291} + - component: {fileID: 1140687290} + - component: {fileID: 1140687292} + m_Layer: 5 + m_Name: Minigames + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1140687289 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1140687288} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.3, y: 0.3, z: 0.3} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 1507634725} + - {fileID: 2142141096} + - {fileID: 835293732} + m_Father: {fileID: 906197777} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -90} + m_SizeDelta: {x: 1524, y: 378} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1140687290 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1140687288} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} @@ -1151,9 +1733,9 @@ MonoBehaviour: m_ColorMultiplier: 1 m_FadeDuration: 0.1 m_SpriteState: - m_HighlightedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_PressedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_SelectedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} + m_HighlightedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_PressedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_SelectedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} m_DisabledSprite: {fileID: 0} m_AnimationTriggers: m_NormalTrigger: Normal @@ -1162,61 +1744,51 @@ MonoBehaviour: m_SelectedTrigger: Selected m_DisabledTrigger: Disabled m_Interactable: 1 - m_TargetGraphic: {fileID: 955994880} + m_TargetGraphic: {fileID: 1507634726} m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: MainMenuScreen, Assembly-CSharp - m_MethodName: GotoSettings + - m_Target: {fileID: 1038929893} + m_TargetAssemblyTypeName: UnityEngine.Playables.PlayableDirector, UnityEngine + m_MethodName: Play m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 - m_StringArgument: SettingsScreen + m_StringArgument: m_BoolArgument: 0 m_CallState: 2 ---- !u!114 &955994880 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 955994877} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: aa6b260f6addb6746be3dac4f14e3689, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &955994881 +--- !u!222 &1140687291 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 955994877} + m_GameObject: {fileID: 1140687288} m_CullTransparentMesh: 1 ---- !u!1 &991775367 +--- !u!95 &1140687292 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1140687288} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 196bc314c0fd00a42aede7fc33ab93f5, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &1181577735 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1224,75 +1796,125 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 991775368} - - component: {fileID: 991775370} - - component: {fileID: 991775369} + - component: {fileID: 1181577736} + - component: {fileID: 1181577739} + - component: {fileID: 1181577737} + - component: {fileID: 1181577740} m_Layer: 5 - m_Name: Image + m_Name: Lessen m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &991775368 +--- !u!224 &1181577736 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 991775367} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_GameObject: {fileID: 1181577735} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 2.2, y: 2.2, z: 2.2} + m_LocalScale: {x: 0.3, y: 0.3, z: 0.3} m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 955994878} - m_RootOrder: 1 + m_Children: + - {fileID: 1054366575} + - {fileID: 1693498775} + - {fileID: 921819064} + m_Father: {fileID: 906197777} + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -2288, y: 8} - m_SizeDelta: {x: 512, y: 512} + m_AnchoredPosition: {x: 0, y: 55} + m_SizeDelta: {x: 1524, y: 378} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &991775369 +--- !u!114 &1181577737 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 991775367} + m_GameObject: {fileID: 1181577735} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} m_Name: m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 2 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_PressedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_SelectedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1054366576} + m_OnClick: m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 47502749546946c47b5b2fc9c38fcc40, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &991775370 + m_Calls: + - m_Target: {fileID: 1603401481} + m_TargetAssemblyTypeName: UnityEngine.Playables.PlayableDirector, UnityEngine + m_MethodName: Play + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!222 &1181577739 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 991775367} + m_GameObject: {fileID: 1181577735} m_CullTransparentMesh: 1 ---- !u!1 &1369063653 +--- !u!95 &1181577740 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1181577735} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 196bc314c0fd00a42aede7fc33ab93f5, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &1283325277 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1300,43 +1922,44 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1369063654} - - component: {fileID: 1369063656} - - component: {fileID: 1369063655} + - component: {fileID: 1283325278} + - component: {fileID: 1283325280} + - component: {fileID: 1283325279} + - component: {fileID: 1283325281} m_Layer: 5 - m_Name: Image + m_Name: Circle (1) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1369063654 +--- !u!224 &1283325278 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1369063653} + m_GameObject: {fileID: 1283325277} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 2.7, y: 2.7, z: 2.7} - m_ConstrainProportionsScale: 1 + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 1637175261} - m_RootOrder: 1 + m_Father: {fileID: 906197777} + m_RootOrder: 9 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -2292, y: -0} - m_SizeDelta: {x: 512, y: 512} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1369063655 + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 260, y: -300} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1283325279 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1369063653} + m_GameObject: {fileID: 1283325277} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} @@ -1350,7 +1973,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: ec4ff70417eb8574bae722f2dba0f59e, type: 3} + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1360,14 +1983,34 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1369063656 +--- !u!222 &1283325280 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1369063653} + m_GameObject: {fileID: 1283325277} m_CullTransparentMesh: 1 +--- !u!95 &1283325281 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1283325277} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 47b8ff2adcd4fa64981587b8490f907b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1 &1377361014 GameObject: m_ObjectHideFlags: 0 @@ -1380,6 +2023,7 @@ GameObject: - component: {fileID: 1377361018} - component: {fileID: 1377361017} - component: {fileID: 1377361016} + - component: {fileID: 1377361019} m_Layer: 5 m_Name: Quit m_TagString: Untagged @@ -1398,15 +2042,14 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 830464406} + m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 5 + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} m_AnchoredPosition: {x: 10, y: -10} - m_SizeDelta: {x: 64, y: 64} + m_SizeDelta: {x: 50, y: 50} m_Pivot: {x: 0, y: 1} --- !u!114 &1377361016 MonoBehaviour: @@ -1452,8 +2095,8 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: MainMenuScreen, Assembly-CSharp + - m_Target: {fileID: 61972068} + m_TargetAssemblyTypeName: MainMenuScreen, CommonScripts m_MethodName: QuitApplication m_Mode: 1 m_Arguments: @@ -1477,15 +2120,15 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 0, b: 0, a: 1} + m_Color: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 + m_Sprite: {fileID: 21300000, guid: 3494ae6682f81cb419859e3699220d9d, type: 3} + m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 4 @@ -1502,7 +2145,27 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1377361014} m_CullTransparentMesh: 1 ---- !u!1 &1637175260 +--- !u!95 &1377361019 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1377361014} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: ab0e4afacdd6ce34fb9a66804f0d4238, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &1507634724 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1510,178 +2173,43 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1637175261} - - component: {fileID: 1637175264} - - component: {fileID: 1637175263} - - component: {fileID: 1637175262} + - component: {fileID: 1507634725} + - component: {fileID: 1507634727} + - component: {fileID: 1507634726} m_Layer: 5 - m_Name: Courses + m_Name: Button Image m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1637175261 +--- !u!224 &1507634725 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1637175260} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_GameObject: {fileID: 1507634724} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0.085, y: 0.085, z: 0.85} + m_LocalScale: {x: 1.3, y: 1.3, z: 1.3} m_ConstrainProportionsScale: 1 - m_Children: - - {fileID: 37409564} - - {fileID: 1369063654} - m_Father: {fileID: 906197777} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 6434.104, y: 1862.9999} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1637175262 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1637175260} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 2 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_PressedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_SelectedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1637175263} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 906197780} - m_TargetAssemblyTypeName: MainMenuScreen, Assembly-CSharp - m_MethodName: GotoCourses - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: CoursesScreen - m_BoolArgument: 0 - m_CallState: 2 ---- !u!114 &1637175263 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1637175260} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: aa6b260f6addb6746be3dac4f14e3689, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1637175264 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1637175260} - m_CullTransparentMesh: 1 ---- !u!1 &1733122251 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1733122252} - - component: {fileID: 1733122254} - - component: {fileID: 1733122253} - m_Layer: 0 - m_Name: Logo - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1733122252 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1733122251} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -3.073702} - m_LocalScale: {x: 10, y: 8, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 906197777} + m_Father: {fileID: 1140687289} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 220} - m_SizeDelta: {x: 100, y: 100} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1388, y: 497} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1733122253 +--- !u!114 &1507634726 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1733122251} + m_GameObject: {fileID: 1507634724} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} @@ -1695,7 +2223,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: f4df4aae6f11d0c4487c9616f770b019, type: 3} + m_Sprite: {fileID: 21300000, guid: 46578af6a9f38ea46bf4f53f79e8fca8, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1705,14 +2233,870 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1733122254 +--- !u!222 &1507634727 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1733122251} + m_GameObject: {fileID: 1507634724} m_CullTransparentMesh: 1 +--- !u!1 &1562838010 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1562838011} + - component: {fileID: 1562838014} + - component: {fileID: 1562838013} + - component: {fileID: 1562838012} + m_Layer: 5 + m_Name: Circle (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1562838011 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1562838010} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 11 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 260, y: -470} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 0, y: 0} +--- !u!95 &1562838012 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1562838010} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &1562838013 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1562838010} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1562838014 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1562838010} + m_CullTransparentMesh: 1 +--- !u!1 &1586632570 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1586632571} + - component: {fileID: 1586632573} + - component: {fileID: 1586632572} + m_Layer: 5 + m_Name: Button Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1586632571 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1586632570} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 751230905} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 187, y: 0} + m_SizeDelta: {x: -374, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1586632572 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1586632570} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Instellingen + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 250 + m_fontSizeBase: 250 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1586632573 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1586632570} + m_CullTransparentMesh: 1 +--- !u!1 &1603401480 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1603401482} + - component: {fileID: 1603401481} + m_Layer: 0 + m_Name: Director ExitTo CourseMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!320 &1603401481 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1603401480} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + m_InitialState: 0 + m_WrapMode: 0 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 7960070878223035243, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 8745738078766204527, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 4350005768353392531, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 7595589887998305822, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -8582760416834872199, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 751230908} + - key: {fileID: 4179371391357151474, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1283325281} + - key: {fileID: -6461985129190707182, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 826778413} + - key: {fileID: -2701421434816263238, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -644108254300868384, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 0} + value: {fileID: 1181577740} + - key: {fileID: 0} + value: {fileID: 1140687292} + - key: {fileID: 0} + value: {fileID: 751230908} + - key: {fileID: 0} + value: {fileID: 1283325281} + - key: {fileID: 0} + value: {fileID: 826778413} + - key: {fileID: 0} + value: {fileID: 1676839002} + - key: {fileID: 0} + value: {fileID: 1747129309} + - key: {fileID: 8324031387123106780, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 2139126816910514718, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 0} + value: {fileID: 1562838012} + - key: {fileID: 4509904291432811175, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 61972070} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 3557235052885036117, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 2790252717313872206, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -5899776333742599432, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 751230908} + - key: {fileID: 0} + value: {fileID: 1283325281} + - key: {fileID: 0} + value: {fileID: 826778413} + - key: {fileID: 0} + value: {fileID: 1676839002} + - key: {fileID: 0} + value: {fileID: 1747129309} + - key: {fileID: 0} + value: {fileID: 1739303843} + - key: {fileID: 0} + value: {fileID: 1786639650} + - key: {fileID: -3010792027217435242, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 826778413} + - key: {fileID: 1173479326806649973, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1283325281} + - key: {fileID: 5908694173847546634, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1562838012} + - key: {fileID: 8085811114252437081, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -6441785808545757162, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 4790687436092278219, guid: 9406fe9f4b6ff024a8b0251f02a9f1eb, type: 2} + value: {fileID: 1377361019} + m_ExposedReferences: + m_References: [] +--- !u!4 &1603401482 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1603401480} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 58824783} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1676838998 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1676838999} + - component: {fileID: 1676839001} + - component: {fileID: 1676839000} + - component: {fileID: 1676839002} + m_Layer: 5 + m_Name: Circle (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1676838999 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1676838998} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: -160, y: -250} + m_SizeDelta: {x: 535, y: 535} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1676839000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1676838998} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1676839001 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1676838998} + m_CullTransparentMesh: 1 +--- !u!95 &1676839002 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1676838998} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &1693498774 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1693498775} + - component: {fileID: 1693498777} + - component: {fileID: 1693498776} + m_Layer: 5 + m_Name: Button Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1693498775 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1693498774} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1181577736} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 187, y: 0} + m_SizeDelta: {x: -374, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1693498776 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1693498774} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Lessen + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 250 + m_fontSizeBase: 250 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1693498777 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1693498774} + m_CullTransparentMesh: 1 +--- !u!1 &1739303839 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1739303840} + - component: {fileID: 1739303842} + - component: {fileID: 1739303841} + - component: {fileID: 1739303843} + m_Layer: 5 + m_Name: WE + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1739303840 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1739303839} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: -325, y: -115} + m_SizeDelta: {x: 500, y: 250} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &1739303841 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1739303839} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: We + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 37d049cc0ec73ba4188bdaf99a92cbe6, type: 2} + m_sharedMaterial: {fileID: 3354070144502634594, guid: 37d049cc0ec73ba4188bdaf99a92cbe6, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 1 + m_colorMode: 1 + m_fontColorGradient: + topLeft: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + topRight: {r: 0.25882354, g: 0.61960787, b: 0.7411765, a: 1} + bottomLeft: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + bottomRight: {r: 0.25882354, g: 0.61960787, b: 0.7411765, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 270 + m_fontSizeBase: 270 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 4 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1739303842 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1739303839} + m_CullTransparentMesh: 1 +--- !u!95 &1739303843 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1739303839} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 6b7d9f6f570023640b182154818df183, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &1747129305 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1747129306} + - component: {fileID: 1747129308} + - component: {fileID: 1747129307} + - component: {fileID: 1747129309} + m_Layer: 5 + m_Name: Circle (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1747129306 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1747129305} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: -1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -375, y: -250} + m_SizeDelta: {x: 535, y: 535} + m_Pivot: {x: 1, y: 0} +--- !u!114 &1747129307 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1747129305} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1747129308 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1747129305} + m_CullTransparentMesh: 1 +--- !u!95 &1747129309 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1747129305} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 8d2ff77db5e35814cbe7ed8d0ca8a00b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1 &1768150802 GameObject: m_ObjectHideFlags: 0 @@ -1761,10 +3145,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -1807,14 +3191,14 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} ---- !u!1 &1966196596 +--- !u!1 &1786639646 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1822,43 +3206,44 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1966196597} - - component: {fileID: 1966196599} - - component: {fileID: 1966196598} + - component: {fileID: 1786639647} + - component: {fileID: 1786639649} + - component: {fileID: 1786639648} + - component: {fileID: 1786639650} m_Layer: 5 - m_Name: Text (TMP) + m_Name: SIGN m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1966196597 +--- !u!224 &1786639647 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1966196596} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_GameObject: {fileID: 1786639646} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 + m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 955994878} - m_RootOrder: 0 + m_Father: {fileID: 906197777} + m_RootOrder: 6 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 700, y: 0} - m_SizeDelta: {x: -1800, y: -640} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1966196598 + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 175, y: -115} + m_SizeDelta: {x: 500, y: 250} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &1786639648 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1966196596} + m_GameObject: {fileID: 1786639646} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} @@ -1872,17 +3257,248 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Instellingen + m_text: Sign m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 37d049cc0ec73ba4188bdaf99a92cbe6, type: 2} + m_sharedMaterial: {fileID: 3354070144502634594, guid: 37d049cc0ec73ba4188bdaf99a92cbe6, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 1 + m_colorMode: 1 + m_fontColorGradient: + topLeft: {r: 0.9490196, g: 0.49803922, b: 0.047058824, a: 1} + topRight: {r: 0.96862745, g: 0.6784314, b: 0.09803922, a: 1} + bottomLeft: {r: 0.9490196, g: 0.49803922, b: 0.047058824, a: 1} + bottomRight: {r: 0.96862745, g: 0.6784314, b: 0.09803922, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 270 + m_fontSizeBase: 270 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 2 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1786639649 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1786639646} + m_CullTransparentMesh: 1 +--- !u!95 &1786639650 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1786639646} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 6b7d9f6f570023640b182154818df183, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &2087405561 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2087405562} + - component: {fileID: 2087405564} + - component: {fileID: 2087405563} + m_Layer: 5 + m_Name: Button Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2087405562 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2087405561} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.3, y: 1.3, z: 1.3} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 751230905} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1388, y: 497} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2087405563 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2087405561} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 46578af6a9f38ea46bf4f53f79e8fca8, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2087405564 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2087405561} + m_CullTransparentMesh: 1 +--- !u!1 &2142141095 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2142141096} + - component: {fileID: 2142141098} + - component: {fileID: 2142141097} + m_Layer: 5 + m_Name: Button Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2142141096 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2142141095} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1140687289} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 187, y: 0} + m_SizeDelta: {x: -374, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2142141097 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2142141095} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Spelletjes + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -1899,8 +3515,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 1000 - m_fontSizeBase: 1000 + m_fontSize: 250 + m_fontSizeBase: 250 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 @@ -1941,15 +3557,87 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1966196599 +--- !u!222 &2142141098 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1966196596} + m_GameObject: {fileID: 2142141095} m_CullTransparentMesh: 1 ---- !u!1 &2105029352 +--- !u!4 &8444593018541939376 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8444593018541939390} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 58824783} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &8444593018541939377 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8444593018541939390} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + m_InitialState: 0 + m_WrapMode: 0 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 0} + value: {fileID: 0} + - key: {fileID: 7960070878223035243, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 8745738078766204527, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 4350005768353392531, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 7595589887998305822, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -8582760416834872199, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 751230908} + - key: {fileID: 4179371391357151474, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1283325281} + - key: {fileID: -6461985129190707182, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 826778413} + - key: {fileID: -2701421434816263238, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -644108254300868384, guid: e9c4a356b1ade0d4aae5b9c332f7113b, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 4350005768353392531, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 1181577740} + - key: {fileID: 7595589887998305822, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 1140687292} + - key: {fileID: -8582760416834872199, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 751230908} + - key: {fileID: 4179371391357151474, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 1283325281} + - key: {fileID: -6461985129190707182, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 826778413} + - key: {fileID: -2701421434816263238, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 1676839002} + - key: {fileID: -644108254300868384, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 1747129309} + - key: {fileID: 7960070878223035243, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 1739303843} + - key: {fileID: 8745738078766204527, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 1786639650} + - key: {fileID: 6319176095920718519, guid: 307ae7d8f4dcb8842a064af301714167, type: 2} + value: {fileID: 1377361019} + m_ExposedReferences: + m_References: [] +--- !u!1 &8444593018541939390 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1957,71 +3645,12 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 2105029353} - - component: {fileID: 2105029355} - - component: {fileID: 2105029354} - m_Layer: 5 - m_Name: Image + - component: {fileID: 8444593018541939376} + - component: {fileID: 8444593018541939377} + m_Layer: 0 + m_Name: Director EnterFrom Default m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &2105029353 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2105029352} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1.1, y: 1.1, z: 0.9166666} - m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 108186281} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -2307, y: 0} - m_SizeDelta: {x: 980, y: 786} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &2105029354 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2105029352} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 45f7eb5181e65e6478cc677929e5c7eb, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &2105029355 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2105029352} - m_CullTransparentMesh: 1 diff --git a/Assets/Common/Scenes/MinigameActivityScreen.unity b/Assets/Common/Scenes/MinigameActivityScreen.unity index c9fdc82..9a37912 100644 --- a/Assets/Common/Scenes/MinigameActivityScreen.unity +++ b/Assets/Common/Scenes/MinigameActivityScreen.unity @@ -236,7 +236,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_RootOrder - value: 7 + value: 8 objectReference: {fileID: 0} - target: {fileID: 2823887524698191630, guid: 53b0d00ac817ebf43b61bea2d160dd66, type: 3} propertyPath: m_AnchorMax.x @@ -377,7 +377,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 150, y: -100} + m_AnchoredPosition: {x: 100, y: -100} m_SizeDelta: {x: 400, y: 64} m_Pivot: {x: 0, y: 0.5} --- !u!114 &507029408 @@ -402,15 +402,15 @@ MonoBehaviour: m_Calls: [] m_text: Ranking m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} + rgba: 4279009266 + m_fontColor: {r: 0.9490196, g: 0.49803922, b: 0.047058824, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -433,8 +433,8 @@ MonoBehaviour: m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 1 - m_HorizontalAlignment: 1 + m_fontStyle: 0 + m_HorizontalAlignment: 2 m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 @@ -612,16 +612,16 @@ RectTransform: m_GameObject: {fileID: 755030129} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 + m_LocalScale: {x: 1.7, y: 1.7, z: 1.7} + m_ConstrainProportionsScale: 1 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 3 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 150, y: 150} - m_SizeDelta: {x: 400, y: 400} + m_AnchoredPosition: {x: 100, y: 150} + m_SizeDelta: {x: 256, y: 211} m_Pivot: {x: 0, y: 0.5} --- !u!114 &755030131 MonoBehaviour: @@ -643,9 +643,9 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 8f5216ce0bfcecc4da0340703872c4ff, type: 3} + m_Sprite: {fileID: 21300000, guid: 5387f0486602abf479f049d9afa9d3cb, type: 3} m_Type: 0 - m_PreserveAspect: 0 + m_PreserveAspect: 1 m_FillCenter: 1 m_FillMethod: 4 m_FillAmount: 1 @@ -672,7 +672,6 @@ GameObject: - component: {fileID: 906197777} - component: {fileID: 906197779} - component: {fileID: 906197778} - - component: {fileID: 906197780} m_Layer: 5 m_Name: Panel m_TagString: Untagged @@ -687,7 +686,7 @@ RectTransform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 @@ -695,11 +694,13 @@ RectTransform: - {fileID: 1168097235} - {fileID: 1990031299} - {fileID: 915818720} + - {fileID: 1624926936} - {fileID: 755030130} - - {fileID: 955994878} - {fileID: 507029407} + - {fileID: 1026350212} - {fileID: 1329933896} - {fileID: 143992427} + - {fileID: 2136972068} m_Father: {fileID: 1768150806} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -721,14 +722,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -746,27 +747,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 ---- !u!114 &906197780 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 906197776} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 90de9a5c57c2189429073f8aadc9e9b7, type: 3} - m_Name: - m_EditorClassIdentifier: - minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} - title: {fileID: 1168097236} - description: {fileID: 1990031300} - gameImage: {fileID: 755030131} - button: {fileID: 955994879} - controls: {fileID: 915818721} - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - userContainer: {fileID: 507029407} - prefab: {fileID: 381012861935775045, guid: 154c17a838d2896499bd76d28a584222, type: 3} --- !u!1 &915818719 GameObject: m_ObjectHideFlags: 0 @@ -802,7 +782,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 250, y: -100} + m_AnchoredPosition: {x: 200, y: -100} m_SizeDelta: {x: 1000, y: 400} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &915818721 @@ -827,8 +807,8 @@ MonoBehaviour: m_Calls: [] m_text: Explain how to play the game, how to get points m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -852,8 +832,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 40 - m_fontSizeBase: 40 + m_fontSize: 45 + m_fontSizeBase: 45 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 @@ -902,7 +882,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 915818719} m_CullTransparentMesh: 1 ---- !u!1 &955994877 +--- !u!1 &1026350211 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -910,166 +890,64 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 955994878} - - component: {fileID: 955994881} - - component: {fileID: 955994880} - - component: {fileID: 955994879} + - component: {fileID: 1026350212} + - component: {fileID: 1026350215} + - component: {fileID: 1026350214} + - component: {fileID: 1026350213} m_Layer: 5 - m_Name: Play Button + m_Name: Circle (4) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &955994878 +--- !u!224 &1026350212 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 955994877} + m_GameObject: {fileID: 1026350211} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: - - {fileID: 1966196597} - - {fileID: 991775368} - m_Father: {fileID: 906197777} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 1, y: 0} - m_AnchorMax: {x: 1, y: 0} - m_AnchoredPosition: {x: -20, y: 20} - m_SizeDelta: {x: 500, y: 145} - m_Pivot: {x: 1, y: 0} ---- !u!114 &955994879 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 955994877} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 2 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_PressedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_SelectedSprite: {fileID: 21300000, guid: 887126f63e8c2a340abc9fc3c2e7fdca, type: 3} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 955994880} - m_OnClick: - m_PersistentCalls: - m_Calls: [] ---- !u!114 &955994880 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 955994877} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: aa6b260f6addb6746be3dac4f14e3689, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &955994881 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 955994877} - m_CullTransparentMesh: 1 ---- !u!1 &991775367 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 991775368} - - component: {fileID: 991775370} - - component: {fileID: 991775369} - m_Layer: 5 - m_Name: Image - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &991775368 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 991775367} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 + m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 955994878} - m_RootOrder: 1 + m_Father: {fileID: 906197777} + m_RootOrder: 6 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0.5} - m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 20, y: 0} - m_SizeDelta: {x: 100, y: 100} - m_Pivot: {x: 0, y: 0.5} ---- !u!114 &991775369 + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 270, y: 100} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &1026350213 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1026350211} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 47b8ff2adcd4fa64981587b8490f907b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &1026350214 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 991775367} + m_GameObject: {fileID: 1026350211} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} @@ -1083,7 +961,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 43db869a07cf51f45a411b6e4a417743, type: 3} + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1093,13 +971,13 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &991775370 +--- !u!222 &1026350215 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 991775367} + m_GameObject: {fileID: 1026350211} m_CullTransparentMesh: 1 --- !u!1 &1168097234 GameObject: @@ -1161,16 +1039,16 @@ MonoBehaviour: m_Calls: [] m_text: Title of the game m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4292118016 - m_fontColor: {r: 0, g: 0.5254902, b: 0.8313726, a: 1} - m_enableVertexGradient: 1 + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: topLeft: {r: 0.11764707, g: 0.6745098, b: 1, a: 1} @@ -1192,7 +1070,7 @@ MonoBehaviour: m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 1 + m_fontStyle: 0 m_HorizontalAlignment: 2 m_VerticalAlignment: 512 m_textAlignment: 65535 @@ -1236,6 +1114,141 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1168097234} m_CullTransparentMesh: 1 +--- !u!1 &1216890870 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1216890871} + - component: {fileID: 1216890873} + - component: {fileID: 1216890872} + m_Layer: 5 + m_Name: Button Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1216890871 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1216890870} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1624926936} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 117.808, y: 0} + m_SizeDelta: {x: -235.617, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1216890872 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1216890870} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Begin + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 250 + m_fontSizeBase: 250 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1216890873 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1216890870} + m_CullTransparentMesh: 1 --- !u!1001 &1329933895 PrefabInstance: m_ObjectHideFlags: 0 @@ -1243,10 +1256,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 906197777} m_Modifications: - - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument - value: Common/Scenes/ListMinigamesScreen - objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name value: ButtonBack @@ -1261,7 +1270,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_RootOrder - value: 6 + value: 7 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchorMax.x @@ -1281,11 +1290,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -1317,11 +1326,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -1342,6 +1351,263 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} m_PrefabInstance: {fileID: 1329933895} m_PrefabAsset: {fileID: 0} +--- !u!1 &1426248757 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1426248758} + - component: {fileID: 1426248760} + - component: {fileID: 1426248759} + m_Layer: 5 + m_Name: Button Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1426248758 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1426248757} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1624926936} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -500, y: 0} + m_SizeDelta: {x: 280, y: 280} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1426248759 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1426248757} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 20d0d5f265af8554887f17fc0271b1be, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1426248760 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1426248757} + m_CullTransparentMesh: 1 +--- !u!1 &1624926935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1624926936} + - component: {fileID: 1624926938} + - component: {fileID: 1624926937} + m_Layer: 5 + m_Name: Begin + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1624926936 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1624926935} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.29999998, y: 0.29999998, z: 0.29999998} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 1663825585} + - {fileID: 1216890871} + - {fileID: 1426248758} + m_Father: {fileID: 906197777} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -70, y: -408} + m_SizeDelta: {x: 1524, y: 378} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1624926937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1624926935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 2 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_PressedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_SelectedSprite: {fileID: 21300000, guid: a96945215efea6247ad7760d024d1eb6, type: 3} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1663825586} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 0} + m_TargetAssemblyTypeName: CourseActivityScreen, CommonScripts + m_MethodName: StartCourse + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!222 &1624926938 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1624926935} + m_CullTransparentMesh: 1 +--- !u!1 &1663825584 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1663825585} + - component: {fileID: 1663825587} + - component: {fileID: 1663825586} + m_Layer: 5 + m_Name: Button Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1663825585 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1663825584} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.3, y: 1.3, z: 1.3} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1624926936} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1388, y: 497} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1663825586 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1663825584} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 46578af6a9f38ea46bf4f53f79e8fca8, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1663825587 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1663825584} + m_CullTransparentMesh: 1 --- !u!1 &1768150802 GameObject: m_ObjectHideFlags: 0 @@ -1390,10 +1656,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -1436,14 +1702,14 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} ---- !u!1 &1966196596 +--- !u!1 &1874965509 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1451,133 +1717,51 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1966196597} - - component: {fileID: 1966196599} - - component: {fileID: 1966196598} - m_Layer: 5 - m_Name: Text (TMP) + - component: {fileID: 1874965511} + - component: {fileID: 1874965510} + m_Layer: 0 + m_Name: MinigameActivityController m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1966196597 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1966196596} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: [] - m_Father: {fileID: 955994878} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1966196598 +--- !u!114 &1874965510 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1966196596} + m_GameObject: {fileID: 1874965509} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Script: {fileID: 11500000, guid: 90de9a5c57c2189429073f8aadc9e9b7, type: 3} m_Name: m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: Begin - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 80 - m_fontSizeBase: 80 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 150.5354, y: 26.162018, z: 37.023926, w: 27.4693} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1966196599 -CanvasRenderer: + minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} + title: {fileID: 1168097236} + description: {fileID: 1990031300} + gameImage: {fileID: 755030131} + button: {fileID: 1624926937} + controls: {fileID: 915818721} + userContainer: {fileID: 507029407} + prefab: {fileID: 381012861935775045, guid: 154c17a838d2896499bd76d28a584222, type: 3} + rankingTitle: {fileID: 507029406} +--- !u!4 &1874965511 +Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1966196596} - m_CullTransparentMesh: 1 + m_GameObject: {fileID: 1874965509} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -51.51357, y: 13.6327915, z: -0.6560367} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1990031298 GameObject: m_ObjectHideFlags: 0 @@ -1613,7 +1797,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 250, y: 200} + m_AnchoredPosition: {x: 200, y: 200} m_SizeDelta: {x: 1000, y: 200} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1990031300 @@ -1638,15 +1822,15 @@ MonoBehaviour: m_Calls: [] m_text: This is a description of the following game m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4288255380 - m_fontColor: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} + rgba: 4290616898 + m_fontColor: {r: 0.25882354, g: 0.61960787, b: 0.7411765, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -1663,13 +1847,13 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 52 - m_fontSizeBase: 52 + m_fontSize: 55 + m_fontSizeBase: 55 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 1 + m_fontStyle: 0 m_HorizontalAlignment: 1 m_VerticalAlignment: 512 m_textAlignment: 65535 @@ -1713,3 +1897,100 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1990031298} m_CullTransparentMesh: 1 +--- !u!1 &2136972067 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2136972068} + - component: {fileID: 2136972071} + - component: {fileID: 2136972070} + - component: {fileID: 2136972069} + m_Layer: 5 + m_Name: Circle (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2136972068 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2136972067} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 230, y: -215} + m_SizeDelta: {x: 360, y: 360} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &2136972069 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2136972067} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &2136972070 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2136972067} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2136972071 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2136972067} + m_CullTransparentMesh: 1 diff --git a/Assets/Common/Scenes/SettingsScreen.unity b/Assets/Common/Scenes/SettingsScreen.unity index 95115ee..bf83a36 100644 --- a/Assets/Common/Scenes/SettingsScreen.unity +++ b/Assets/Common/Scenes/SettingsScreen.unity @@ -275,6 +275,103 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &571869929 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 571869930} + - component: {fileID: 571869933} + - component: {fileID: 571869932} + - component: {fileID: 571869931} + m_Layer: 5 + m_Name: Circle (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &571869930 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 571869929} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: -160, y: -250} + m_SizeDelta: {x: 535, y: 535} + m_Pivot: {x: 0, y: 0} +--- !u!95 &571869931 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 571869929} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 47b8ff2adcd4fa64981587b8490f907b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &571869932 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 571869929} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &571869933 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 571869929} + m_CullTransparentMesh: 1 --- !u!1001 &730783504 PrefabInstance: m_ObjectHideFlags: 0 @@ -282,10 +379,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 906197777} m_Modifications: - - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument - value: Common/Scenes/StartScreen - objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name value: ButtonBack @@ -320,11 +413,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -356,11 +449,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -381,6 +474,31 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} m_PrefabInstance: {fileID: 730783504} m_PrefabAsset: {fileID: 0} +--- !u!1 &730783506 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + m_PrefabInstance: {fileID: 730783504} + m_PrefabAsset: {fileID: 0} +--- !u!95 &730783507 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 730783506} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1 &906197776 GameObject: m_ObjectHideFlags: 0 @@ -413,6 +531,8 @@ RectTransform: m_Children: - {fileID: 730783505} - {fileID: 2035873552} + - {fileID: 571869930} + - {fileID: 1571811196} m_Father: {fileID: 1768150806} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -434,14 +554,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -459,6 +579,148 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 +--- !u!1 &1203775218 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1203775219} + - component: {fileID: 1203775220} + m_Layer: 0 + m_Name: SettingsController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1203775219 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1203775218} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1203775220 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1203775218} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c206227bcf352fd4784750b5b2b19a31, type: 3} + m_Name: + m_EditorClassIdentifier: + directorEnterFromMainMenu: {fileID: 2007382037} +--- !u!1 &1571811195 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1571811196} + - component: {fileID: 1571811199} + - component: {fileID: 1571811198} + - component: {fileID: 1571811197} + m_Layer: 5 + m_Name: Circle (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1571811196 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1571811195} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 260, y: -300} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 0, y: 0} +--- !u!95 &1571811197 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1571811195} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &1571811198 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1571811195} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1571811199 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1571811195} + m_CullTransparentMesh: 1 --- !u!1 &1768150802 GameObject: m_ObjectHideFlags: 0 @@ -507,10 +769,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -553,13 +815,64 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} +--- !u!1 &2007382036 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2007382038} + - component: {fileID: 2007382037} + m_Layer: 0 + m_Name: Director EnterFrom MainMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!320 &2007382037 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2007382036} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + m_InitialState: 0 + m_WrapMode: 2 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: -4664426466800762542, guid: d6b723dad69fc14499c2e4dc32aeb16c, type: 2} + value: {fileID: 730783507} + m_ExposedReferences: + m_References: [] +--- !u!4 &2007382038 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2007382036} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1001 &2035873551 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Common/Scenes/ThemeSelectionScreen.unity b/Assets/Common/Scenes/ThemeSelectionScreen.unity index 589e613..84ac33f 100644 --- a/Assets/Common/Scenes/ThemeSelectionScreen.unity +++ b/Assets/Common/Scenes/ThemeSelectionScreen.unity @@ -198,10 +198,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 906197777} m_Modifications: - - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} - propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_StringArgument - value: Common/Scenes/InfoMinigame - objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name value: ButtonBack @@ -216,7 +212,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_RootOrder - value: 0 + value: 2 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchorMax.x @@ -236,11 +232,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -272,11 +268,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -309,7 +305,7 @@ GameObject: - component: {fileID: 315493451} - component: {fileID: 315493450} m_Layer: 5 - m_Name: Text (TMP) + m_Name: Title m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -328,7 +324,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 1 + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} @@ -355,17 +351,17 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: 'Pick your theme:' + m_text: Kies een thema m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -382,8 +378,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 48 - m_fontSizeBase: 48 + m_fontSize: 90 + m_fontSizeBase: 90 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 @@ -516,6 +512,103 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &896016097 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 896016098} + - component: {fileID: 896016101} + - component: {fileID: 896016100} + - component: {fileID: 896016099} + m_Layer: 5 + m_Name: Circle (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &896016098 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 896016097} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 270, y: 100} + m_SizeDelta: {x: 470, y: 470} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &896016099 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 896016097} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 47b8ff2adcd4fa64981587b8490f907b, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &896016100 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 896016097} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 357b7d5d4e2bc504db44ea6e6f4b3f9a, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &896016101 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 896016097} + m_CullTransparentMesh: 1 --- !u!1 &906197776 GameObject: m_ObjectHideFlags: 0 @@ -546,9 +639,11 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 239318301} - {fileID: 315493449} - {fileID: 1939390636} + - {fileID: 239318301} + - {fileID: 896016098} + - {fileID: 1018932630} m_Father: {fileID: 1768150806} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -570,14 +665,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -595,6 +690,150 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 906197776} m_CullTransparentMesh: 1 +--- !u!1 &1018932629 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1018932630} + - component: {fileID: 1018932633} + - component: {fileID: 1018932632} + - component: {fileID: 1018932631} + m_Layer: 5 + m_Name: Circle (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1018932630 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018932629} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 230, y: -215} + m_SizeDelta: {x: 360, y: 360} + m_Pivot: {x: 1, y: 0.5} +--- !u!95 &1018932631 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018932629} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 51c408377313b474fa55f6c01c841728, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!114 &1018932632 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018932629} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 88410b681ed1df3499ff0660fe5706b4, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1018932633 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018932629} + m_CullTransparentMesh: 1 +--- !u!1 &1183799206 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1183799208} + - component: {fileID: 1183799207} + m_Layer: 0 + m_Name: ThemeSelectionController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1183799207 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1183799206} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30d9f9130bf1d414aaad006b2177bdea, type: 3} + m_Name: + m_EditorClassIdentifier: + themePrefab: {fileID: 1441088452393136277, guid: 67febbbd89041e243b4e201a9f8d91e9, type: 3} + themesContainer: {fileID: 1939390636} + minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} +--- !u!4 &1183799208 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1183799206} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 960, y: 540, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1768150802 GameObject: m_ObjectHideFlags: 0 @@ -607,7 +846,6 @@ GameObject: - component: {fileID: 1768150805} - component: {fileID: 1768150804} - component: {fileID: 1768150803} - - component: {fileID: 1768150807} m_Layer: 5 m_Name: Canvas m_TagString: Untagged @@ -644,10 +882,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -690,28 +928,13 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} ---- !u!114 &1768150807 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1768150802} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 30d9f9130bf1d414aaad006b2177bdea, type: 3} - m_Name: - m_EditorClassIdentifier: - themePrefab: {fileID: 1441088452393136277, guid: 67febbbd89041e243b4e201a9f8d91e9, type: 3} - themesContainer: {fileID: 1939390636} - minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} --- !u!1 &1939390635 GameObject: m_ObjectHideFlags: 0 @@ -742,7 +965,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 2 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} diff --git a/Assets/Common/ScriptableObjects/AnimalsTheme.asset b/Assets/Common/ScriptableObjects/AnimalsTheme.asset index a7817e0..e24710a 100644 --- a/Assets/Common/ScriptableObjects/AnimalsTheme.asset +++ b/Assets/Common/ScriptableObjects/AnimalsTheme.asset @@ -14,72 +14,116 @@ MonoBehaviour: m_EditorClassIdentifier: title: Dieren description: Van vis tot leeuw - index: 2 - model: {fileID: 0} + themeIndex: 2 + modelIndex: 0 learnables: - name: Walvis image: {fileID: 21300000, guid: 2b01165a5836ab14593d7a5862bd6793, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: f1a51ed74f926dd4d926b7e979010cd4, type: 3} - name: Konijn image: {fileID: 21300000, guid: bc11ff9d6cc35de45ab58f39f13d7142, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 13eab628a5046ce4eaa4456e89e91676, type: 3} - name: Giraf image: {fileID: 21300000, guid: 0cc198f1cde659246a199b30459720b1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 8c9255bb112a29646af17dfa8ea4f824, type: 3} - name: Vis image: {fileID: 21300000, guid: 7f105a09a3d164547925ee1bdfa595ca, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 31eae20cf173beb45b49254f75bc9dda, type: 3} - name: Schildpad image: {fileID: 21300000, guid: e519f0f7b00e6834187963a0131cae52, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 4c08a56d960695041b8f28df05656ee7, type: 3} - name: Lama image: {fileID: 21300000, guid: f48ba3c9b39103145b75d6249c0a25f1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 4a9d9cfb418c4144d926788672f77994, type: 3} - name: Dolfijn image: {fileID: 21300000, guid: 4654657a2ebea444898fa6eeaefcd18d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 50984981e18e51f41b2e0ecf8ef5fe9f, type: 3} - name: Haai image: {fileID: 21300000, guid: 313c22e5834595645989d609fe9d8853, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: fed929776552f824f9e923affbd08881, type: 3} - name: Kangoeroe image: {fileID: 21300000, guid: e4af402f37099cd4195d7d2654519744, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 943f84b1b4ff8a94984ed8ea918e716b, type: 3} - name: Kat image: {fileID: 21300000, guid: 73f4e028d9efb644aa23538a749667c5, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 9c6fac3471b9e5e498712c27ead8d523, type: 3} - name: Hond image: {fileID: 21300000, guid: b67b99d98d1ceb1489743bcd78b9ab70, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 7dee256e66c656548a109e60001252a5, type: 3} - name: Kip image: {fileID: 21300000, guid: 61e56570163833e448037bc353ada0ac, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: da5ffb315f3db1f499b0251bb432fb61, type: 3} - name: Leeuw image: {fileID: 21300000, guid: f989719a5c45c7a4183b2bc12c1c4905, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 5ded07bb7f551a1408103cc0450d5ffc, type: 3} - name: Olifant image: {fileID: 21300000, guid: 1392922567cd59d4fb0beceea3f5917a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: d2fc9e7ffac2167498e186a8eca49cec, type: 3} - name: Paard image: {fileID: 21300000, guid: 3c314ae9e10eafb49b57c98c9e779bd8, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 9749acd6e97fb9b428f1620205c81741, type: 3} - name: Panda image: {fileID: 21300000, guid: 33509e453b5093e43a148a668a961c56, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 59de6730d922c3d41a54f8027a8d0038, type: 3} - name: Papegaai image: {fileID: 21300000, guid: 39ac3b86729423846be1fbd56b8d92d6, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: e8a2d27148548cf4eb90db45db389420, type: 3} - name: Ram image: {fileID: 21300000, guid: 8f4a6fabc238910468113f4ffd467ce0, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: a608099d623abe44584c654f45d6d3df, type: 3} - name: Tijger image: {fileID: 21300000, guid: 83d6525e4efa4954091e08095349f45a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 1a35432ec29830a4f9dec7842b8e78a6, type: 3} - name: Varken image: {fileID: 21300000, guid: db31bca6363270441ab54421f55c1263, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 5a756bc6d7be8384b9528855a70b7790, type: 3} - name: Vos image: {fileID: 21300000, guid: 9d5771baa6ea6e041b066135d6798e1c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 2fcc6458613539a4693514cfedd9f490, type: 3} - name: Zebra image: {fileID: 21300000, guid: b203b4e5f8568ff46b2277ce6d61017a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 624b79a549f726343bc01d925c948216, type: 3} diff --git a/Assets/Common/ScriptableObjects/BasicSignsTheme.asset b/Assets/Common/ScriptableObjects/BasicSignsTheme.asset new file mode 100644 index 0000000..e9e71f4 --- /dev/null +++ b/Assets/Common/ScriptableObjects/BasicSignsTheme.asset @@ -0,0 +1,94 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d6b0fdaea76420c48b69a990fabb107f, type: 3} + m_Name: BasicSignsTheme + m_EditorClassIdentifier: + title: Basis Gebaren + description: Van links tot rechts + themeIndex: 1 + modelIndex: 2 + learnables: + - name: Tot ziens + image: {fileID: 21300000, guid: f2a020e24bfa24842bccecf6b36d5b79, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.7 + clip: {fileID: 32900000, guid: 199075a9c3138354db43569bade8faaa, type: 3} + - name: Saluut + image: {fileID: 21300000, guid: 9736ebf7e194d954e8db0c651e72210e, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.65 + clip: {fileID: 32900000, guid: b3ffa09a793bc8742b894a0d90945739, type: 3} + - name: Goedemorgen + image: {fileID: 21300000, guid: 3d2e3ec9ed08795429f60c10f335196b, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.95 + clip: {fileID: 32900000, guid: 088520ac18815d249a627b939d919b87, type: 3} + - name: Goedemiddag + image: {fileID: 21300000, guid: bf52126d7537c894ca4b576c5eef699b, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.65 + clip: {fileID: 32900000, guid: 07593101fbf5f5b48a6081618c359d43, type: 3} + - name: Goed + image: {fileID: 21300000, guid: df027cf65fb04bd408d4062aa9ec0b0f, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.95 + clip: {fileID: 32900000, guid: f9af6f8ba451f9045bb13cb87b5b2945, type: 3} + - name: Slecht + image: {fileID: 21300000, guid: 42286591a195a7542a4f0922fbe161e2, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 + clip: {fileID: 32900000, guid: e552e225d0f46964ea9ee79070e9f03c, type: 3} + - name: Ja + image: {fileID: 21300000, guid: 0b11c08cf900cd041afab0419594dac2, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.6 + clip: {fileID: 32900000, guid: d514b6143c06749489a4a727a10913f0, type: 3} + - name: Links + image: {fileID: 21300000, guid: 1dbac4bae035dc84f8bb19045a290b3c, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 + clip: {fileID: 32900000, guid: d3417d06c92c99d4aab3f370be7430d8, type: 3} + - name: Rechts + image: {fileID: 21300000, guid: 712e26ec9b082ad4bb926c4171815e47, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.6 + clip: {fileID: 32900000, guid: 51936adbe64aee644b81a10958ceba9e, type: 3} + - name: Bedanken + image: {fileID: 21300000, guid: ae9e448e11485c54aa664b69833dce2f, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.6 + clip: {fileID: 32900000, guid: ea0208d218c503b42ba7c0b819127344, type: 3} + - name: Sorry + image: {fileID: 21300000, guid: 4d265c68fdb4f644ba22e74523ba7f1b, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.95 + clip: {fileID: 32900000, guid: d53e61ab6d142164c94776d4ea62edb7, type: 3} + - name: Goedenacht + image: {fileID: 21300000, guid: 77bad74134ac6cd439cc026dafffa3aa, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.6 + clip: {fileID: 32900000, guid: 4d6c8346776deb7449acf087232e640a, type: 3} + - name: Smakelijk + image: {fileID: 21300000, guid: 650f938e5cacbc2409939ab73077b692, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.7 + clip: {fileID: 32900000, guid: 436159822cb53bc4b8d1bcbf83d109ce, type: 3} + - name: Goedenavond + image: {fileID: 21300000, guid: 1df76d321ac1c984e8809e92a5ae6d5f, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.8 + clip: {fileID: 32900000, guid: 5b201af7cea977c4c9bfac53553d4351, type: 3} + - name: Nee + image: {fileID: 21300000, guid: 9107fcdcf02ace74bae5b8dd77835434, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.6 + clip: {fileID: 32900000, guid: c869292eee244624589e5bfbdd43bb09, type: 3} diff --git a/Assets/Common/ScriptableObjects/BasicSignsTheme.asset.meta b/Assets/Common/ScriptableObjects/BasicSignsTheme.asset.meta new file mode 100644 index 0000000..0ede7a4 --- /dev/null +++ b/Assets/Common/ScriptableObjects/BasicSignsTheme.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd48f91f5d3b2d041b08640872a65d9c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/ScriptableObjects/ClothesTheme.asset b/Assets/Common/ScriptableObjects/ClothesTheme.asset index bcc40cf..2cb2e56 100644 --- a/Assets/Common/ScriptableObjects/ClothesTheme.asset +++ b/Assets/Common/ScriptableObjects/ClothesTheme.asset @@ -14,62 +14,101 @@ MonoBehaviour: m_EditorClassIdentifier: title: Kleren en Kleuren description: Van rok tot sok - index: 1 + themeIndex: 1 + modelIndex: 0 learnables: - name: Blauw image: {fileID: 21300000, guid: 182fb89eba9c64041bef31ca35c4bcd8, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: ddbd51ba81efa0d4386063f0908dddbc, type: 3} - name: Bril image: {fileID: 21300000, guid: c671ae6bf5c5e90419add134a669aec1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 50ab64534fbf206448eae89e7f849536, type: 3} - name: Geel image: {fileID: 21300000, guid: c7006b8cc5cff974b9ff307fe13fdd5e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 7e14190a75067624abdb6a2872a4afac, type: 3} - name: Grijs image: {fileID: 21300000, guid: 7d4fdd972dcef1747bcbcc598b075504, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: f71578e140d29484580a9b9ab6ef1b50, type: 3} - name: Groen image: {fileID: 21300000, guid: d1f80913126d4c94285c1160f9e50c24, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: e275659c79beb764b882ed5293d70087, type: 3} - name: Hemd image: {fileID: 21300000, guid: 28d5b4df34fc2b049b2455f303461f45, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 732b94d1c76ad8a4bb3fee5c686c0d8e, type: 3} - name: Hoed image: {fileID: 21300000, guid: cede6c6f958f0ae4bbba6282528292cf, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 6a3028c09a55d4a418b56ea4a716777a, type: 3} - name: Jas image: {fileID: 21300000, guid: 4a61d44b0e2ccb242a97681b429b8343, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 558ee737100d298479641a10ae09852e, type: 3} - name: Kous image: {fileID: 21300000, guid: 83b7dc2f696a1c443acf92f310a61cc3, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: cf8a1b846823a074d90075f29753b679, type: 3} - name: Zwart image: {fileID: 21300000, guid: 5527d4c18ce148a4c8ce7de7b927cb5e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 2895a22e7719def418818a5b532bfbf5, type: 3} - name: Wit image: {fileID: 21300000, guid: 5387f0486602abf479f049d9afa9d3cb, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 351aac8168f9ea34f95878dd90ef5f3b, type: 3} - name: Trui image: {fileID: 21300000, guid: 2413cb0f9b70cd84aae8a3aa1b83e7e8, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: c907e04793964864dad921a6a01af8a7, type: 3} - name: Handschoenen image: {fileID: 21300000, guid: 12d9777dbc9d4f543b822e38838e47d4, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: cf67ee32acd99eb4d935a4fedb7e1fb1, type: 3} - name: Muts image: {fileID: 21300000, guid: b620a409ad2371d43b418b851715df4d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 125c5c87cf540e94098608da4a956b21, type: 3} - name: Oranje image: {fileID: 21300000, guid: 16f645dc2176fa248af566b5295b451a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: d64c7a8ee9206e848b5b3e8ccce0db41, type: 3} - name: Paars image: {fileID: 21300000, guid: d574bf2c96bb5b74080b4cf8ca51312d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: b19ed4b06b9556d4081c0683b495e71a, type: 3} - name: Rood image: {fileID: 21300000, guid: 47a49435e7b8c9a49b162fb4d6f9ceaa, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 552079dd964f93643a4ca82452c49f35, type: 3} - name: Roze image: {fileID: 21300000, guid: e3c4feacdb7710349b326280e2163a84, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 6d35ec9a9a78cf3429a1366279003e06, type: 3} - name: Schoen image: {fileID: 21300000, guid: 2b98a98c11c5bbf4782d9d41b1c9f213, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 422c7afc0cb753b42bf72e281c743097, type: 3} diff --git a/Assets/Common/ScriptableObjects/FamilyTheme.asset b/Assets/Common/ScriptableObjects/FamilyTheme.asset index 9a804ee..3fe32d4 100644 --- a/Assets/Common/ScriptableObjects/FamilyTheme.asset +++ b/Assets/Common/ScriptableObjects/FamilyTheme.asset @@ -14,53 +14,86 @@ MonoBehaviour: m_EditorClassIdentifier: title: Familie description: Van generatie tot generatie - index: 6 + themeIndex: 6 + modelIndex: 0 learnables: - name: Broer image: {fileID: 21300000, guid: eecf67266f150f1489717049489cf16d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: b28449b4d9aeee742a2ccff0b0632287, type: 3} - name: Dochter image: {fileID: 21300000, guid: e3fc0b9401fa388449dc5af9d64649b3, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 62bca0f4ed278fe448fc78c9e74fb06d, type: 3} - name: Echtgenoot image: {fileID: 21300000, guid: 8f62ca0a4fbda0249a1c1c5755044c72, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: dc3cf889664616d4aba5b2cad1489995, type: 3} - name: Familie image: {fileID: 21300000, guid: 79b2160558ee77c4c9c4c08990d1d023, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 793bc470865b11145ad616973d312a34, type: 3} - name: Generatie image: {fileID: 21300000, guid: 5ef20b546d01c8344adcfd87abeed833, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: e6f03e29134e03c4c86fddad1b14d986, type: 3} - name: Gezin image: {fileID: 21300000, guid: 0c45e339ca2a63042a626781e81b7d47, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 03631798d85f3c1478dbfb0a9e9b576b, type: 3} - name: Kind image: {fileID: 21300000, guid: 190ff727bab235644844dcdae4a08f64, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: c71d841cd9441944aabcf18163129268, type: 3} - name: Moeder image: {fileID: 21300000, guid: 322a8fca641097146ad859da5cd5c299, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 055f4bc01648d7741bb1b0299352f83d, type: 3} - name: Neef image: {fileID: 21300000, guid: 6876f7cd47aef414da6a5dcd37fb6aa7, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 1d47f98d0f49d884bb4bba27c2849921, type: 3} - name: Nicht image: {fileID: 21300000, guid: f22221e828db5df48a0c23244184da3f, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 1bbd0c9374ddaab479c7ef3222c5f3f2, type: 3} - name: Oom image: {fileID: 21300000, guid: d64816ca8258e11488281131f8292073, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: d14475211a1e21a43ac0786905a33d5f, type: 3} - name: Ouders image: {fileID: 21300000, guid: 7a3d7c13edb3c1b46b946b79d0ea314c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: a974b184fb3ee214f8c32398e0535c76, type: 3} - name: Tante image: {fileID: 21300000, guid: 00d37184d2522024fa531189cb06afc2, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 614bc070326fe74478a5f971effb7286, type: 3} - name: Vader image: {fileID: 21300000, guid: 525992a7e2aaf3342b5fe7027ff6711c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: dcd795e4c01d40a4d9573aed47c23ea0, type: 3} - name: Zoon image: {fileID: 21300000, guid: 54504dcf0d7601147a53b4de0edc1292, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 27ac8f0a8c9a07b4fa170a72fc255566, type: 3} - name: Zus image: {fileID: 21300000, guid: 9356d7e0991e75d4098d58ba52c14c3d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 644394f006b4cf246a26ca73c5171280, type: 3} diff --git a/Assets/Common/ScriptableObjects/FingerspellingTheme.asset b/Assets/Common/ScriptableObjects/FingerspellingTheme.asset index 6e91a5a..83bc393 100644 --- a/Assets/Common/ScriptableObjects/FingerspellingTheme.asset +++ b/Assets/Common/ScriptableObjects/FingerspellingTheme.asset @@ -14,84 +14,136 @@ MonoBehaviour: m_EditorClassIdentifier: title: Handalfabet description: Van A tot Z - index: 0 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 0 + modelIndex: 1 learnables: - name: A image: {fileID: 21300000, guid: 4eb4ef55f866f114dafb722f4bd05c76, type: 3} + handGuide: {fileID: 21300000, guid: ed5c09a22f5dcb3498f246f9490aa533, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 94a82fe62ff36fc46b79eaca5d78c324, type: 3} - name: B image: {fileID: 21300000, guid: 4dda47b7ae59ce0499ff8e89a310b351, type: 3} + handGuide: {fileID: 21300000, guid: 8e050dadd89377d4fb62a4ad8f9e8535, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 318bd1a8b7889b94eb4b679a8e422c82, type: 3} - name: C image: {fileID: 21300000, guid: bb08a500be7994743bdf7f1e38e6538e, type: 3} + handGuide: {fileID: 21300000, guid: 330c40bb91dc4b545829054df966ea97, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 788822d230357a141ac24d2fb9c75b96, type: 3} - name: D image: {fileID: 21300000, guid: 3decd69ae4947b240bd680f39b6c5779, type: 3} + handGuide: {fileID: 21300000, guid: bd9ec5405bb0fea449e9da0f88c524b3, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 2b276c0661e3c1f46b485c382c3d2eb2, type: 3} - name: E image: {fileID: 21300000, guid: ab8d9fdabea483c409535c3bb26305d8, type: 3} + handGuide: {fileID: 21300000, guid: de823bdd2e36be047a6c7937e5bf5cda, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 23b63c8aaace85149adba9082f75bba5, type: 3} - name: F image: {fileID: 21300000, guid: d58ae54ae96a8d741854c485d4c03d52, type: 3} + handGuide: {fileID: 21300000, guid: 044b86526fb6697488bbacdc1d76fa03, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: e8272b19b1f494c44a88be82259d8478, type: 3} - name: G image: {fileID: 21300000, guid: d4507d82135bd9a4ea1fa5cc0afe19ba, type: 3} + handGuide: {fileID: 21300000, guid: 8e61bbc6d63e9d14f88136e81a0b9d84, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 9793a0da1cef6094fa45dbf42f2f593a, type: 3} - name: H image: {fileID: 21300000, guid: 2720176db57a2384a8b44e023f1548cc, type: 3} + handGuide: {fileID: 21300000, guid: ed4e4023600c05347874842b68f62231, type: 3} + thresholdPercentage: 0.8 clip: {fileID: 32900000, guid: 27d1b6711ce142a408ac26b1fcfaf68e, type: 3} - name: I image: {fileID: 21300000, guid: d827fa45fec334e42bdaf76859e73db6, type: 3} + handGuide: {fileID: 21300000, guid: d5bbee7ab92ab2149bffdcd93b93a2d3, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: f1022e53c692f5e488bc2bf68ef42c05, type: 3} - name: J image: {fileID: 21300000, guid: 8293bed5458bb2e4380d47a9d78e1ca8, type: 3} + handGuide: {fileID: 21300000, guid: 32df0c392f6fbfe4faa3bd6f0f009b7a, type: 3} + thresholdPercentage: 0.95 clip: {fileID: 32900000, guid: ed10642881e9a304ba7a6bfb0a40c871, type: 3} - name: K image: {fileID: 21300000, guid: 2353b41a97a55014a9168e5f19352162, type: 3} + handGuide: {fileID: 21300000, guid: 54e8aaec5729e0b438b755ce1c5b8c9f, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: aa5026b1ef45e3742a08c8112e8a6f91, type: 3} - name: L image: {fileID: 21300000, guid: c9ebdbf10e096ed4c9bf08becc1067c3, type: 3} + handGuide: {fileID: 21300000, guid: c042d24972c09f849854641b82d164bf, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 4614fd87478f09a4fb0dae142dcb283f, type: 3} - name: M image: {fileID: 21300000, guid: 1d8d7e858fe9d7d4a83ae2c47aa186a9, type: 3} + handGuide: {fileID: 21300000, guid: 6014df6c8e5794c4c91b3d7c636b073f, type: 3} + thresholdPercentage: 0.75 clip: {fileID: 32900000, guid: 480ffa4003b79ed41bcd22c25c2b4b0a, type: 3} - name: N image: {fileID: 21300000, guid: 746cc027bdb95d640b2b7c3b717f209c, type: 3} + handGuide: {fileID: 21300000, guid: 4a88b6a6c8a4bf5479b9c033313c20dc, type: 3} + thresholdPercentage: 0.7 clip: {fileID: 32900000, guid: 6d40896901cbaad4a9c229e27eee4a0b, type: 3} - name: O image: {fileID: 21300000, guid: cf58cec61def4644d966172584346ea7, type: 3} + handGuide: {fileID: 21300000, guid: 13dd6d407842cbc41a74312f86a7451a, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: e100ef044ef83504e859e526ed84cead, type: 3} - name: P image: {fileID: 21300000, guid: 070eca79d6b8ece479abe291f5ecf1f1, type: 3} + handGuide: {fileID: 21300000, guid: de3b948a0c6e04547afffebadd53c44e, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 85c4e40c247c2db46bc3eb5b7306d14c, type: 3} - name: Q image: {fileID: 21300000, guid: 26f522f2e30c5b640b3e21aedc311346, type: 3} + handGuide: {fileID: 21300000, guid: 189b131f13ce67844933e28c6d031cad, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 34465d640f4c47948b3a3007226eafe3, type: 3} - name: R image: {fileID: 21300000, guid: 5a21107f2fda09e449f052f986c25aee, type: 3} + handGuide: {fileID: 21300000, guid: a05e3762c949b83428dc2baf99ab1b34, type: 3} + thresholdPercentage: 0.75 clip: {fileID: 32900000, guid: 29ab11460587e4e458fc5e367245db90, type: 3} - name: S image: {fileID: 21300000, guid: d934313344ebc264cb9a7ab061c5c4aa, type: 3} + handGuide: {fileID: 21300000, guid: 5c157ea40838eb74f8226c89a7244613, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 6d7adadd8bbcd284ba047e18fe0b0350, type: 3} - name: T image: {fileID: 21300000, guid: 1c0841dbd38336841acbe8b5d2b70ff4, type: 3} + handGuide: {fileID: 21300000, guid: ecd6f60f1bc981b4fb5082ac07e69b6f, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: bb6526ca38b2fda4b8d976d106789f8d, type: 3} - name: U image: {fileID: 21300000, guid: e94c3a7781305514da0676f64c81d231, type: 3} + handGuide: {fileID: 21300000, guid: c81ae3b4548e432498e92c09b4f6d0c9, type: 3} + thresholdPercentage: 0.8 clip: {fileID: 32900000, guid: b65d525135c41e04fbe646dcf4dc0714, type: 3} - name: V image: {fileID: 21300000, guid: 73ff28d33f02abb4386f970bb3417767, type: 3} + handGuide: {fileID: 21300000, guid: 5ab8fc41b65050e4a884ef7ac126318b, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 4ae264889e31d344a80b41449e7d5755, type: 3} - name: W image: {fileID: 21300000, guid: ca7dcaa8441f3314394af32f35d9c5a9, type: 3} + handGuide: {fileID: 21300000, guid: f345e4c4670a26e43bb67fdd98d17aa5, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: c4cca5e21c896994088b3f8e55cb619e, type: 3} - name: X image: {fileID: 21300000, guid: 034ab0453d401c243901dc5c74eccda5, type: 3} + handGuide: {fileID: 21300000, guid: 2c38602225a250a45be1017aab650a3d, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: ed96233595fdef448bcb5ea59df9915a, type: 3} - name: Y image: {fileID: 21300000, guid: 9e46e7579c4695f429c05fe204fe2442, type: 3} + handGuide: {fileID: 21300000, guid: 6f880b9858734b34e8d014189cf0535e, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: f126a23d57436ad4ba1b2130f08bce1e, type: 3} - name: Z image: {fileID: 21300000, guid: e3ddc281a25573d479ee69e8f0196b53, type: 3} + handGuide: {fileID: 21300000, guid: de44788bbe2193043a246d12d2df52e5, type: 3} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 39bdb6ec75c70b54f987683f0140e508, type: 3} diff --git a/Assets/Common/ScriptableObjects/FoodTheme.asset b/Assets/Common/ScriptableObjects/FoodTheme.asset index 80a80d8..762d715 100644 --- a/Assets/Common/ScriptableObjects/FoodTheme.asset +++ b/Assets/Common/ScriptableObjects/FoodTheme.asset @@ -14,72 +14,116 @@ MonoBehaviour: m_EditorClassIdentifier: title: Groenten en Fruit description: Van kers tot pompoen - index: 3 - model: {fileID: 0} + themeIndex: 3 + modelIndex: 0 learnables: - name: Aardappel image: {fileID: 21300000, guid: 2610cdbc24a125f43ada7fed67d8f51b, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: fa2e0dc56498fc641bcc48c0993e8da8, type: 3} - name: Aardbei image: {fileID: 21300000, guid: 1a28fa2c46acbb1408633e4e98061d56, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: a1398d26e1693944889608325f49f559, type: 3} - name: Ajuin image: {fileID: 21300000, guid: b1581340c7eea4448835492296442cba, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 89fa02eca3ccd39479723ba10b16a7f9, type: 3} - name: Appel image: {fileID: 21300000, guid: 1a4d7d2fe1dc58448b2c0451d2924003, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: ce9125ad311f38a40baca216971b9d67, type: 3} - name: Appelsien image: {fileID: 21300000, guid: c03308f45b0a99040a9412bb5e780cdd, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: e2b8bd08c3716d24c94933557b3f82fb, type: 3} - name: Banaan image: {fileID: 21300000, guid: 8009fc8cfee7ea848a678e056731c02e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 169aef4dd609cd4428fd7e61165fa92c, type: 3} - name: Bessen image: {fileID: 21300000, guid: 7272bfa2b3f87564eb961d41c641479d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 9557e499fc1215242b8c168dabe2668b, type: 3} - name: Bloemkool image: {fileID: 21300000, guid: 487940208ac3a0d4bb41696e11e9f8e7, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 564f670a4caa3054ca99be6f7415b66e, type: 3} - name: Bonen image: {fileID: 21300000, guid: ad47c02ff85e06948b9f73cae6eb0221, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 70f2d26e55527f24fbaa6e59e09e5cfa, type: 3} - name: Broccoli image: {fileID: 21300000, guid: b76404afa08793f4391e71078bed6be7, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 55d34fcfb105b574f90f064da7aaba37, type: 3} - name: Champignon image: {fileID: 21300000, guid: 6a89fa1b42445d6459752b97fc755470, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 4914ecb76cd051048b3ea7400762648b, type: 3} - name: Erwt image: {fileID: 21300000, guid: d5d61528ca4d25e448c0435975e2a193, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: eba376b2044d6b649b6fd9a347ad8d14, type: 3} - name: Kers image: {fileID: 21300000, guid: e1ae6da5a172cba498b406aeb8d30bfc, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: fae6a9a6defd2e44e9b44241d023b312, type: 3} - name: Kiwi image: {fileID: 21300000, guid: c04017a4f1c894f44b11b4348935e87b, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 5027d0d12146e2e42b44a2b3c44016ee, type: 3} - name: Komkommer image: {fileID: 21300000, guid: affe34960b38b8f4b95f3eeb8b10c795, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 0dabca6f767b4244784fe05093922ac9, type: 3} - name: Meloen image: {fileID: 21300000, guid: d8391180fd69bef478f711f327f5c60e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: a349e9e8ee3e9594295b0b667ceb13fd, type: 3} - name: Peer image: {fileID: 21300000, guid: 5e5d7221dd9626c4bb15c4bc5abe0e84, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 07f2c3e52fce7674eafa22daa9c567f9, type: 3} - name: Perzik image: {fileID: 21300000, guid: 439c062e9ba9d0f439dffd41509ceee7, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 1f6cdc404076aef4da77cb0cda09c0e1, type: 3} - name: Pompoen image: {fileID: 21300000, guid: 4ea79b62a6cb15345959144622dc9f43, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 66646a278adf0894682ff97fc011f927, type: 3} - name: Prei image: {fileID: 21300000, guid: c2fe2cad9d48a784980823528889af18, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: a08119dd84708e9488a58f971d1e4350, type: 3} - name: Tomaat image: {fileID: 21300000, guid: e16943962d961d948a0a6dc73ebf2b0b, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: 7ca3dbd42b3033341b3c5c51059643f6, type: 3} - name: Wortel image: {fileID: 21300000, guid: 8962e03659a079546810c3ad9c8a211c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 32900000, guid: ef9554901c0c6784e9102d5c1fd28a9a, type: 3} diff --git a/Assets/Common/ScriptableObjects/HobbyTheme.asset b/Assets/Common/ScriptableObjects/HobbyTheme.asset index c17ad1d..576e229 100644 --- a/Assets/Common/ScriptableObjects/HobbyTheme.asset +++ b/Assets/Common/ScriptableObjects/HobbyTheme.asset @@ -12,52 +12,83 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d6b0fdaea76420c48b69a990fabb107f, type: 3} m_Name: HobbyTheme m_EditorClassIdentifier: - title: Hobbies + title: Hobby's description: Van schilderen tot reizen - index: 4 + themeIndex: 4 + modelIndex: 0 learnables: - name: Dansen image: {fileID: 21300000, guid: 6d405f607ae817744b49f921f0611088, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 4b4acf2c6d2408b40bab36fa539a66d6, type: 3} - name: Fietsen image: {fileID: 21300000, guid: 7df74e91898d9a74cbb621afc8b871f0, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 113b92b5eaada264d9fe7852ab0d68c9, type: 3} - name: Kaarten image: {fileID: 21300000, guid: afd6e9f6acae11a498e500da41a5c7be, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: dda8f60564c509147a33a097af56f4da, type: 3} - name: Lopen image: {fileID: 21300000, guid: 589dcd93dd2ebfd4f885b2495164bf4f, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: fdf57fb5257b4c54b8f90ffd3153f7d3, type: 3} - name: Muziek image: {fileID: 21300000, guid: 0225e90ef27951a4bb3aa2f0dd109d52, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 80c9c6b695a87784899db3204262af57, type: 3} - name: Paardrijden image: {fileID: 21300000, guid: c119f0999a2010d4abe34231b7a30707, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 1f1ef32c6ef802747bec1f9c47a719ea, type: 3} - name: Poker image: {fileID: 21300000, guid: 5a750da0f508d88419c6744d678f12d5, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: b6758433647bc6745af145a6062a462c, type: 3} - name: Reizen image: {fileID: 21300000, guid: da70d64cd98bde64f9fe7c11cf015b0e, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 57c1edc6a2cad6446bce7b80d3dcfe1f, type: 3} - name: Schilderen image: {fileID: 21300000, guid: 626d822c212ea1b45abd0dc9bc625c19, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 40181f017e1cc4d4bbd9a6189e858a38, type: 3} - name: Sport image: {fileID: 21300000, guid: dd8ed8c8a2668064283f2adaec9ba9fc, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: d1c9f4f5f3ef30144b05942b7d531b13, type: 3} - name: Tekenen image: {fileID: 21300000, guid: 05d42c2b3157bb14ba9b7f1cf70f1a36, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: bcb2e2847ba47404980a0c95f8314112, type: 3} - name: Toneel image: {fileID: 21300000, guid: 3701f5e4f55d0e84fadd0cb718f4aa27, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 630f90d46aa472248ab238916af72e4c, type: 3} - name: Voetbal image: {fileID: 21300000, guid: ac34db14477c3fb4ca5e1925ec63807d, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 4d8e15b2d6c74414cb31628b54c91180, type: 3} - name: Wandelen image: {fileID: 21300000, guid: e22755368101b324181d71109cc83d67, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: eabf920307a322f4d83f3f9544a455ac, type: 3} - name: Zwemmen image: {fileID: 21300000, guid: b01343f4df018f04c82ef0e6fa9e3090, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 02420b604c695f341ac6bce97805e1b9, type: 3} diff --git a/Assets/Common/ScriptableObjects/HouseTheme.asset b/Assets/Common/ScriptableObjects/HouseTheme.asset index 3e9bf20..166ef65 100644 --- a/Assets/Common/ScriptableObjects/HouseTheme.asset +++ b/Assets/Common/ScriptableObjects/HouseTheme.asset @@ -12,55 +12,88 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d6b0fdaea76420c48b69a990fabb107f, type: 3} m_Name: HouseTheme m_EditorClassIdentifier: - title: Huis beschrijven + title: Het huis description: Van zetel tot villa - index: 5 + themeIndex: 5 + modelIndex: 0 learnables: - name: Keuken image: {fileID: 21300000, guid: b17ce5bf59092b847b084d3400e7a1b4, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 3f52680b4a6d7e34cbf1ea0ef3ce1fa3, type: 3} - name: Gang image: {fileID: 21300000, guid: 3643fe1f56aae524bb6ed9b8853ce2dc, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: e600cc81d36bdb2409f53cc35bbef50b, type: 3} - name: Badkamer image: {fileID: 21300000, guid: bc8d63bfa541b0a41bfe02cc2d1417cd, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 9b54826551ddaac4d87df4b893550039, type: 3} - name: Living image: {fileID: 21300000, guid: f0f32521c0b858144b27f0393c7690e5, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: ecb6e7cc9293892478e57b491655d7ff, type: 3} - name: Slaapkamer image: {fileID: 21300000, guid: 2803bab3b0944364e83c34fcea39f7b1, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: be0bf4e3852aa4942a54dee0e94ee72e, type: 3} - name: Villa image: {fileID: 21300000, guid: c8bc006b29807e34d888ea31e5d53841, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 0723800c4b5fc684a852f69c229f3742, type: 3} - name: Huis image: {fileID: 21300000, guid: 93d02a123ee1f3542b15eb5165212674, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: a5f609b5a706b6549bfc00276aa54d45, type: 3} - name: Appartement image: {fileID: 21300000, guid: 6c6d074973c092a4caa72d50ca49ce89, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 71b229de73980e14db1ea45a58adfb9d, type: 3} - name: Bed image: {fileID: 21300000, guid: 9c1848215213efe49af84b703896340d, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 1fea2657552d0cd49afdf88792755bba, type: 3} - name: Bureau image: {fileID: 21300000, guid: 820bc37a6551974478d9fad4afca05e3, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 297b19cbb7e6dcd4ea8cf83ac3aeef3e, type: 3} - name: Chalet image: {fileID: 21300000, guid: 5c1c3408e8d7d204fa9ce72342749690, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: a866b80d2da42144793f48d327409402, type: 3} - name: Kast image: {fileID: 21300000, guid: 4d1076b98d294f14abdc586590762136, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: e8c14c74f7798b84682379f20ee9c36d, type: 3} - name: Kleerkast image: {fileID: 21300000, guid: b767f5e5e770d904f9a978211119fb52, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: f04395e9930586a43851ce03e064ca47, type: 3} - name: Zetel image: {fileID: 21300000, guid: 6878cc948d694474098857ef41535aa0, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 2586366760cd29c44b66ac3d221559c4, type: 3} - name: Stoel image: {fileID: 21300000, guid: 9b6d34ea549acee49978ad400187151d, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 5bc395b6e838c9149a8fbd1d4cbefbe1, type: 3} - name: Tafel image: {fileID: 21300000, guid: 6ec51b3aa2cc0fd42b85cadcf66a32cc, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 32900000, guid: 7f8f5de97d210544c88bd28e77f2c242, type: 3} diff --git a/Assets/Common/ScriptableObjects/SignThemeList.asset b/Assets/Common/ScriptableObjects/SignThemeList.asset index 047635f..36a9250 100644 --- a/Assets/Common/ScriptableObjects/SignThemeList.asset +++ b/Assets/Common/ScriptableObjects/SignThemeList.asset @@ -14,9 +14,11 @@ MonoBehaviour: m_EditorClassIdentifier: currentThemeIndex: 0 themes: + - {fileID: 11400000, guid: dd48f91f5d3b2d041b08640872a65d9c, type: 2} - {fileID: 11400000, guid: 6abf76ea9ca532a44b852393ad2d219f, type: 2} - {fileID: 11400000, guid: 5755ca304d16d3449991668b383d7dd5, type: 2} - {fileID: 11400000, guid: 12f3260b96f41d1478804406d793a927, type: 2} - {fileID: 11400000, guid: adc0467561c43494db61e303d4aeefee, type: 2} - {fileID: 11400000, guid: 40cf29fa07988ee4aa02e227c20df3a7, type: 2} - {fileID: 11400000, guid: 70b23bd64ac995b41ae7c26221a9d039, type: 2} + - {fileID: 11400000, guid: e02921b294fdad940b6e4d57e716d3bf, type: 2} diff --git a/Assets/Common/ScriptableObjects/SpellingBasicsTheme.asset b/Assets/Common/ScriptableObjects/SpellingBasicsTheme.asset index 728fc13..e55e420 100644 --- a/Assets/Common/ScriptableObjects/SpellingBasicsTheme.asset +++ b/Assets/Common/ScriptableObjects/SpellingBasicsTheme.asset @@ -14,45 +14,71 @@ MonoBehaviour: m_EditorClassIdentifier: title: Basics description: Van welkom tot stop - index: 10 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 10 + modelIndex: 1 learnables: - name: Hallo image: {fileID: 21300000, guid: f2a020e24bfa24842bccecf6b36d5b79, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Alstublieft image: {fileID: 21300000, guid: 027a60ab9a4c4cd40a9bf9184c0fff78, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Bravo image: {fileID: 21300000, guid: 31118947b58b03a41bd950b9a56aa630, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Dank U image: {fileID: 21300000, guid: ae9e448e11485c54aa664b69833dce2f, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Goed Zo image: {fileID: 21300000, guid: df027cf65fb04bd408d4062aa9ec0b0f, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Goeiemorgen image: {fileID: 21300000, guid: 7077e2980ce4d7e4eaf16c80b62adb18, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Ja image: {fileID: 21300000, guid: 0b11c08cf900cd041afab0419594dac2, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Nee image: {fileID: 21300000, guid: 82677c0d46df9ec4cb295bc054c6d56b, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Links image: {fileID: 21300000, guid: 1dbac4bae035dc84f8bb19045a290b3c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Rechts image: {fileID: 21300000, guid: 712e26ec9b082ad4bb926c4171815e47, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Slaapwel image: {fileID: 21300000, guid: 2f0049ac615d7224d925d5692eade66e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Stop image: {fileID: 21300000, guid: 9107fcdcf02ace74bae5b8dd77835434, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Welkom image: {fileID: 21300000, guid: bca90b281ada8c64cbb86f75c70bc510, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingBuildings.asset b/Assets/Common/ScriptableObjects/SpellingBuildings.asset index 069d1fc..c2ab242 100644 --- a/Assets/Common/ScriptableObjects/SpellingBuildings.asset +++ b/Assets/Common/ScriptableObjects/SpellingBuildings.asset @@ -14,51 +14,81 @@ MonoBehaviour: m_EditorClassIdentifier: title: In de Stad description: Van park tot zwembad - index: 8 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 8 + modelIndex: 1 learnables: - name: Park image: {fileID: 21300000, guid: 8ea62bbfad596234c9f6ba49c41b3b08, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Appartement image: {fileID: 21300000, guid: a2a80a53e08111b409a74a20938e1ee6, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Bibliotheek image: {fileID: 21300000, guid: 195175605283f3c458d0295b43d7e809, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Bioscoop image: {fileID: 21300000, guid: cad55eea65a2f3d459658eede9e698e1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Huis image: {fileID: 21300000, guid: 57c236ee7238a294baef494445a9b882, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Speelpleintje image: {fileID: 21300000, guid: 9b7351845516f784a87ca62a5d4eb821, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Sporthal image: {fileID: 21300000, guid: 5b02bf51927953247b995b79569bb08c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Stadion image: {fileID: 21300000, guid: 1f2351ab27af1a449a428787787fe926, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Station image: {fileID: 21300000, guid: 77f4cefcea6b2f945b952c51e9e496f1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Tent image: {fileID: 21300000, guid: 448eb2d34f79a4b4388c2a3e8306f147, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Theater image: {fileID: 21300000, guid: 58bcc5a439fcac949bc01f188dd17be7, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Toren image: {fileID: 21300000, guid: 6d0c05526dcf9e342966ce3020e24fd8, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Winkel image: {fileID: 21300000, guid: 4b6010c64cf91e247bb233e0464daa86, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Ziekenhuis image: {fileID: 21300000, guid: ed2c7508e1d95504ab52452284385d60, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Zwembad image: {fileID: 21300000, guid: 6bd4d04bc90d1c047a261990c53806a3, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingFarm.asset b/Assets/Common/ScriptableObjects/SpellingFarm.asset index ea05801..ad29b33 100644 --- a/Assets/Common/ScriptableObjects/SpellingFarm.asset +++ b/Assets/Common/ScriptableObjects/SpellingFarm.asset @@ -14,51 +14,81 @@ MonoBehaviour: m_EditorClassIdentifier: title: Boerderijdieren description: Van konijn tot kip - index: 16 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 16 + modelIndex: 1 learnables: - name: kat image: {fileID: 21300000, guid: 73f4e028d9efb644aa23538a749667c5, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: hond image: {fileID: 21300000, guid: b67b99d98d1ceb1489743bcd78b9ab70, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: konijn image: {fileID: 21300000, guid: bc11ff9d6cc35de45ab58f39f13d7142, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: cavia image: {fileID: 21300000, guid: 671bf6375a004ae42ba2178f3e376f7e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: paard image: {fileID: 21300000, guid: 3c314ae9e10eafb49b57c98c9e779bd8, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Varken image: {fileID: 21300000, guid: db31bca6363270441ab54421f55c1263, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Koe image: {fileID: 21300000, guid: 8e69dfd19237abb4f98eb11e74153109, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Lama image: {fileID: 21300000, guid: f48ba3c9b39103145b75d6249c0a25f1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Alpaca image: {fileID: 21300000, guid: 399cc241fc79bd74db314f146e7fb6b9, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Kip image: {fileID: 21300000, guid: 61e56570163833e448037bc353ada0ac, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Schaap image: {fileID: 21300000, guid: 1118d67f50622cc4ab02aa23c6dc1fd4, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Ram image: {fileID: 21300000, guid: 8f4a6fabc238910468113f4ffd467ce0, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Goudvis image: {fileID: 21300000, guid: 7f105a09a3d164547925ee1bdfa595ca, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Schildpad image: {fileID: 21300000, guid: e519f0f7b00e6834187963a0131cae52, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Papegaai image: {fileID: 21300000, guid: 39ac3b86729423846be1fbd56b8d92d6, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingFruit.asset b/Assets/Common/ScriptableObjects/SpellingFruit.asset index c8c4a1d..134be1b 100644 --- a/Assets/Common/ScriptableObjects/SpellingFruit.asset +++ b/Assets/Common/ScriptableObjects/SpellingFruit.asset @@ -14,48 +14,76 @@ MonoBehaviour: m_EditorClassIdentifier: title: Fruit description: Van aardbei tot kers - index: 13 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 13 + modelIndex: 1 learnables: - name: Aardbei image: {fileID: 21300000, guid: 1a28fa2c46acbb1408633e4e98061d56, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Appel image: {fileID: 21300000, guid: 1a4d7d2fe1dc58448b2c0451d2924003, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Appelsien image: {fileID: 21300000, guid: c03308f45b0a99040a9412bb5e780cdd, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Banaan image: {fileID: 21300000, guid: 8009fc8cfee7ea848a678e056731c02e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Bessen image: {fileID: 21300000, guid: 7272bfa2b3f87564eb961d41c641479d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Citroen image: {fileID: 21300000, guid: eeaf3a15c797b6d499d04a1755dfb264, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Druiven image: {fileID: 21300000, guid: e0f093ba55158c9409202d27574ac137, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Kers image: {fileID: 21300000, guid: e1ae6da5a172cba498b406aeb8d30bfc, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Kiwi image: {fileID: 21300000, guid: c04017a4f1c894f44b11b4348935e87b, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Meloen image: {fileID: 21300000, guid: d8391180fd69bef478f711f327f5c60e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Papaja image: {fileID: 21300000, guid: 7d3621c9975f90f49b7147f375453499, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Peer image: {fileID: 21300000, guid: 5e5d7221dd9626c4bb15c4bc5abe0e84, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Perzik image: {fileID: 21300000, guid: 439c062e9ba9d0f439dffd41509ceee7, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Tomaat image: {fileID: 21300000, guid: e16943962d961d948a0a6dc73ebf2b0b, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingGeography.asset b/Assets/Common/ScriptableObjects/SpellingGeography.asset index c688b95..1d11b09 100644 --- a/Assets/Common/ScriptableObjects/SpellingGeography.asset +++ b/Assets/Common/ScriptableObjects/SpellingGeography.asset @@ -14,69 +14,111 @@ MonoBehaviour: m_EditorClassIdentifier: title: Geografie description: Van hier tot China - index: 7 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 7 + modelIndex: 1 learnables: - name: China image: {fileID: 21300000, guid: a5c1efdb79dcfb54aaf2723f4b4842be, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Australie image: {fileID: 21300000, guid: b3e2fba5fb3a3574186357f297664e4c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Belgie image: {fileID: 21300000, guid: b6c94794c5a511f4f8dbca6505a3589f, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Canada image: {fileID: 21300000, guid: f25bc0b48c11dbe4680713ac9e29da03, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Colombia image: {fileID: 21300000, guid: 80118537f1c15e6448c21294727cac65, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Duitsland image: {fileID: 21300000, guid: a634f69689e4af14884b24ac2f248dc1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Europa image: {fileID: 21300000, guid: 5e3c345e006acf74791d272061159b89, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Finland image: {fileID: 21300000, guid: 263ab0c625efd97458380f4460cc224e, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Frankrijk image: {fileID: 21300000, guid: 787bf66fabd593c4fa2f97246cd796c9, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Griekenland image: {fileID: 21300000, guid: 8f88dcc790fc9aa4092aa932a4435296, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Ierland image: {fileID: 21300000, guid: 664164a2b68411641a9372f7bf307955, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: India image: {fileID: 21300000, guid: 0df3311450e8a814294559d9d8935426, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Italie image: {fileID: 21300000, guid: 9b91d580e0077554e9c9ebe042121d63, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Japan image: {fileID: 21300000, guid: cd10705f388bd804797b8bb624e300fe, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Nederland image: {fileID: 21300000, guid: 079d20b4822fd5847b9759ef0adbf35a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Noorwegen image: {fileID: 21300000, guid: 6612d3cbb4cf65648aa09e4d7028a7c1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Portugal image: {fileID: 21300000, guid: 142bf75d78226a543bf156bc3f71ecce, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Rusland image: {fileID: 21300000, guid: 1cccf029519ee5944874fd7d6e305c6b, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Qatar image: {fileID: 21300000, guid: e3554841d4cb066448e6f35b220e2abd, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Spanje image: {fileID: 21300000, guid: 24d8ce79d5ccf0f45a9219e1d2b90fc0, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Zweden image: {fileID: 21300000, guid: 9f2ca39eb65a6cd49b8c15b058593f55, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingHobbies.asset b/Assets/Common/ScriptableObjects/SpellingHobbies.asset index d4ccf05..9f11f7a 100644 --- a/Assets/Common/ScriptableObjects/SpellingHobbies.asset +++ b/Assets/Common/ScriptableObjects/SpellingHobbies.asset @@ -12,56 +12,88 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d6b0fdaea76420c48b69a990fabb107f, type: 3} m_Name: SpellingHobbies m_EditorClassIdentifier: - title: Hobbies + title: Hobby's description: Van sport tot muziek - index: 11 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 4 + modelIndex: 1 learnables: - name: Dansen image: {fileID: 21300000, guid: 6d405f607ae817744b49f921f0611088, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Fietsen image: {fileID: 21300000, guid: 7df74e91898d9a74cbb621afc8b871f0, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Kaarten image: {fileID: 21300000, guid: afd6e9f6acae11a498e500da41a5c7be, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Lopen image: {fileID: 21300000, guid: 589dcd93dd2ebfd4f885b2495164bf4f, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Muziek image: {fileID: 21300000, guid: 0225e90ef27951a4bb3aa2f0dd109d52, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Paardrijden image: {fileID: 21300000, guid: c119f0999a2010d4abe34231b7a30707, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Quizzen image: {fileID: 21300000, guid: bb29251071801564aa5fb1242ead844b, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Poker image: {fileID: 21300000, guid: 5a750da0f508d88419c6744d678f12d5, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Reizen image: {fileID: 21300000, guid: da70d64cd98bde64f9fe7c11cf015b0e, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Schilderen image: {fileID: 21300000, guid: 626d822c212ea1b45abd0dc9bc625c19, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Sport image: {fileID: 21300000, guid: dd8ed8c8a2668064283f2adaec9ba9fc, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Tekenen image: {fileID: 21300000, guid: 05d42c2b3157bb14ba9b7f1cf70f1a36, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Toneel image: {fileID: 21300000, guid: 3701f5e4f55d0e84fadd0cb718f4aa27, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Voetbal image: {fileID: 21300000, guid: ac34db14477c3fb4ca5e1925ec63807d, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Wandelen image: {fileID: 21300000, guid: e22755368101b324181d71109cc83d67, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} - name: Zwemmen image: {fileID: 21300000, guid: b01343f4df018f04c82ef0e6fa9e3090, type: 3} + handGuide: {fileID: 0} + thresholdPercentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingPeople.asset b/Assets/Common/ScriptableObjects/SpellingPeople.asset index b156af6..59acdf1 100644 --- a/Assets/Common/ScriptableObjects/SpellingPeople.asset +++ b/Assets/Common/ScriptableObjects/SpellingPeople.asset @@ -14,51 +14,81 @@ MonoBehaviour: m_EditorClassIdentifier: title: Mensen description: Van vrienden tot familie - index: 12 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 12 + modelIndex: 1 learnables: - name: Broer image: {fileID: 21300000, guid: daebe503f7767b64683d8eeab617e8bc, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Baby image: {fileID: 21300000, guid: 2a94b9c33a71bef4fa91a98ff77b65ce, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Jongen image: {fileID: 21300000, guid: b874e4bc5a44a3e468d6c5b7d13c4686, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Man image: {fileID: 21300000, guid: b4427d880e915c149b5328fdb60d6100, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Meisje image: {fileID: 21300000, guid: 8223750f5664b454ca1f968fc9cbd7d6, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Neef image: {fileID: 21300000, guid: 1814cf10743709849b0ee51a511b08e8, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Nicht image: {fileID: 21300000, guid: 48274dd8be0fc5a48995de7b90b8c486, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Nonkel image: {fileID: 21300000, guid: 9cd035c8b5357714f8a24a1f659ea0c6, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Oma image: {fileID: 21300000, guid: 0445b96d15746d545bcc2ee496e1b9ca, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Opa image: {fileID: 21300000, guid: 8e849a26214ca31479eab0fff6b9c09c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Ouders image: {fileID: 21300000, guid: 0822aa7a46faf5b4e87ffd574be28e98, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Tante image: {fileID: 21300000, guid: dd64146652642f84da62fe7b56cd9f64, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Vrienden image: {fileID: 21300000, guid: 7b72529c5f1ef7b42a81d3da5c23a3b8, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Vrouw image: {fileID: 21300000, guid: 9699459068cabf34c9f97f84e96eadfd, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Zus image: {fileID: 21300000, guid: 77b55b694a3b5af4ba499f87b84e5c11, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingSports.asset b/Assets/Common/ScriptableObjects/SpellingSports.asset index f148555..c5d00a6 100644 --- a/Assets/Common/ScriptableObjects/SpellingSports.asset +++ b/Assets/Common/ScriptableObjects/SpellingSports.asset @@ -14,54 +14,86 @@ MonoBehaviour: m_EditorClassIdentifier: title: Sporten description: Van atletiek tot zeilen - index: 9 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 9 + modelIndex: 1 learnables: - name: Atletiek image: {fileID: 21300000, guid: 25a05f23961d2b443972f4aa3c2bec29, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Basketbal image: {fileID: 21300000, guid: 156e4253c2ba9744299120c4f7a4907f, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Boksen image: {fileID: 21300000, guid: 0eaa7dbb8a13329469c554438883ca0f, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Golf image: {fileID: 21300000, guid: ec1678139fcc5074b95a3a965bfa6821, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Gymnastiek image: {fileID: 21300000, guid: 1281c25012472ec4d84478d6818f19f0, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Hockey image: {fileID: 21300000, guid: 301dde71aeaf59b479bc2c0913e3c80c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Judo image: {fileID: 21300000, guid: 6d71e06f1b883ef4abf104860419498a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Paardrijden image: {fileID: 21300000, guid: 1ec2db5d415d74349b19ed061b738b68, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Roeien image: {fileID: 21300000, guid: 8bf794ec6b135bb4485887a09ed97534, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Schaatsen image: {fileID: 21300000, guid: 733ff2209581a2442808d259fb6a0431, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Tennis image: {fileID: 21300000, guid: 881ef1ba222af1447b9690404d30c252, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Voetbal image: {fileID: 21300000, guid: 58490254216a52b40b0c438f544a6f0f, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Volleybal image: {fileID: 21300000, guid: b0564e1d65736cb4d875b7db5b934ea6, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Wielrennen image: {fileID: 21300000, guid: 6de1a4e2d8ac7e04b928c700e3164ba3, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Zeilen image: {fileID: 21300000, guid: 1794b47dd6219cb458a057dcddee11a0, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Zwemmen image: {fileID: 21300000, guid: 3543c100b40bc7043a7413860dcb625a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingThemeList.asset b/Assets/Common/ScriptableObjects/SpellingThemeList.asset index e183bb5..b1eb7ed 100644 --- a/Assets/Common/ScriptableObjects/SpellingThemeList.asset +++ b/Assets/Common/ScriptableObjects/SpellingThemeList.asset @@ -22,5 +22,4 @@ MonoBehaviour: - {fileID: 11400000, guid: 16c8d2819a07e3142a431b116601954d, type: 2} - {fileID: 11400000, guid: 0a0b1b81e0de10b47bb08fb226b89432, type: 2} - {fileID: 11400000, guid: 80b0a5e4c64e9724ba647e727535c4d5, type: 2} - - {fileID: 11400000, guid: 80b0a5e4c64e9724ba647e727535c4d5, type: 2} - {fileID: 11400000, guid: 11ae933ede5acd14398efb8dd2549527, type: 2} diff --git a/Assets/Common/ScriptableObjects/SpellingVeggies.asset b/Assets/Common/ScriptableObjects/SpellingVeggies.asset index 84923d9..617fae1 100644 --- a/Assets/Common/ScriptableObjects/SpellingVeggies.asset +++ b/Assets/Common/ScriptableObjects/SpellingVeggies.asset @@ -14,48 +14,76 @@ MonoBehaviour: m_EditorClassIdentifier: title: Groenten description: Van erwt tot komkommer - index: 14 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 14 + modelIndex: 1 learnables: - name: Aardappel image: {fileID: 21300000, guid: 2610cdbc24a125f43ada7fed67d8f51b, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Ajuin image: {fileID: 21300000, guid: b1581340c7eea4448835492296442cba, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Bloemkool image: {fileID: 21300000, guid: 487940208ac3a0d4bb41696e11e9f8e7, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Bonen image: {fileID: 21300000, guid: ad47c02ff85e06948b9f73cae6eb0221, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Broccoli image: {fileID: 21300000, guid: b76404afa08793f4391e71078bed6be7, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Champignon image: {fileID: 21300000, guid: 6a89fa1b42445d6459752b97fc755470, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Erwt image: {fileID: 21300000, guid: d5d61528ca4d25e448c0435975e2a193, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Komkommer image: {fileID: 21300000, guid: affe34960b38b8f4b95f3eeb8b10c795, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Kool image: {fileID: 21300000, guid: 71ba9e10934004c4984f0a4900c2bfa6, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Mais image: {fileID: 21300000, guid: 46d05a2c28542224682bfda441d8af08, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Paprika image: {fileID: 21300000, guid: f62dbfe5d956caa48a05ae470b2afbcd, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Pompoen image: {fileID: 21300000, guid: 4ea79b62a6cb15345959144622dc9f43, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Prei image: {fileID: 21300000, guid: c2fe2cad9d48a784980823528889af18, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Wortel image: {fileID: 21300000, guid: 8962e03659a079546810c3ad9c8a211c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/ScriptableObjects/SpellingWild.asset b/Assets/Common/ScriptableObjects/SpellingWild.asset index 4848035..348dc9c 100644 --- a/Assets/Common/ScriptableObjects/SpellingWild.asset +++ b/Assets/Common/ScriptableObjects/SpellingWild.asset @@ -14,54 +14,86 @@ MonoBehaviour: m_EditorClassIdentifier: title: Dieren in het wild description: Van Leeuw tot olifant - index: 15 - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + themeIndex: 15 + modelIndex: 1 learnables: - name: Vos image: {fileID: 21300000, guid: 9d5771baa6ea6e041b066135d6798e1c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Tijger image: {fileID: 21300000, guid: 83d6525e4efa4954091e08095349f45a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Lynx image: {fileID: 21300000, guid: d34fe3b6e07e66142a8ce4cf20814b8a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Wolf image: {fileID: 21300000, guid: 8c304fe460423214ea0bb6ebc235ed2d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Giraf image: {fileID: 21300000, guid: 0cc198f1cde659246a199b30459720b1, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Leeuw image: {fileID: 21300000, guid: f989719a5c45c7a4183b2bc12c1c4905, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Dolfijn image: {fileID: 21300000, guid: 4654657a2ebea444898fa6eeaefcd18d, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Walvis image: {fileID: 21300000, guid: 2b01165a5836ab14593d7a5862bd6793, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Haai image: {fileID: 21300000, guid: 313c22e5834595645989d609fe9d8853, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Hert image: {fileID: 21300000, guid: e5f3d99cdf5298d4f86d42dd019a6bad, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Olifant image: {fileID: 21300000, guid: 1392922567cd59d4fb0beceea3f5917a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Kangoeroe image: {fileID: 21300000, guid: e4af402f37099cd4195d7d2654519744, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Panda image: {fileID: 21300000, guid: 33509e453b5093e43a148a668a961c56, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Slang image: {fileID: 21300000, guid: eefb367ff44256d43a14cde2c3924321, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Zebra image: {fileID: 21300000, guid: b203b4e5f8568ff46b2277ce6d61017a, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} - name: Aap image: {fileID: 21300000, guid: 6feaaea4b64633f49b4538bfd4b3755c, type: 3} + handGuide: {fileID: 0} + thresholdPrecentage: 0.9 clip: {fileID: 0} diff --git a/Assets/Common/Scripts/BootScreen.cs b/Assets/Common/Scripts/BootScreen.cs index ef66015..b1a7c71 100644 --- a/Assets/Common/Scripts/BootScreen.cs +++ b/Assets/Common/Scripts/BootScreen.cs @@ -12,12 +12,20 @@ public class BootScreen : MonoBehaviour /// public TMP_Text errorText; + /// + /// Reference to the list that holds all user avatars + /// + public UserAvatarList sprites; + /// /// Request authorization and check whether at least 1 webcam is available /// /// IEnumerator object IEnumerator Start() { + UserList.AVATARS = sprites.avatars; + PersistentDataController.GetInstance().Load(); + yield return Application.RequestUserAuthorization(UserAuthorization.WebCam); if (Application.HasUserAuthorization(UserAuthorization.WebCam)) { diff --git a/Assets/Common/Scripts/CommonScripts.asmdef b/Assets/Common/Scripts/CommonScripts.asmdef index 8b1a1ba..d6a3630 100644 --- a/Assets/Common/Scripts/CommonScripts.asmdef +++ b/Assets/Common/Scripts/CommonScripts.asmdef @@ -5,7 +5,7 @@ "GUID:6055be8ebefd69e48b49212b09b47b2f", "GUID:63c63e721f65ebb7d871cb9ef49f4752", "GUID:1631ed2680c61245b8211d943c1639a8", - "GUID:5c2b5ba89f9e74e418232e154bc5cc7a", + "GUID:e83ddf9a537a96b4a804a16bb7872ec1", "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25" ], "includePlatforms": [], diff --git a/Assets/Common/Scripts/CourseActivityScreen.cs b/Assets/Common/Scripts/CourseActivityScreen.cs index ab0cdb4..c589316 100644 --- a/Assets/Common/Scripts/CourseActivityScreen.cs +++ b/Assets/Common/Scripts/CourseActivityScreen.cs @@ -1,5 +1,6 @@ using TMPro; using UnityEngine; +using UnityEngine.Playables; using UnityEngine.UI; /// @@ -12,20 +13,16 @@ public class CourseActivityScreen : MonoBehaviour public GameObject previewButton; // ^^^ TEMPORARY STUFF ^^^ + public GameObject restartButton; /// /// Reference to the courses /// public CourseList courseList; - /// - /// Reference to the users - /// - public UserList userList; - /// /// Reference to the course progress /// - private Progress progress; + private PersistentDataController.SavedCourseProgress progress; /// /// Title Display @@ -42,11 +39,27 @@ public class CourseActivityScreen : MonoBehaviour /// public Image courseImage; + /// /// Progress bar Display /// public Slider progressBar; + /// + /// Reference to the progressBar gameObject + /// + public GameObject progressObject; + + /// + /// Reference to the 'completed' gameObject + /// + public GameObject completedObject; + + /// + /// Reference to the scene playable director + /// + public PlayableDirector directorEnterFromCourseMenu; + /// /// Sets the infopage for a given course /// @@ -56,8 +69,8 @@ public class CourseActivityScreen : MonoBehaviour Course course = courseList.courses[index]; // vvv TEMPORARY STUFF vvv - playButton.SetActive(course.theme.model != null); - previewButton.SetActive(course.theme.model == null); + playButton.SetActive(course.theme.modelIndex != ModelIndex.NONE); + previewButton.SetActive(course.theme.modelIndex == ModelIndex.NONE); // ^^^ TEMPORARY STUFF ^^^ title.text = course.title; @@ -66,12 +79,48 @@ public class CourseActivityScreen : MonoBehaviour //slider.value = progressValue; // Set progress - userList.Load(); - progress = userList.GetCurrentUser().GetCourseProgress(course.index); - if (progress != null) - progressBar.value = progress.Get("courseProgress"); + PersistentDataController.GetInstance().Load(); + progress = UserList.GetCurrentUser().GetCourseProgress(course.index); + if (progress != null && course.theme.modelIndex != ModelIndex.NONE) + { + progressBar.value = progress.progress; + if (progress.progress == 1.0f) + { + playButton.SetActive(false); + progressObject.SetActive(false); + completedObject.SetActive(true); + } + if (progress.inUseLearnables > 0) + { + restartButton.SetActive(true); + playButton.transform.Find("Button Text").GetComponent().text = "Verder"; + } + else + { + restartButton.SetActive(false); + } + } else + { progressBar.value = 0.0f; + restartButton.SetActive(false); + playButton.transform.Find("Button Text").GetComponent().text = "Begin"; + } + + var sys = SystemController.GetInstance(); + if (sys.previousScene == SystemController.GetSceneIndex("Common/Scenes/CoursesMenuScreen")) + directorEnterFromCourseMenu.Play(); + } + + /// + /// Callback to reset and start the course + /// + public void ResetCourseProgress() + { + UserList.GetCurrentUser().ResetCourseProgress(progress.courseIndex); + UserList.Save(); + progressBar.value = 0.0f; + StartCourse(); } /// @@ -79,6 +128,6 @@ public class CourseActivityScreen : MonoBehaviour /// public void StartCourse() { - SystemController.GetInstance().LoadNextScene("Courses/Scenes/TemplateCourse"); + SystemController.GetInstance().LoadNextScene("Courses/Scenes/CourseScreen"); } } diff --git a/Assets/Common/Scripts/CourseItem.cs b/Assets/Common/Scripts/CourseItem.cs index ac6d5b2..c23625b 100644 --- a/Assets/Common/Scripts/CourseItem.cs +++ b/Assets/Common/Scripts/CourseItem.cs @@ -69,7 +69,7 @@ public class CourseItem : MonoBehaviour progress = Mathf.Clamp01(progress); completed.SetActive(1.0f <= progress); slider.SetActive(0.0f <= progress && progress < 1.0f); - slider.GetComponent().value = progress; + slider.GetComponent().fillAmount = progress; // Add click functionality button.onClick.AddListener(() => diff --git a/Assets/Common/Scripts/CourseMenuScreen.cs b/Assets/Common/Scripts/CourseMenuScreen.cs index ef56303..02e1249 100644 --- a/Assets/Common/Scripts/CourseMenuScreen.cs +++ b/Assets/Common/Scripts/CourseMenuScreen.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using UnityEngine; +using UnityEngine.Playables; /// /// CourseMenuScreen scene manager @@ -27,23 +28,28 @@ public class CourseMenuScreen : MonoBehaviour /// public GameObject courseItem; - /// - /// Reference to the users so we can get the current user; - /// - public UserList userList; - /// /// Reference to the courses /// public CourseList courseList; + /// + /// Reference to the scene playable director + /// + public PlayableDirector directorEnterFromDefault; + + /// + /// Reference to the scene playable director + /// + public PlayableDirector directorEnterFromMainMenu; + /// /// Start is called before the first frame update /// void Start() { - userList.Load(); - User user = userList.GetCurrentUser(); + PersistentDataController.GetInstance().Load(); + User user = UserList.GetCurrentUser(); // Recent courses List> recentCourses = user.GetRecentCourses(); @@ -71,6 +77,13 @@ public class CourseMenuScreen : MonoBehaviour item.course = courseList.GetCourseByIndex(course.Item1); item.progress = course.Item2; } + + var sys = SystemController.GetInstance(); + if (sys.previousScene == SystemController.GetSceneIndex("Common/Scenes/MainMenuScreen")) + directorEnterFromMainMenu.Play(); + else + directorEnterFromDefault.Play(); + } /// diff --git a/Assets/Common/Scripts/ListCoursesScreen.cs b/Assets/Common/Scripts/ListCoursesScreen.cs index 7628ecf..d91a438 100644 --- a/Assets/Common/Scripts/ListCoursesScreen.cs +++ b/Assets/Common/Scripts/ListCoursesScreen.cs @@ -1,15 +1,11 @@ using UnityEngine; +using UnityEngine.Playables; /// /// ListCourseScreen scene manager /// public class ListCoursesScreen : MonoBehaviour { - /// - /// Reference to the userlist - /// - public UserList userList; - /// /// Reference to the course-list container object /// @@ -25,13 +21,18 @@ public class ListCoursesScreen : MonoBehaviour /// public CourseList courseList; + /// + /// Reference to the scene playable director + /// + public PlayableDirector directorEnterFromCourseMenu; + /// /// Start is called before the first frame update /// void Start() { - userList.Load(); - User user = userList.GetCurrentUser(); + PersistentDataController.GetInstance().Load(); + User user = UserList.GetCurrentUser(); foreach (Course course in courseList.courses) { @@ -42,9 +43,13 @@ public class ListCoursesScreen : MonoBehaviour CourseItem item = instance.GetComponent(); item.course = course; - Progress progress = user.GetCourseProgress(course.index); - item.progress = progress != null ? progress.Get("courseProgress") : 0.0f; + var progress = user.GetCourseProgress(course.index); + item.progress = progress != null ? progress.progress : 0.0f; } + + var sys = SystemController.GetInstance(); + if (sys.previousScene == SystemController.GetSceneIndex("Common/Scenes/CoursesMenuScreen")) + directorEnterFromCourseMenu.Play(); } /// diff --git a/Assets/Common/Scripts/ListMinigamesScreen.cs b/Assets/Common/Scripts/ListMinigamesScreen.cs index 613d674..7fdfa74 100644 --- a/Assets/Common/Scripts/ListMinigamesScreen.cs +++ b/Assets/Common/Scripts/ListMinigamesScreen.cs @@ -1,4 +1,5 @@ using UnityEngine; +using UnityEngine.Playables; /// /// ListMinigameScreen scene manager @@ -20,6 +21,11 @@ public class ListMinigamesScreen : MonoBehaviour /// public MinigameList minigameList; + /// + /// Reference to the scene playable director + /// + public PlayableDirector directorEnterFromMainMenu; + /// /// Start is called before the first frame update /// @@ -34,6 +40,10 @@ public class ListMinigamesScreen : MonoBehaviour MinigameItem item = instance.GetComponent(); item.minigame = minigame; } + + var sys = SystemController.GetInstance(); + if (sys.previousScene == SystemController.GetSceneIndex("Common/Scenes/MainMenuScreen")) + directorEnterFromMainMenu.Play(); } /// diff --git a/Assets/Common/Scripts/MainMenuScreen.cs b/Assets/Common/Scripts/MainMenuScreen.cs index d4f7382..cfc4e6d 100644 --- a/Assets/Common/Scripts/MainMenuScreen.cs +++ b/Assets/Common/Scripts/MainMenuScreen.cs @@ -1,5 +1,6 @@ using System.IO; using UnityEngine; +using UnityEngine.Playables; /// /// StartScreen scene manager @@ -7,9 +8,24 @@ using UnityEngine; public class MainMenuScreen : MonoBehaviour { /// - /// Referece to the userlist to check whether an user account is present + /// Reference to the enter animation scene playable director /// - public UserList userList; + public PlayableDirector directorEnterFromBoot; + + /// + /// Reference to the enter animation scene playable director + /// + public PlayableDirector directorEnterFromCourseMenu; + + /// + /// Reference to the enter animation scene playable director + /// + public PlayableDirector directorEnterFromListMinigames; + + /// + /// Reference to the enter animation scene playable director + /// + public PlayableDirector directorEnterFromSettings; /// /// Check on load whether a user is already present, @@ -17,13 +33,29 @@ public class MainMenuScreen : MonoBehaviour /// void Awake() { - userList.Load(); - if (!File.Exists(UserList.PATH) || userList.GetUsers().Count <= 0) + if (!File.Exists(PersistentDataController.PATH) || UserList.GetUsers().Count <= 0) { + UserCreationScreen.canGoBack = false; SystemController.GetInstance().LoadNextScene("Accounts/Scenes/UserCreationScreen"); } } + /// + /// Start is called before the first frame update + /// + void Start() + { + var sys = SystemController.GetInstance(); + if (sys.previousScene == SystemController.GetSceneIndex("Common/Scenes/Boot")) + directorEnterFromBoot.Play(); + else if (sys.previousScene == SystemController.GetSceneIndex("Common/Scenes/CoursesMenuScreen")) + directorEnterFromCourseMenu.Play(); + else if (sys.previousScene == SystemController.GetSceneIndex("Common/Scenes/ListMinigamesScreen")) + directorEnterFromListMinigames.Play(); + else if (sys.previousScene == SystemController.GetSceneIndex("Common/Scenes/SettingsScreen")) + directorEnterFromSettings.Play(); + } + /// /// Quit the application /// diff --git a/Assets/Common/Scripts/MinigameActivityScreen.cs b/Assets/Common/Scripts/MinigameActivityScreen.cs index 46dc2ba..ce3da48 100644 --- a/Assets/Common/Scripts/MinigameActivityScreen.cs +++ b/Assets/Common/Scripts/MinigameActivityScreen.cs @@ -40,15 +40,10 @@ public class MinigameActivityScreen : MonoBehaviour /// public TMP_Text controls; - /// - /// Reference to the users - /// - public UserList userList; - /// /// Reference to the Minigame progress /// - private Progress progress; + private PersistentDataController.SavedMinigameProgress progress; /// /// Reference to the users-high-scores container object @@ -60,12 +55,17 @@ public class MinigameActivityScreen : MonoBehaviour /// public GameObject prefab; + /// + /// Reference to the ranking title + /// + public GameObject rankingTitle; + /// /// Sets the infopage for a given minigame /// void Start() { - userList.Load(); + PersistentDataController.GetInstance().Load(); GenerateContent(); GenerateHighScores(); } @@ -109,21 +109,23 @@ public class MinigameActivityScreen : MonoBehaviour Minigame minigame = minigameList.minigames[index]; List> allScores = new List>(); - foreach (User user in userList.GetUsers()) + foreach (User user in UserList.GetUsers()) { // Get user's progress for this minigame progress = user.GetMinigameProgress(minigame.index); if (progress != null) { // Add scores to dictionary - List scores = progress.Get>("highestScores"); + List scores = progress.highestScores; foreach (Score score in scores) { - allScores.Add(new Tuple(user.username, user.avatar, score)); + allScores.Add(new Tuple(user.GetUsername(), user.GetAvatar(), score)); } } } + rankingTitle.SetActive(allScores.Count > 0); + // Sort allScores based on Score.scoreValue allScores.Sort((a, b) => b.Item3.scoreValue.CompareTo(a.Item3.scoreValue)); diff --git a/Assets/Common/Scripts/SettingsScreen.cs b/Assets/Common/Scripts/SettingsScreen.cs new file mode 100644 index 0000000..07189b3 --- /dev/null +++ b/Assets/Common/Scripts/SettingsScreen.cs @@ -0,0 +1,18 @@ +using UnityEngine; +using UnityEngine.Playables; + +public class SettingsScreen : MonoBehaviour +{ + /// + /// Reference to the scene playable director + /// + public PlayableDirector directorEnterFromMainMenu; + + /// + /// Start is called before the first frame update + /// + void Start() + { + directorEnterFromMainMenu.Play(); + } +} diff --git a/Assets/Hangman/Scripts/HangmanImages.cs.meta b/Assets/Common/Scripts/SettingsScreen.cs.meta similarity index 83% rename from Assets/Hangman/Scripts/HangmanImages.cs.meta rename to Assets/Common/Scripts/SettingsScreen.cs.meta index 1f1643e..d5b20ac 100644 --- a/Assets/Hangman/Scripts/HangmanImages.cs.meta +++ b/Assets/Common/Scripts/SettingsScreen.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d9c124cfcaadaf040b00ede50b1b022c +guid: c206227bcf352fd4784750b5b2b19a31 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Common/Scripts/ThemeItem.cs b/Assets/Common/Scripts/ThemeItem.cs index 157c4c4..b448446 100644 --- a/Assets/Common/Scripts/ThemeItem.cs +++ b/Assets/Common/Scripts/ThemeItem.cs @@ -59,7 +59,7 @@ public class ThemeItem : MonoBehaviour { //PlayerPrefs.SetString("gamePath", minigame.minigameEntryPoint); Minigame minigame = minigameList.minigames[minigameList.currentMinigameIndex]; - minigame.themeList.SetCurrentTheme(theme.index); + minigame.themeList.SetCurrentTheme(theme.themeIndex); SystemController.GetInstance().SwapScene(minigame.minigameEntryPoint); }); } diff --git a/Assets/Common/Scripts/UserButton.cs b/Assets/Common/Scripts/UserButton.cs index 5fa77e5..ee25a5e 100644 --- a/Assets/Common/Scripts/UserButton.cs +++ b/Assets/Common/Scripts/UserButton.cs @@ -7,11 +7,6 @@ using UnityEngine.UI; /// public class UserButton : MonoBehaviour { - /// - /// Reference to the user list, so we can extract the current user - /// - public UserList userList; - /// /// UI reference to the avatar object /// @@ -32,10 +27,10 @@ public class UserButton : MonoBehaviour /// void Start() { - userList.Load(); - User user = userList.GetCurrentUser(); - avatar.sprite = user.avatar; - username.text = user.username; + PersistentDataController.GetInstance().Load(); + User user = UserList.GetCurrentUser(); + avatar.sprite = user.GetAvatar(); + username.text = user.GetUsername(); dropdownBox.SetActive(false); } diff --git a/Assets/Common/Tests/CommonTests.asmdef b/Assets/Common/Tests/CommonTests.asmdef index aaa7ab0..a568a8e 100644 --- a/Assets/Common/Tests/CommonTests.asmdef +++ b/Assets/Common/Tests/CommonTests.asmdef @@ -5,7 +5,10 @@ "UnityEngine.TestRunner", "UnityEditor.TestRunner", "CommonScripts", - "InterfacesScripts" + "InterfacesScripts", + "SignPredictor", + "NatML.ML", + "ArchitectureScripts" ], "includePlatforms": [ "Editor" diff --git a/Assets/Common/Tests/ModelListTest.cs b/Assets/Common/Tests/ModelListTest.cs new file mode 100644 index 0000000..bc1f44d --- /dev/null +++ b/Assets/Common/Tests/ModelListTest.cs @@ -0,0 +1,88 @@ +using NatML; +using NUnit.Framework; +using UnityEngine; +/// +/// Test the ModelList class +/// +[TestFixture] +public class ModelListTest +{ + private ModelList modelList; + + /// + /// Setup a ModelList with all possible Models in the enum + /// + [SetUp] + public void Setup_Model() + { + modelList = ScriptableObject.CreateInstance(); + + // Add a Model for each index in the enum + + // Dumb way to access each index in the enum, couldn't find a different way to do it though + foreach (var field in typeof(ModelIndex).GetFields()) + { + if (field.IsLiteral) + { + ModelIndex value = (ModelIndex)field.GetValue(null); + string name = field.Name; + ModelList.ModelTuple model = new ModelList.ModelTuple(); + // This is all we will need to distinguish + model.index = value; + + // Insert in front to guarantee that ModelIndex will not line up with listIndex + modelList.models.Insert(0, model); + } + } + } + /// + /// Check if current model can be correctly gotten as current via GetCurrentModel + /// + [Test] + public void TestGetCurrentModel() + { + System.Random random = new System.Random(); + ModelIndex value = (ModelIndex)random.Next(modelList.models.Count); + modelList.SetCurrentModel(value); + +#if (UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN) + Assert.AreEqual(modelList.models[modelList.currentModelIndex].modelWINDOWS, modelList.GetCurrentModel()); +#elif (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX) + Assert.AreEqual(modelList.models[modelList.currentModelIndex].modelMAC, modelList.GetCurrentModel()); +#endif + + // Check if empty model fails gracefully (returns null) + Assert.IsNull(ScriptableObject.CreateInstance().GetCurrentModel()); + } + + /// + /// Check if all models can be correctly set as current via SetCurrentModel + /// + [Test] + public void TestSetCurrentModel() + { + foreach (var field in typeof(ModelIndex).GetFields()) + { + if (field.IsLiteral) + { + ModelIndex value = (ModelIndex)field.GetValue(null); + string name = field.Name; + modelList.SetCurrentModel(value); + + // Fetch the current model and check if its name is the same as the one we made into the current one + ModelList.ModelTuple m = modelList.models[modelList.currentModelIndex]; + + Assert.AreEqual(m.index, value); +#if (UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN) + Assert.IsTrue(m.modelWINDOWS is MLModelData || m.modelWINDOWS is null); +#elif (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX) + Assert.IsTrue(m.modelMAC is MLModelData || m.modelMAC is null); +#endif + } + } + ModelList emptyList = ScriptableObject.CreateInstance(); + emptyList.SetCurrentModel(ModelIndex.FINGERSPELLING); + + Assert.IsTrue(emptyList.currentModelIndex == -1); + } +} diff --git a/Assets/Common/Tests/ModelListTest.cs.meta b/Assets/Common/Tests/ModelListTest.cs.meta new file mode 100644 index 0000000..85cdfd3 --- /dev/null +++ b/Assets/Common/Tests/ModelListTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1313e0cc80244354eb6e2d0c1e891941 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Tests/ThemeListTest.cs b/Assets/Common/Tests/ThemeListTest.cs index f316212..6a34fe1 100644 --- a/Assets/Common/Tests/ThemeListTest.cs +++ b/Assets/Common/Tests/ThemeListTest.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using UnityEngine; + /// /// Test the ThemeList class /// @@ -27,7 +28,7 @@ public class ThemeListTest string name = field.Name; Theme theme = ScriptableObject.CreateInstance(); // This is all we will need to distinguish - theme.index = value; + theme.themeIndex = value; theme.title = name; // Insert in front to guarantee that themeIndex will not line up with listIndex diff --git a/Assets/Common/Tests/ThemeTest.cs b/Assets/Common/Tests/ThemeTest.cs index e6db61f..a93d7e4 100644 --- a/Assets/Common/Tests/ThemeTest.cs +++ b/Assets/Common/Tests/ThemeTest.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using System.Collections.Generic; using UnityEngine; + /// /// Test the Theme class /// diff --git a/Assets/Common/Videos/Alphabet/ALFABET_A.mp4 b/Assets/Common/Videos/Alphabet/ALFABET_A.mp4 index d9e8690..de22b37 100644 Binary files a/Assets/Common/Videos/Alphabet/ALFABET_A.mp4 and b/Assets/Common/Videos/Alphabet/ALFABET_A.mp4 differ diff --git a/Assets/Common/Videos/Alphabet/ALFABET_P.mp4 b/Assets/Common/Videos/Alphabet/ALFABET_P.mp4 index 16fa3cc..8b3a925 100644 Binary files a/Assets/Common/Videos/Alphabet/ALFABET_P.mp4 and b/Assets/Common/Videos/Alphabet/ALFABET_P.mp4 differ diff --git a/Assets/Common/Videos/Alphabet/ALFABET_W.mp4 b/Assets/Common/Videos/Alphabet/ALFABET_W.mp4 index 5b2b7d8..54f120b 100644 Binary files a/Assets/Common/Videos/Alphabet/ALFABET_W.mp4 and b/Assets/Common/Videos/Alphabet/ALFABET_W.mp4 differ diff --git a/Assets/Common/Videos/Alphabet/ALFABET_X.mp4 b/Assets/Common/Videos/Alphabet/ALFABET_X.mp4 index be8c212..8b31434 100644 Binary files a/Assets/Common/Videos/Alphabet/ALFABET_X.mp4 and b/Assets/Common/Videos/Alphabet/ALFABET_X.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns.meta b/Assets/Common/Videos/BasicSigns.meta new file mode 100644 index 0000000..1800281 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b540d811a56827e4381cd6cec809e747 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/BEDANKEN-A-1036.mp4 b/Assets/Common/Videos/BasicSigns/BEDANKEN-A-1036.mp4 new file mode 100644 index 0000000..5198216 Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/BEDANKEN-A-1036.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/BEDANKEN-A-1036.mp4.meta b/Assets/Common/Videos/BasicSigns/BEDANKEN-A-1036.mp4.meta new file mode 100644 index 0000000..1b64670 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/BEDANKEN-A-1036.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ea0208d218c503b42ba7c0b819127344 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/GOED-C-4413.mp4 b/Assets/Common/Videos/BasicSigns/GOED-C-4413.mp4 new file mode 100644 index 0000000..2fe46ba Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/GOED-C-4413.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/GOED-C-4413.mp4.meta b/Assets/Common/Videos/BasicSigns/GOED-C-4413.mp4.meta new file mode 100644 index 0000000..a5c01e4 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/GOED-C-4413.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f9af6f8ba451f9045bb13cb87b5b2945 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/GOEDEMIDDAG-A-14937.mp4 b/Assets/Common/Videos/BasicSigns/GOEDEMIDDAG-A-14937.mp4 new file mode 100644 index 0000000..b5124d4 Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/GOEDEMIDDAG-A-14937.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/GOEDEMIDDAG-A-14937.mp4.meta b/Assets/Common/Videos/BasicSigns/GOEDEMIDDAG-A-14937.mp4.meta new file mode 100644 index 0000000..484cbcf --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/GOEDEMIDDAG-A-14937.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 07593101fbf5f5b48a6081618c359d43 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/GOEDEMORGEN-B-14939.mp4 b/Assets/Common/Videos/BasicSigns/GOEDEMORGEN-B-14939.mp4 new file mode 100644 index 0000000..16ffb68 Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/GOEDEMORGEN-B-14939.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/GOEDEMORGEN-B-14939.mp4.meta b/Assets/Common/Videos/BasicSigns/GOEDEMORGEN-B-14939.mp4.meta new file mode 100644 index 0000000..8238252 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/GOEDEMORGEN-B-14939.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 088520ac18815d249a627b939d919b87 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/GOEDENACHT-A-14940.mp4 b/Assets/Common/Videos/BasicSigns/GOEDENACHT-A-14940.mp4 new file mode 100644 index 0000000..121290f Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/GOEDENACHT-A-14940.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/GOEDENACHT-A-14940.mp4.meta b/Assets/Common/Videos/BasicSigns/GOEDENACHT-A-14940.mp4.meta new file mode 100644 index 0000000..08fa0be --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/GOEDENACHT-A-14940.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4d6c8346776deb7449acf087232e640a +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/GOEDENAVOND-B-14951.mp4 b/Assets/Common/Videos/BasicSigns/GOEDENAVOND-B-14951.mp4 new file mode 100644 index 0000000..f5198ad Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/GOEDENAVOND-B-14951.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/GOEDENAVOND-B-14951.mp4.meta b/Assets/Common/Videos/BasicSigns/GOEDENAVOND-B-14951.mp4.meta new file mode 100644 index 0000000..131aef4 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/GOEDENAVOND-B-14951.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5b201af7cea977c4c9bfac53553d4351 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/JA-A-5464.mp4 b/Assets/Common/Videos/BasicSigns/JA-A-5464.mp4 new file mode 100644 index 0000000..4de1c39 Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/JA-A-5464.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/JA-A-5464.mp4.meta b/Assets/Common/Videos/BasicSigns/JA-A-5464.mp4.meta new file mode 100644 index 0000000..019bce7 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/JA-A-5464.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d514b6143c06749489a4a727a10913f0 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/LINKS-A-6911.mp4 b/Assets/Common/Videos/BasicSigns/LINKS-A-6911.mp4 new file mode 100644 index 0000000..bb167da Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/LINKS-A-6911.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/LINKS-A-6911.mp4.meta b/Assets/Common/Videos/BasicSigns/LINKS-A-6911.mp4.meta new file mode 100644 index 0000000..4ed6d11 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/LINKS-A-6911.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d3417d06c92c99d4aab3f370be7430d8 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/NEE-A-15049.mp4 b/Assets/Common/Videos/BasicSigns/NEE-A-15049.mp4 new file mode 100644 index 0000000..b269b5a Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/NEE-A-15049.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/NEE-A-15049.mp4.meta b/Assets/Common/Videos/BasicSigns/NEE-A-15049.mp4.meta new file mode 100644 index 0000000..bfdcb5a --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/NEE-A-15049.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c869292eee244624589e5bfbdd43bb09 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/RECHTS-A-9803.mp4 b/Assets/Common/Videos/BasicSigns/RECHTS-A-9803.mp4 new file mode 100644 index 0000000..d704036 Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/RECHTS-A-9803.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/RECHTS-A-9803.mp4.meta b/Assets/Common/Videos/BasicSigns/RECHTS-A-9803.mp4.meta new file mode 100644 index 0000000..702b619 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/RECHTS-A-9803.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 51936adbe64aee644b81a10958ceba9e +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/SALUUT-A-10284.mp4 b/Assets/Common/Videos/BasicSigns/SALUUT-A-10284.mp4 new file mode 100644 index 0000000..4b8d9db Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/SALUUT-A-10284.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/SALUUT-A-10284.mp4.meta b/Assets/Common/Videos/BasicSigns/SALUUT-A-10284.mp4.meta new file mode 100644 index 0000000..5bf5c9d --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/SALUUT-A-10284.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b3ffa09a793bc8742b894a0d90945739 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/SLECHT-D-10928.mp4 b/Assets/Common/Videos/BasicSigns/SLECHT-D-10928.mp4 new file mode 100644 index 0000000..9e1ac4e Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/SLECHT-D-10928.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/SLECHT-D-10928.mp4.meta b/Assets/Common/Videos/BasicSigns/SLECHT-D-10928.mp4.meta new file mode 100644 index 0000000..f7b5a60 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/SLECHT-D-10928.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e552e225d0f46964ea9ee79070e9f03c +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/SMAKELIJK-A-10984.mp4 b/Assets/Common/Videos/BasicSigns/SMAKELIJK-A-10984.mp4 new file mode 100644 index 0000000..a760608 Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/SMAKELIJK-A-10984.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/SMAKELIJK-A-10984.mp4.meta b/Assets/Common/Videos/BasicSigns/SMAKELIJK-A-10984.mp4.meta new file mode 100644 index 0000000..f9d7835 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/SMAKELIJK-A-10984.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 436159822cb53bc4b8d1bcbf83d109ce +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/SORRY-A-11113.mp4 b/Assets/Common/Videos/BasicSigns/SORRY-A-11113.mp4 new file mode 100644 index 0000000..87a5fba Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/SORRY-A-11113.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/SORRY-A-11113.mp4.meta b/Assets/Common/Videos/BasicSigns/SORRY-A-11113.mp4.meta new file mode 100644 index 0000000..2c72d85 --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/SORRY-A-11113.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d53e61ab6d142164c94776d4ea62edb7 +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Videos/BasicSigns/TOT-ZIENS-A-12142.mp4 b/Assets/Common/Videos/BasicSigns/TOT-ZIENS-A-12142.mp4 new file mode 100644 index 0000000..7b2a57f Binary files /dev/null and b/Assets/Common/Videos/BasicSigns/TOT-ZIENS-A-12142.mp4 differ diff --git a/Assets/Common/Videos/BasicSigns/TOT-ZIENS-A-12142.mp4.meta b/Assets/Common/Videos/BasicSigns/TOT-ZIENS-A-12142.mp4.meta new file mode 100644 index 0000000..4afd4ed --- /dev/null +++ b/Assets/Common/Videos/BasicSigns/TOT-ZIENS-A-12142.mp4.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 199075a9c3138354db43569bade8faaa +VideoClipImporter: + externalObjects: {} + serializedVersion: 2 + frameRange: 0 + startFrame: -1 + endFrame: -1 + colorSpace: 0 + deinterlace: 0 + encodeAlpha: 0 + flipVertical: 0 + flipHorizontal: 0 + importAudio: 1 + targetSettings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Animations.meta b/Assets/Courses/Animations.meta new file mode 100644 index 0000000..48b9fa8 --- /dev/null +++ b/Assets/Courses/Animations.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22b79b4c5a84f584b9a6eb9508e89d5f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Animations/Confetti.anim b/Assets/Courses/Animations/Confetti.anim new file mode 100644 index 0000000..a6e5cef --- /dev/null +++ b/Assets/Courses/Animations/Confetti.anim @@ -0,0 +1,2213 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Confetti + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 650 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.16666667 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6666667 + value: 250 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sparkle (1) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.16666667 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6666667 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sparkle (1) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.16666667 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6666667 + value: -150 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sparkle (2) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.16666667 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6666667 + value: 800 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sparkle (2) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.33333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 350 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sparkle (3) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.33333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 500 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sparkle (3) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.33333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: -350 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sparkle (4) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.33333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 600 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sparkle (4) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sparkle (4) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sparkle (3) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.6666667 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sparkle (2) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.6666667 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sparkle (1) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 120 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (1) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 457 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (1) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (1) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: -225 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (2) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 654 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (2) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (2) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: -138 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (3) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 475 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (3) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (3) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 199 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (4) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 600 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (4) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (4) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 206 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (5) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 759 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (5) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (5) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 33 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (6) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 833 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (6) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (6) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_PPtrCurves: [] + m_SampleRate: 6 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 83635035 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 83635035 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3682788113 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3682788113 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 4038045906 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 4038045906 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3920920979 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3920920979 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2801080148 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2801080148 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2801080148 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3920920979 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 4038045906 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3682788113 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3005333927 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3005333927 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3005333927 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2550960740 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2550960740 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2550960740 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2165809957 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2165809957 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 2165809957 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3461756386 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3461756386 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3461756386 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3612148899 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3612148899 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 3612148899 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 4234172256 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 4234172256 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + - serializedVersion: 2 + path: 4234172256 + attribute: 304273561 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1.1666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 650 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.16666667 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6666667 + value: 250 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sparkle (1) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.16666667 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6666667 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sparkle (1) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.16666667 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6666667 + value: -150 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sparkle (2) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.16666667 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6666667 + value: 800 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sparkle (2) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.33333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 350 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sparkle (3) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.33333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 500 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sparkle (3) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.33333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: -350 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sparkle (4) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.33333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 600 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sparkle (4) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sparkle (4) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sparkle (3) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.6666667 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sparkle (2) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.6666667 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sparkle (1) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 120 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (1) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 457 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (1) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (1) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: -225 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (2) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 654 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (2) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (2) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: -138 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (3) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 475 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (3) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (3) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 199 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (4) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 600 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (4) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (4) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 206 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (5) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 759 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (5) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (5) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 33 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: Image Sun (6) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 700 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 833 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Image Sun (6) + classID: 224 + script: {fileID: 0} + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.1666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Color.a + path: Image Sun (6) + classID: 114 + script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Courses/Animations/Confetti.anim.meta b/Assets/Courses/Animations/Confetti.anim.meta new file mode 100644 index 0000000..1b4bd55 --- /dev/null +++ b/Assets/Courses/Animations/Confetti.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80e3a60d4ea0a694db9be9f4a056a91c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Animations/Confetti.controller b/Assets/Courses/Animations/Confetti.controller new file mode 100644 index 0000000..81c8783 --- /dev/null +++ b/Assets/Courses/Animations/Confetti.controller @@ -0,0 +1,156 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1101 &-7239564584697438876 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: [] + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: -2938659460563783466} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0 + m_TransitionOffset: 0 + m_ExitTime: 1 + m_HasExitTime: 1 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1102 &-2938659460563783466 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Start + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 4172487341573610915} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 0} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Confetti + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: Display Confetti + m_Type: 9 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 9100000} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 6848255674075954930} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1101 &4172487341573610915 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Display Confetti + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 9042158504931283488} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0 + m_TransitionOffset: 0 + m_ExitTime: 0.75 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1107 &6848255674075954930 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 9042158504931283488} + m_Position: {x: 320, y: 240, z: 0} + - serializedVersion: 1 + m_State: {fileID: -2938659460563783466} + m_Position: {x: 320, y: 120, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: -2938659460563783466} +--- !u!1102 &9042158504931283488 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Confetti + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: -7239564584697438876} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 80e3a60d4ea0a694db9be9f4a056a91c, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: diff --git a/Assets/Courses/Animations/Confetti.controller.meta b/Assets/Courses/Animations/Confetti.controller.meta new file mode 100644 index 0000000..3a6a56d --- /dev/null +++ b/Assets/Courses/Animations/Confetti.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e9aa59de00b92e6468ea178b6a87868f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Animations/PanelAtRest.anim b/Assets/Courses/Animations/PanelAtRest.anim new file mode 100644 index 0000000..d98e288 --- /dev/null +++ b/Assets/Courses/Animations/PanelAtRest.anim @@ -0,0 +1,98 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: PanelAtRest + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Courses/Animations/PanelAtRest.anim.meta b/Assets/Courses/Animations/PanelAtRest.anim.meta new file mode 100644 index 0000000..fd779e4 --- /dev/null +++ b/Assets/Courses/Animations/PanelAtRest.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0a3de39ab7b53741b4cc9b514f651d4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Animations/Sign with Video and Image.controller b/Assets/Courses/Animations/Sign with Video and Image.controller new file mode 100644 index 0000000..e4984b5 --- /dev/null +++ b/Assets/Courses/Animations/Sign with Video and Image.controller @@ -0,0 +1,220 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1102 &-6762280829515909430 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: PanelAtRest + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 3972640238460552754} + - {fileID: 5011812139034206004} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: b0a3de39ab7b53741b4cc9b514f651d4, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1102 &-5595631104847502785 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: SlidePanelOut + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: [] + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 01aa21a7da3008e499655335bd79647d, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1102 &-1098571647962602430 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: SlidePanelIn + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 5438550235036740166} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 1051f9ab6ffe79b49903eb6935cb85db, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Sign with Video and Image + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: Slide Panel In + m_Type: 9 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + - m_Name: Slide Panel Out + m_Type: 9 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 4086587755769510042} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1101 &3972640238460552754 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Slide Panel In + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: -1098571647962602430} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0 + m_TransitionOffset: 0 + m_ExitTime: 1 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1107 &4086587755769510042 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: -1098571647962602430} + m_Position: {x: -100, y: 70, z: 0} + - serializedVersion: 1 + m_State: {fileID: -5595631104847502785} + m_Position: {x: -100, y: 250, z: 0} + - serializedVersion: 1 + m_State: {fileID: -6762280829515909430} + m_Position: {x: 150, y: 70, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 40, y: -10, z: 0} + m_EntryPosition: {x: 170, y: 220, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: -6762280829515909430} +--- !u!1101 &5011812139034206004 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Slide Panel Out + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: -5595631104847502785} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0 + m_TransitionOffset: 0 + m_ExitTime: 0 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1101 &5438550235036740166 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Slide Panel Out + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: -5595631104847502785} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0 + m_TransitionOffset: 0 + m_ExitTime: 1 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 diff --git a/Assets/Courses/Animations/Sign with Video and Image.controller.meta b/Assets/Courses/Animations/Sign with Video and Image.controller.meta new file mode 100644 index 0000000..878eaac --- /dev/null +++ b/Assets/Courses/Animations/Sign with Video and Image.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1f42eebe6fb647e49b6bcd8023590eb7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Animations/SlidePanelIn.anim b/Assets/Courses/Animations/SlidePanelIn.anim new file mode 100644 index 0000000..913d7fc --- /dev/null +++ b/Assets/Courses/Animations/SlidePanelIn.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: SlidePanelIn + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1920 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1920 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Courses/Animations/SlidePanelIn.anim.meta b/Assets/Courses/Animations/SlidePanelIn.anim.meta new file mode 100644 index 0000000..9db9d64 --- /dev/null +++ b/Assets/Courses/Animations/SlidePanelIn.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1051f9ab6ffe79b49903eb6935cb85db +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Animations/SlidePanelOut.anim b/Assets/Courses/Animations/SlidePanelOut.anim new file mode 100644 index 0000000..f642962 --- /dev/null +++ b/Assets/Courses/Animations/SlidePanelOut.anim @@ -0,0 +1,116 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: SlidePanelOut + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -1920 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_PPtrCurves: [] + m_SampleRate: 12 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1460864421 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.41666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -1920 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.x + path: + classID: 224 + script: {fileID: 0} + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Courses/Animations/SlidePanelOut.anim.meta b/Assets/Courses/Animations/SlidePanelOut.anim.meta new file mode 100644 index 0000000..d24dc05 --- /dev/null +++ b/Assets/Courses/Animations/SlidePanelOut.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 01aa21a7da3008e499655335bd79647d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/PlayModeTests/BasicTests.cs b/Assets/Courses/PlayModeTests/BasicTests.cs index 28331c9..6d4d054 100644 --- a/Assets/Courses/PlayModeTests/BasicTests.cs +++ b/Assets/Courses/PlayModeTests/BasicTests.cs @@ -12,7 +12,7 @@ public class BasicTests [UnityTest] public IEnumerator BasicTestsWithEnumeratorPasses() { - SceneManager.LoadScene("TemplateCourse"); + SceneManager.LoadScene("CourseScreen"); // Use the Assert class to test conditions. // Use yield to skip a frame. yield return null; diff --git a/Assets/Courses/PlayModeTests/PlayModeTests.asmdef b/Assets/Courses/PlayModeTests/PlayModeTests.asmdef index c978340..081dc61 100644 --- a/Assets/Courses/PlayModeTests/PlayModeTests.asmdef +++ b/Assets/Courses/PlayModeTests/PlayModeTests.asmdef @@ -1,6 +1,22 @@ { "name": "PlayModeTests", - "optionalUnityReferences": [ - "TestAssemblies" - ] -} + "rootNamespace": "", + "references": [ + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "ArchitectureScripts" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Courses/Prefabs.meta b/Assets/Courses/Prefabs.meta new file mode 100644 index 0000000..c9902e7 --- /dev/null +++ b/Assets/Courses/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6db45a76d49ab374d812c861046eab0c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Prefabs/Choice Fingerspelling.prefab b/Assets/Courses/Prefabs/Choice Fingerspelling.prefab new file mode 100644 index 0000000..0a3f1cc --- /dev/null +++ b/Assets/Courses/Prefabs/Choice Fingerspelling.prefab @@ -0,0 +1,200 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5113510004904501784 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8754575466874197751} + - component: {fileID: 673816572445470689} + - component: {fileID: 7970930246351935795} + m_Layer: 5 + m_Name: ImageOption + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8754575466874197751 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5113510004904501784} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2971620926005579559} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 200, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &673816572445470689 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5113510004904501784} + m_CullTransparentMesh: 1 +--- !u!114 &7970930246351935795 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5113510004904501784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6757870033260325101 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2971620926005579559} + - component: {fileID: 6432676832222266704} + - component: {fileID: 2847679918420822150} + - component: {fileID: 4998400628217915919} + m_Layer: 5 + m_Name: Choice Fingerspelling + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2971620926005579559 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6757870033260325101} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8754575466874197751} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -960, y: -540} + m_SizeDelta: {x: 250, y: 250} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6432676832222266704 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6757870033260325101} + m_CullTransparentMesh: 1 +--- !u!114 &2847679918420822150 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6757870033260325101} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 0.78431374} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 4998400628217915919} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &4998400628217915919 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6757870033260325101} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: deac5438096d5f64bbdf6b1934ef230e, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 1 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1.5 diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/Generated/onnx.proto3.meta b/Assets/Courses/Prefabs/Choice Fingerspelling.prefab.meta similarity index 63% rename from Packages/com.unity.barracuda/Runtime/ONNX/Generated/onnx.proto3.meta rename to Assets/Courses/Prefabs/Choice Fingerspelling.prefab.meta index 46215da..83cc9db 100644 --- a/Packages/com.unity.barracuda/Runtime/ONNX/Generated/onnx.proto3.meta +++ b/Assets/Courses/Prefabs/Choice Fingerspelling.prefab.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 5d7cda065413e45b6a67b8623bd3b710 -DefaultImporter: +guid: 3d0da629a7686e34cb645f9e375f1754 +PrefabImporter: externalObjects: {} userData: assetBundleName: diff --git a/Assets/Courses/Prefabs/Choice.prefab b/Assets/Courses/Prefabs/Choice.prefab new file mode 100644 index 0000000..c213f40 --- /dev/null +++ b/Assets/Courses/Prefabs/Choice.prefab @@ -0,0 +1,336 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &499712802029590215 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8166464829605811136} + - component: {fileID: 8993002675371337427} + - component: {fileID: 4018761505178052810} + m_Layer: 5 + m_Name: TextOption + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8166464829605811136 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 499712802029590215} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2971620926005579559} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 55, y: 0} + m_SizeDelta: {x: -110, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8993002675371337427 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 499712802029590215} + m_CullTransparentMesh: 1 +--- !u!114 &4018761505178052810 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 499712802029590215} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Button + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294309365 + m_fontColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 48 + m_fontSizeBase: 48 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &5113510004904501784 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8754575466874197751} + - component: {fileID: 673816572445470689} + - component: {fileID: 7970930246351935795} + m_Layer: 5 + m_Name: ImageOption + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8754575466874197751 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5113510004904501784} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2971620926005579559} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &673816572445470689 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5113510004904501784} + m_CullTransparentMesh: 1 +--- !u!114 &7970930246351935795 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5113510004904501784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6757870033260325101 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2971620926005579559} + - component: {fileID: 6432676832222266704} + - component: {fileID: 2847679918420822150} + - component: {fileID: 4998400628217915919} + m_Layer: 5 + m_Name: Choice + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2971620926005579559 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6757870033260325101} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8166464829605811136} + - {fileID: 8754575466874197751} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -960, y: -540} + m_SizeDelta: {x: 500, y: 100} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6432676832222266704 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6757870033260325101} + m_CullTransparentMesh: 1 +--- !u!114 &2847679918420822150 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6757870033260325101} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 0.78431374} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 4998400628217915919} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &4998400628217915919 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6757870033260325101} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: deac5438096d5f64bbdf6b1934ef230e, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 1 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1.5 diff --git a/Assets/Courses/Prefabs/Choice.prefab.meta b/Assets/Courses/Prefabs/Choice.prefab.meta new file mode 100644 index 0000000..d175a14 --- /dev/null +++ b/Assets/Courses/Prefabs/Choice.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1d4760e75172ce846819b46a0357c742 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Prefabs/Learnable Sprite.prefab b/Assets/Courses/Prefabs/Learnable Sprite.prefab new file mode 100644 index 0000000..148436a --- /dev/null +++ b/Assets/Courses/Prefabs/Learnable Sprite.prefab @@ -0,0 +1,78 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &932198721856629018 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 932198721856629013} + - component: {fileID: 932198721856629015} + - component: {fileID: 932198721856629012} + m_Layer: 5 + m_Name: Learnable Sprite + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &932198721856629013 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 932198721856629018} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &932198721856629015 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 932198721856629018} + m_CullTransparentMesh: 1 +--- !u!114 &932198721856629012 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 932198721856629018} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 7ff2526af24167b4083dab0d9fd486ea, type: 3} + m_Type: 0 + m_PreserveAspect: 1 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 diff --git a/Assets/Courses/Prefabs/Learnable Sprite.prefab.meta b/Assets/Courses/Prefabs/Learnable Sprite.prefab.meta new file mode 100644 index 0000000..2b67fbb --- /dev/null +++ b/Assets/Courses/Prefabs/Learnable Sprite.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 95bd99d20fa0c1348807ebf7a3717c02 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Prefabs/MultipleChoice Panel.prefab b/Assets/Courses/Prefabs/MultipleChoice Panel.prefab new file mode 100644 index 0000000..e574f57 --- /dev/null +++ b/Assets/Courses/Prefabs/MultipleChoice Panel.prefab @@ -0,0 +1,539 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &531490360556612897 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2753082322791035192} + - component: {fileID: 4172057369382989418} + m_Layer: 5 + m_Name: Choices Fingerspelling + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2753082322791035192 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 531490360556612897} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4061330368179216051} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 45} + m_SizeDelta: {x: 250, y: 250} + m_Pivot: {x: 0.5, y: 0} +--- !u!114 &4172057369382989418 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 531490360556612897} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 250, y: 250} + m_Spacing: {x: 25, y: 25} + m_Constraint: 2 + m_ConstraintCount: 1 +--- !u!1 &2111479550264969558 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5812954516243589766} + - component: {fileID: 8814642598985503128} + m_Layer: 5 + m_Name: Choices + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5812954516243589766 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2111479550264969558} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4061330368179216051} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 120} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0} +--- !u!114 &8814642598985503128 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2111479550264969558} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 500, y: 100} + m_Spacing: {x: 25, y: 25} + m_Constraint: 2 + m_ConstraintCount: 2 +--- !u!1 &4061330367519500214 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4061330367519500213} + - component: {fileID: 4061330367519500106} + - component: {fileID: 4061330367519500107} + - component: {fileID: 4061330367519500212} + m_Layer: 5 + m_Name: Pause button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4061330367519500213 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330367519500214} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4061330367711737314} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 10} + m_SizeDelta: {x: 50, y: 50} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &4061330367519500106 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330367519500214} + m_CullTransparentMesh: 0 +--- !u!114 &4061330367519500107 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330367519500214} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: e9d7c25ce4800b840a37d69d5b876671, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &4061330367519500212 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330367519500214} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 0 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 4061330367519500107} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1776754253067810093} + m_TargetAssemblyTypeName: PanelMultipleChoice, CourseScripts + m_MethodName: TogglePlayPause + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!1 &4061330367711737315 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4061330367711737314} + - component: {fileID: 4061330367711737312} + - component: {fileID: 4061330367711737313} + m_Layer: 5 + m_Name: Video Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4061330367711737314 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330367711737315} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 4061330367519500213} + m_Father: {fileID: 4061330368179216051} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 96} + m_SizeDelta: {x: 900, y: 600} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4061330367711737312 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330367711737315} + m_CullTransparentMesh: 1 +--- !u!114 &4061330367711737313 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330367711737315} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 8400000, guid: b0382d4acabd441499108c97444d642a, type: 2} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!1 &4061330368179216060 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4061330368179216051} + - component: {fileID: 4061330368179216049} + - component: {fileID: 4061330368179216050} + - component: {fileID: 1776754253067810093} + - component: {fileID: 4803386377269900023} + m_Layer: 5 + m_Name: MultipleChoice Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4061330368179216051 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330368179216060} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4061330367711737314} + - {fileID: 4061330368314523223} + - {fileID: 5812954516243589766} + - {fileID: 2753082322791035192} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4061330368179216049 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330368179216060} + m_CullTransparentMesh: 0 +--- !u!114 &4061330368179216050 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330368179216060} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &1776754253067810093 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330368179216060} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e46fcdec22898f04eac0a7981baae26a, type: 3} + m_Name: + m_EditorClassIdentifier: + webcamScreen: {fileID: 4061330368314523222} + playSprite: {fileID: 21300000, guid: 05a683651206b994fa7921be6d84dddf, type: 3} + pauseSprite: {fileID: 21300000, guid: e9d7c25ce4800b840a37d69d5b876671, type: 3} + courseController: {fileID: 0} + videoPlayer: {fileID: 0} + playButton: {fileID: 4061330367519500107} + optionContainer: {fileID: 5812954516243589766} + optionFingerspellingContainer: {fileID: 2753082322791035192} + optionPrefab: {fileID: 6757870033260325101, guid: 1d4760e75172ce846819b46a0357c742, type: 3} + optionFingerspellingPrefab: {fileID: 6757870033260325101, guid: 3d0da629a7686e34cb645f9e375f1754, type: 3} + progress: + entries: [] + courseIndex: 0 + progress: -1 + completedLearnables: 0 + inUseLearnables: 0 + totalLearnables: 0 + learnables: [] + signs: [] + currentSignIndex: 0 + isFingerSpelling: 0 +--- !u!95 &4803386377269900023 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330368179216060} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 1f42eebe6fb647e49b6bcd8023590eb7, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &4061330368314523216 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4061330368314523223} + - component: {fileID: 4061330368314523221} + - component: {fileID: 4061330368314523222} + m_Layer: 5 + m_Name: Webcam Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &4061330368314523223 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330368314523216} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.75, y: 0.75, z: 0.75} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 4061330368179216051} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 420, y: 100} + m_SizeDelta: {x: 900, y: 600} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4061330368314523221 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330368314523216} + m_CullTransparentMesh: 1 +--- !u!114 &4061330368314523222 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4061330368314523216} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 8400000, guid: 60bb0835fc4bbb043b9b3d8ef48f96a8, type: 2} + m_UVRect: + serializedVersion: 2 + x: 1 + y: 0 + width: -1 + height: 1 diff --git a/Assets/Courses/Prefabs/MultipleChoice Panel.prefab.meta b/Assets/Courses/Prefabs/MultipleChoice Panel.prefab.meta new file mode 100644 index 0000000..b359f90 --- /dev/null +++ b/Assets/Courses/Prefabs/MultipleChoice Panel.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0259289fdb7aea04995238fabcd1d15e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Prefabs/Sign with Image Panel.prefab b/Assets/Courses/Prefabs/Sign with Image Panel.prefab new file mode 100644 index 0000000..80067ca --- /dev/null +++ b/Assets/Courses/Prefabs/Sign with Image Panel.prefab @@ -0,0 +1,556 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1321140593464287921 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1321140593464287926} + - component: {fileID: 1321140593464287927} + m_Layer: 5 + m_Name: Images + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1321140593464287926 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140593464287921} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1321140593660784790} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -420, y: 100} + m_SizeDelta: {x: 450, y: 450} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1321140593464287927 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140593464287921} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 450, y: 450} + m_Spacing: {x: 25, y: 0} + m_Constraint: 2 + m_ConstraintCount: 1 +--- !u!1 &1321140593660784785 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1321140593660784790} + - component: {fileID: 1321140593660784788} + - component: {fileID: 1321140593660784791} + - component: {fileID: -7339382000603611155} + - component: {fileID: 2706222911073219473} + m_Layer: 5 + m_Name: Sign with Image Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1321140593660784790 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140593660784785} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1321140594547902075} + - {fileID: 1321140594132691875} + - {fileID: 1321140593464287926} + - {fileID: 3006345639555307698} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1321140593660784788 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140593660784785} + m_CullTransparentMesh: 0 +--- !u!114 &1321140593660784791 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140593660784785} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &-7339382000603611155 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140593660784785} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 09eba136d66a8cd4abf6f6ebfd0006f4, type: 3} + m_Name: + m_EditorClassIdentifier: + feedbackProgressObject: {fileID: 3006345639555307697} + previewMessage: {fileID: 1321140594132691874} + isPreview: 0 + signImageContainer: {fileID: 1321140593464287926} + signImagePrefab: {fileID: 932198721856629018, guid: 95bd99d20fa0c1348807ebf7a3717c02, type: 3} + webcamScreen: {fileID: 1321140594547902072} + feedbackText: {fileID: 3006345639897809774} + feedbackProgressBar: {fileID: 3006345639643869492} + feedbackProgressImage: {fileID: 3006345639958312625} + signs: [] + currentSignIndex: 0 +--- !u!95 &2706222911073219473 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140593660784785} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 1f42eebe6fb647e49b6bcd8023590eb7, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1 &1321140594132691874 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1321140594132691875} + - component: {fileID: 1321140594132691873} + - component: {fileID: 1321140594132691872} + m_Layer: 5 + m_Name: PreviewMessage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1321140594132691875 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140594132691874} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1321140593660784790} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 150, y: 150} + m_SizeDelta: {x: 900, y: 200} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &1321140594132691873 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140594132691874} + m_CullTransparentMesh: 1 +--- !u!114 &1321140594132691872 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140594132691874} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'DEZE LES IS GESTART IN PREVIEW MODUS + + Het is nog niet mogelijk deze + les te spelen via gebaren. Gebruik de ''Gebaar overslaan'' knop om naar het volgende + gebaar te gaan.' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4278190335 + m_fontColor: {r: 0.9607843, g: 0.28627452, b: 0.23921569, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 1 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &1321140594547902074 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1321140594547902075} + - component: {fileID: 1321140594547902073} + - component: {fileID: 1321140594547902072} + m_Layer: 5 + m_Name: Webcam Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1321140594547902075 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140594547902074} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.75, y: 0.75, z: 0.75} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1321140593660784790} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 82.5, y: 325} + m_SizeDelta: {x: 900, y: 600} + m_Pivot: {x: 0, y: 1} +--- !u!222 &1321140594547902073 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140594547902074} + m_CullTransparentMesh: 1 +--- !u!114 &1321140594547902072 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321140594547902074} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 8400000, guid: 60bb0835fc4bbb043b9b3d8ef48f96a8, type: 2} + m_UVRect: + serializedVersion: 2 + x: 1 + y: 0 + width: -1 + height: 1 +--- !u!1001 &1321140593577244758 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1321140593660784790} + m_Modifications: + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_Pivot.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMax.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMax.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMin.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMin.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_SizeDelta.x + value: 500 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_SizeDelta.y + value: 150 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchoredPosition.x + value: 82.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchoredPosition.y + value: -250 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: signPredictor + value: + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_Name + value: Feedback + objectReference: {fileID: 0} + - target: {fileID: 4318122119968934245, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4318122120222767926, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122120334233317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} +--- !u!1 &3006345639555307697 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 4318122119930585319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 1321140593577244758} + m_PrefabAsset: {fileID: 0} +--- !u!224 &3006345639555307698 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 1321140593577244758} + m_PrefabAsset: {fileID: 0} +--- !u!114 &3006345639643869492 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4318122119968934242, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 1321140593577244758} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 67db9e8f0e2ae9c40bc1e2b64352a6b4, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &3006345639897809774 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 1321140593577244758} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &3006345639958312625 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4318122120334233319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 1321140593577244758} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Courses/Prefabs/Sign with Image Panel.prefab.meta b/Assets/Courses/Prefabs/Sign with Image Panel.prefab.meta new file mode 100644 index 0000000..e58c93c --- /dev/null +++ b/Assets/Courses/Prefabs/Sign with Image Panel.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 41cc30039c205e04baf44453287d6469 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Prefabs/Sign with Video and Image Panel.prefab b/Assets/Courses/Prefabs/Sign with Video and Image Panel.prefab new file mode 100644 index 0000000..c67900f --- /dev/null +++ b/Assets/Courses/Prefabs/Sign with Video and Image Panel.prefab @@ -0,0 +1,756 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6228868149649096753 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6228868149649096748} + - component: {fileID: 6228868149649096751} + - component: {fileID: 6228868149649096750} + m_Layer: 5 + m_Name: PreviewMessage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &6228868149649096748 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868149649096753} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6228868151418550170} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 150, y: 150} + m_SizeDelta: {x: 900, y: 200} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &6228868149649096751 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868149649096753} + m_CullTransparentMesh: 1 +--- !u!114 &6228868149649096750 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868149649096753} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'DEZE LES IS GESTART IN PREVIEW MODUS + + Het is nog niet mogelijk deze + les te spelen via gebaren. Gebruik de ''Gebaar overslaan'' knop om naar het volgende + gebaar te gaan.' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4278190335 + m_fontColor: {r: 0.9607843, g: 0.28627452, b: 0.23921569, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 1 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &6228868150227029584 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6228868150227029585} + - component: {fileID: 6228868150227029583} + - component: {fileID: 6228868150227029582} + m_Layer: 5 + m_Name: Video Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6228868150227029585 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150227029584} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.75, y: 0.75, z: 0.75} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 6228868150560507659} + m_Father: {fileID: 6228868151418550170} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -420, y: 100} + m_SizeDelta: {x: 900, y: 600} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6228868150227029583 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150227029584} + m_CullTransparentMesh: 1 +--- !u!114 &6228868150227029582 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150227029584} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 8400000, guid: b0382d4acabd441499108c97444d642a, type: 2} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!1 &6228868150458477980 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6228868150458477981} + - component: {fileID: 6228868150458477978} + m_Layer: 5 + m_Name: Images + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6228868150458477981 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150458477980} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6228868151418550170} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -420, y: -308} + m_SizeDelta: {x: 256, y: 256} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &6228868150458477978 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150458477980} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 256, y: 256} + m_Spacing: {x: 25, y: 0} + m_Constraint: 2 + m_ConstraintCount: 1 +--- !u!1 &6228868150560507658 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6228868150560507659} + - component: {fileID: 6228868150560507654} + - component: {fileID: 6228868150560507657} + - component: {fileID: 6228868150560507656} + m_Layer: 5 + m_Name: Pause button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6228868150560507659 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150560507658} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6228868150227029585} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 10} + m_SizeDelta: {x: 50, y: 50} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &6228868150560507654 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150560507658} + m_CullTransparentMesh: 0 +--- !u!114 &6228868150560507657 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150560507658} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: e9d7c25ce4800b840a37d69d5b876671, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &6228868150560507656 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868150560507658} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 0 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6228868150560507657} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 3429747640456784550} + m_TargetAssemblyTypeName: PanelWithVideoAndImage, CourseScripts + m_MethodName: TogglePlayPause + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!1 &6228868151341466128 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6228868151341466129} + - component: {fileID: 6228868151341466127} + - component: {fileID: 6228868151341466126} + m_Layer: 5 + m_Name: Webcam Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6228868151341466129 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868151341466128} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.75, y: 0.75, z: 0.75} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 6228868151418550170} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 82.5, y: 325} + m_SizeDelta: {x: 900, y: 600} + m_Pivot: {x: 0, y: 1} +--- !u!222 &6228868151341466127 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868151341466128} + m_CullTransparentMesh: 1 +--- !u!114 &6228868151341466126 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868151341466128} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 8400000, guid: 60bb0835fc4bbb043b9b3d8ef48f96a8, type: 2} + m_UVRect: + serializedVersion: 2 + x: 1 + y: 0 + width: -1 + height: 1 +--- !u!1 &6228868151418550173 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6228868151418550170} + - component: {fileID: 6228868151418550168} + - component: {fileID: 6228868151418550171} + - component: {fileID: 3429747640456784550} + - component: {fileID: 858417495495149503} + m_Layer: 5 + m_Name: Sign with Video and Image Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6228868151418550170 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868151418550173} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6228868150227029585} + - {fileID: 6228868151341466129} + - {fileID: 6228868149649096748} + - {fileID: 6228868150458477981} + - {fileID: 6228868150005252292} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6228868151418550168 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868151418550173} + m_CullTransparentMesh: 0 +--- !u!114 &6228868151418550171 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868151418550173} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &3429747640456784550 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868151418550173} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4631ff9751fcb1e4b8ef5451d2650537, type: 3} + m_Name: + m_EditorClassIdentifier: + feedbackProgressObject: {fileID: 6228868150005252295} + previewMessage: {fileID: 6228868149649096753} + isPreview: 0 + playSprite: {fileID: 21300000, guid: 05a683651206b994fa7921be6d84dddf, type: 3} + pauseSprite: {fileID: 21300000, guid: e9d7c25ce4800b840a37d69d5b876671, type: 3} + videoPlayer: {fileID: 0} + playButton: {fileID: 6228868150560507657} + webcamScreen: {fileID: 6228868151341466126} + signImageContainer: {fileID: 6228868150458477981} + signImagePrefab: {fileID: 932198721856629018, guid: 95bd99d20fa0c1348807ebf7a3717c02, type: 3} + feedbackText: {fileID: 6228868150483786520} + feedbackProgressBar: {fileID: 6228868149697554754} + feedbackProgressImage: {fileID: 6228868150406000327} + signs: [] + currentSignIndex: 0 +--- !u!95 &858417495495149503 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6228868151418550173} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 1f42eebe6fb647e49b6bcd8023590eb7, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 +--- !u!1001 &7898310597051605024 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 6228868151418550170} + m_Modifications: + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_Pivot.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_Pivot.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_RootOrder + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMax.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMax.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMin.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMin.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_SizeDelta.x + value: 500 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_SizeDelta.y + value: 150 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchoredPosition.x + value: 82.5 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchoredPosition.y + value: -250 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122119930585319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_Name + value: Feedback + objectReference: {fileID: 0} + - target: {fileID: 4318122120334233317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} +--- !u!114 &6228868149697554754 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4318122119968934242, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 7898310597051605024} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 67db9e8f0e2ae9c40bc1e2b64352a6b4, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!224 &6228868150005252292 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 7898310597051605024} + m_PrefabAsset: {fileID: 0} +--- !u!1 &6228868150005252295 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 4318122119930585319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 7898310597051605024} + m_PrefabAsset: {fileID: 0} +--- !u!114 &6228868150406000327 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4318122120334233319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 7898310597051605024} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &6228868150483786520 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 7898310597051605024} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Courses/Prefabs/Sign with Video and Image Panel.prefab.meta b/Assets/Courses/Prefabs/Sign with Video and Image Panel.prefab.meta new file mode 100644 index 0000000..e37db81 --- /dev/null +++ b/Assets/Courses/Prefabs/Sign with Video and Image Panel.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ed122bc34368fca4f9c28e96b772da66 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/Scenes/TemplateCourse.unity b/Assets/Courses/Scenes/CourseScreen.unity similarity index 73% rename from Assets/Courses/Scenes/TemplateCourse.unity rename to Assets/Courses/Scenes/CourseScreen.unity index 036592f..71fc22c 100644 --- a/Assets/Courses/Scenes/TemplateCourse.unity +++ b/Assets/Courses/Scenes/CourseScreen.unity @@ -394,7 +394,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 100123244} m_CullTransparentMesh: 1 ---- !u!1 &301088547 +--- !u!1 &257279696 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -402,110 +402,66 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 301088548} - - component: {fileID: 301088550} - - component: {fileID: 301088549} - - component: {fileID: 301088551} + - component: {fileID: 257279697} + - component: {fileID: 257279698} m_Layer: 5 - m_Name: Panel + m_Name: Confetti m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &301088548 +--- !u!224 &257279697 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301088547} + m_GameObject: {fileID: 257279696} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 2145235736} - - {fileID: 1493108463} - - {fileID: 378145455} - - {fileID: 1813638489} - - {fileID: 1335886460} - - {fileID: 1714882682} - - {fileID: 2070775954} + - {fileID: 1600926568} + - {fileID: 1697464982} + - {fileID: 441048006} + - {fileID: 1335095134} + - {fileID: 1921588802} + - {fileID: 1100468617} + - {fileID: 983429721} + - {fileID: 648245398} + - {fileID: 2017030786} + - {fileID: 551249239} + - {fileID: 642206910} m_Father: {fileID: 1559094126} - m_RootOrder: 0 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: -200} m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &301088549 -MonoBehaviour: + m_Pivot: {x: 0.5, y: 0} +--- !u!95 &257279698 +Animator: + serializedVersion: 5 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301088547} + m_GameObject: {fileID: 257279696} m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.4627451} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &301088550 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301088547} - m_CullTransparentMesh: 0 ---- !u!114 &301088551 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301088547} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6b3f784c065813a4a8364b1299284816, type: 3} - m_Name: - m_EditorClassIdentifier: - previewModel: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} - feedbackProgressBar: {fileID: 4318122121437849759} - previewMessage: {fileID: 2070775951} - player: {fileID: 993952931} - button: {fileID: 1159630774} - pauseSprite: {fileID: 21300000, guid: 43db869a07cf51f45a411b6e4a417743, type: 3} - wordImage: {fileID: 2145235737} - title: {fileID: 388014849} - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - courselist: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} - ResultPanel: {fileID: 1383144366} - ResultsTitle: {fileID: 822960079} - ResultsDecription: {fileID: 100123246} - CoursesButton: {fileID: 839294691} - timeSpent: {fileID: 77614869} - feedback: {fileID: 1714882683} + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: e9aa59de00b92e6468ea178b6a87868f, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 --- !u!1 &361280475 GameObject: m_ObjectHideFlags: 0 @@ -711,79 +667,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 374007089} m_CullTransparentMesh: 1 ---- !u!1 &378145454 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 378145455} - - component: {fileID: 378145457} - - component: {fileID: 378145456} - m_Layer: 5 - m_Name: Webcam Background - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &378145455 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 378145454} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 301088548} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 479.99994, y: 117.00006} - m_SizeDelta: {x: 960, y: 540} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &378145456 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 378145454} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Texture: {fileID: 8400000, guid: 60bb0835fc4bbb043b9b3d8ef48f96a8, type: 2} - m_UVRect: - serializedVersion: 2 - x: 1 - y: 0 - width: -1 - height: 1 ---- !u!222 &378145457 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 378145454} - m_CullTransparentMesh: 1 --- !u!1 &388014847 GameObject: m_ObjectHideFlags: 0 @@ -796,7 +679,7 @@ GameObject: - component: {fileID: 388014850} - component: {fileID: 388014849} m_Layer: 5 - m_Name: Title + m_Name: Course Title m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -815,12 +698,12 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1559094126} - m_RootOrder: 1 + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 1} - m_AnchorMax: {x: 0.5, y: 1} - m_AnchoredPosition: {x: 0, y: -25} - m_SizeDelta: {x: 1200, y: 100} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -50} + m_SizeDelta: {x: 0, y: 100} m_Pivot: {x: 0.5, y: 1} --- !u!114 &388014849 MonoBehaviour: @@ -844,15 +727,15 @@ MonoBehaviour: m_Calls: [] m_text: Title m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4294967295 - m_fontColor: {r: 1, g: 1, b: 1, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -864,7 +747,7 @@ MonoBehaviour: m_spriteAsset: {fileID: 0} m_tintAllSprites: 0 m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: 97690656 + m_TextStyleHashCode: -1183493901 m_overrideHtmlColors: 0 m_faceColor: serializedVersion: 2 @@ -876,8 +759,8 @@ MonoBehaviour: m_fontSizeMin: 18 m_fontSizeMax: 72 m_fontStyle: 1 - m_HorizontalAlignment: 1 - m_VerticalAlignment: 256 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 m_textAlignment: 65535 m_characterSpacing: 0 m_wordSpacing: 0 @@ -919,6 +802,216 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 388014847} m_CullTransparentMesh: 1 +--- !u!1 &429306632 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 429306633} + - component: {fileID: 429306636} + - component: {fileID: 429306635} + - component: {fileID: 429306634} + m_Layer: 5 + m_Name: Next Sign Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &429306633 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 429306632} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 981855468} + m_Father: {fileID: 1559094126} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -20, y: 20} + m_SizeDelta: {x: 250, y: 100} + m_Pivot: {x: 1, y: 0} +--- !u!114 &429306634 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 429306632} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 429306635} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1122267056} + m_TargetAssemblyTypeName: TemplateCourse, CourseScripts + m_MethodName: NextSign + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &429306635 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 429306632} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &429306636 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 429306632} + m_CullTransparentMesh: 1 +--- !u!1 &441048005 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 441048006} + - component: {fileID: 441048008} + - component: {fileID: 441048007} + m_Layer: 5 + m_Name: Image Sparkle (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &441048006 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441048005} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &441048007 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441048005} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 1457618957, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &441048008 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441048005} + m_CullTransparentMesh: 1 --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -955,7 +1048,7 @@ Camera: m_Enabled: 1 serializedVersion: 2 m_ClearFlags: 2 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_BackGroundColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 @@ -1003,6 +1096,234 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &551249238 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 551249239} + - component: {fileID: 551249241} + - component: {fileID: 551249240} + m_Layer: 5 + m_Name: Image Sun (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &551249239 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 551249238} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 206, y: 759} + m_SizeDelta: {x: 50, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &551249240 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 551249238} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: -2086278073, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &551249241 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 551249238} + m_CullTransparentMesh: 1 +--- !u!1 &642206909 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 642206910} + - component: {fileID: 642206912} + - component: {fileID: 642206911} + m_Layer: 5 + m_Name: Image Sun (6) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &642206910 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 642206909} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 33, y: 833} + m_SizeDelta: {x: 50, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &642206911 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 642206909} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: -2086278073, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &642206912 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 642206909} + m_CullTransparentMesh: 1 +--- !u!1 &648245397 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 648245398} + - component: {fileID: 648245400} + - component: {fileID: 648245399} + m_Layer: 5 + m_Name: Image Sun (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &648245398 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648245397} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -138, y: 475} + m_SizeDelta: {x: 50, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &648245399 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648245397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: -2086278073, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &648245400 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648245397} + m_CullTransparentMesh: 1 --- !u!1 &822960077 GameObject: m_ObjectHideFlags: 0 @@ -1222,9 +1543,9 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 301088551} - m_TargetAssemblyTypeName: TemplateCourse, Assembly-CSharp - m_MethodName: Back + - m_Target: {fileID: 1122267056} + m_TargetAssemblyTypeName: CoursesController, CourseScripts + m_MethodName: StartCourseController m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} @@ -1301,11 +1622,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 043ccd99cf82b3cc9bf2e00956ce2b93, type: 3} m_Name: m_EditorClassIdentifier: - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + modelList: {fileID: 11400000, guid: 39516e4e6e56f0f4f80647d9c4d8034c, type: 2} modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3} + modelInfoFileEmbedding: {fileID: 4900000, guid: 4e303164823194bc4be87f4c9550cfd0, type: 3} configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3} - screen: {fileID: 378145456} - screen2: {fileID: 0} + screen: {fileID: 0} --- !u!4 &883853269 Transform: m_ObjectHideFlags: 0 @@ -1319,7 +1640,7 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 4 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &892938733 GameObject: @@ -1461,6 +1782,217 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 943225110} m_CullTransparentMesh: 1 +--- !u!1 &981855467 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 981855468} + - component: {fileID: 981855470} + - component: {fileID: 981855469} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &981855468 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 981855467} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 429306633} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &981855469 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 981855467} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Gebaar overslaan + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 26 + m_fontSizeBase: 26 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &981855470 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 981855467} + m_CullTransparentMesh: 1 +--- !u!1 &983429720 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 983429721} + - component: {fileID: 983429723} + - component: {fileID: 983429722} + m_Layer: 5 + m_Name: Image Sun (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &983429721 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 983429720} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -225, y: 654} + m_SizeDelta: {x: 50, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &983429722 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 983429720} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: -2086278073, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &983429723 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 983429720} + m_CullTransparentMesh: 1 --- !u!1 &993952930 GameObject: m_ObjectHideFlags: 0 @@ -1472,7 +2004,7 @@ GameObject: - component: {fileID: 993952932} - component: {fileID: 993952931} m_Layer: 5 - m_Name: Video + m_Name: VideoController m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -1520,15 +2052,15 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 993952930} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 3 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1159630772 +--- !u!1 &1100468616 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1536,100 +2068,43 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1159630773} - - component: {fileID: 1159630776} - - component: {fileID: 1159630775} - - component: {fileID: 1159630774} + - component: {fileID: 1100468617} + - component: {fileID: 1100468619} + - component: {fileID: 1100468618} m_Layer: 5 - m_Name: Pause button + m_Name: Image Sun (1) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1159630773 +--- !u!224 &1100468617 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1159630772} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_GameObject: {fileID: 1100468616} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 1493108463} - m_RootOrder: 0 + m_Father: {fileID: 257279697} + m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -0.000015258789, y: 0} - m_SizeDelta: {x: 100, y: 100} + m_AnchoredPosition: {x: 120, y: 457} + m_SizeDelta: {x: 50, y: 50} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1159630774 +--- !u!114 &1100468618 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1159630772} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1159630775} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 0} - m_TargetAssemblyTypeName: StartPause, Assembly-CSharp - m_MethodName: Pause - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!114 &1159630775 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1159630772} + m_GameObject: {fileID: 1100468616} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} @@ -1643,7 +2118,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 0c64917ad2b43af46a07398231186e6c, type: 3} + m_Sprite: {fileID: -2086278073, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1653,14 +2128,73 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1159630776 +--- !u!222 &1100468619 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1159630772} - m_CullTransparentMesh: 0 + m_GameObject: {fileID: 1100468616} + m_CullTransparentMesh: 1 +--- !u!1 &1122267055 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1122267057} + - component: {fileID: 1122267056} + m_Layer: 0 + m_Name: CourseController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1122267056 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1122267055} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b3f784c065813a4a8364b1299284816, type: 3} + m_Name: + m_EditorClassIdentifier: + signPredictor: {fileID: 883853268} + courseTitle: {fileID: 388014849} + courselist: {fileID: 11400000, guid: a7ab583094b7897468bbca9243717608, type: 2} + ResultPanel: {fileID: 1383144366} + ResultsTitle: {fileID: 822960079} + ResultsDecription: {fileID: 100123246} + CoursesButton: {fileID: 839294691} + timeSpent: {fileID: 77614869} + videoPlayer: {fileID: 993952931} + progressBar: {fileID: 1614792579} + confettiAnimation: {fileID: 257279698} + panelSignWithVideoAndImagePrefab: {fileID: 6228868151418550173, guid: ed122bc34368fca4f9c28e96b772da66, type: 3} + panelSignWithImagePrefab: {fileID: 1321140593660784785, guid: 41cc30039c205e04baf44453287d6469, type: 3} + panelMultipleChoicePrefab: {fileID: 4061330368179216060, guid: 0259289fdb7aea04995238fabcd1d15e, type: 3} + canvas: {fileID: 1559094126} +--- !u!4 &1122267057 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1122267055} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 960, y: 540, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1300721216 GameObject: m_ObjectHideFlags: 0 @@ -1737,13 +2271,101 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1300721216} m_CullTransparentMesh: 1 +--- !u!1 &1335095133 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1335095134} + - component: {fileID: 1335095136} + - component: {fileID: 1335095135} + m_Layer: 5 + m_Name: Image Sparkle (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1335095134 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335095133} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1335095135 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335095133} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 1457618957, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1335095136 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335095133} + m_CullTransparentMesh: 1 --- !u!1001 &1335886459 PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: - m_TransformParent: {fileID: 301088548} + m_TransformParent: {fileID: 1559094126} m_Modifications: + - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Target + value: + objectReference: {fileID: 1122267056} + - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: ReturnToActivityScreen + objectReference: {fileID: 0} + - target: {fileID: 8299246693487308512, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} + propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: CoursesController, CourseScripts + objectReference: {fileID: 0} - target: {fileID: 8299246693487308514, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_Name value: ButtonBack @@ -1778,11 +2400,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -1814,11 +2436,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -1832,7 +2454,8 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - m_RemovedComponents: [] + m_RemovedComponents: + - {fileID: 4518652150503380115, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} --- !u!224 &1335886460 stripped RectTransform: @@ -1876,7 +2499,7 @@ RectTransform: - {fileID: 892938734} - {fileID: 839294690} m_Father: {fileID: 1559094126} - m_RootOrder: 2 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1935,215 +2558,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1383144366} m_CullTransparentMesh: 1 ---- !u!1 &1427866734 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1427866735} - - component: {fileID: 1427866737} - - component: {fileID: 1427866736} - m_Layer: 5 - m_Name: Text (TMP) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1427866735 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1427866734} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1813638489} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1427866736 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1427866734} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: Gebaar overslaan - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 26 - m_fontSizeBase: 26 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1427866737 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1427866734} - m_CullTransparentMesh: 1 ---- !u!1 &1493108462 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1493108463} - - component: {fileID: 1493108465} - - component: {fileID: 1493108464} - m_Layer: 5 - m_Name: Video Background - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1493108463 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1493108462} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1159630773} - m_Father: {fileID: 301088548} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -483.02, y: 117.00003} - m_SizeDelta: {x: 960, y: 540} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1493108464 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1493108462} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Texture: {fileID: 8400000, guid: b0382d4acabd441499108c97444d642a, type: 2} - m_UVRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 ---- !u!222 &1493108465 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1493108462} - m_CullTransparentMesh: 1 --- !u!1 &1559094122 GameObject: m_ObjectHideFlags: 0 @@ -2192,10 +2606,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -2236,33 +2650,320 @@ RectTransform: m_LocalScale: {x: 0, y: 0, z: 0} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 301088548} - {fileID: 388014848} - {fileID: 1383144367} + - {fileID: 429306633} + - {fileID: 257279697} + - {fileID: 1335886460} + - {fileID: 1677120324} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} ---- !u!224 &1714882682 stripped +--- !u!1 &1600926567 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1600926568} + - component: {fileID: 1600926570} + - component: {fileID: 1600926569} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1600926568 RectTransform: - m_CorrespondingSourceObject: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - m_PrefabInstance: {fileID: 4318122121437849758} + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} ---- !u!114 &1714882683 stripped + m_GameObject: {fileID: 1600926567} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 256, y: 256} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1600926569 MonoBehaviour: - m_CorrespondingSourceObject: {fileID: 4318122119930585317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - m_PrefabInstance: {fileID: 4318122121437849758} + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4318122121437849759} + m_GameObject: {fileID: 1600926567} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 44e682a32ee15cc489bf50f3a06f717b, type: 3} + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: -680790105, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1600926570 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1600926567} + m_CullTransparentMesh: 1 +--- !u!1 &1614792575 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1614792576} + - component: {fileID: 1614792578} + - component: {fileID: 1614792579} + m_Layer: 5 + m_Name: Slider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1614792576 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1614792575} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1677120324} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1614792578 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1614792575} + m_CullTransparentMesh: 1 +--- !u!114 &1614792579 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1614792575} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b69b55aa2ac2e0e4592740cf1269d52c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 02283f528ead8084db69c7d8a459f0af, type: 3} + m_FillDirection: 0 + m_FillAmount: 0.237 + m_FillCenter: 1 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1677120323 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1677120324} + - component: {fileID: 1677120326} + - component: {fileID: 1677120325} + m_Layer: 5 + m_Name: Progress + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1677120324 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1677120323} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 1614792576} + m_Father: {fileID: 1559094126} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 30, y: -15} + m_SizeDelta: {x: -80, y: 40} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &1677120325 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1677120323} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 42d6d4c291d8a8a46bd0d545fd445c3d, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1677120326 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1677120323} + m_CullTransparentMesh: 1 +--- !u!1 &1697464981 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1697464982} + - component: {fileID: 1697464984} + - component: {fileID: 1697464983} + m_Layer: 5 + m_Name: Image Sparkle (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1697464982 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1697464981} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1697464983 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1697464981} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 1457618957, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1697464984 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1697464981} + m_CullTransparentMesh: 1 --- !u!1 &1773033262 GameObject: m_ObjectHideFlags: 0 @@ -2398,7 +3099,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1773033262} m_CullTransparentMesh: 1 ---- !u!1 &1813638488 +--- !u!1 &1921588801 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -2406,101 +3107,43 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1813638489} - - component: {fileID: 1813638492} - - component: {fileID: 1813638491} - - component: {fileID: 1813638490} + - component: {fileID: 1921588802} + - component: {fileID: 1921588804} + - component: {fileID: 1921588803} m_Layer: 5 - m_Name: Next Sign Button + m_Name: Image Sparkle (4) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1813638489 +--- !u!224 &1921588802 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1813638488} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_GameObject: {fileID: 1921588801} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1427866735} - m_Father: {fileID: 301088548} - m_RootOrder: 3 + m_Children: [] + m_Father: {fileID: 257279697} + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 789, y: -346.5} - m_SizeDelta: {x: 250, y: 100} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1813638490 +--- !u!114 &1921588803 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1813638488} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1813638491} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 301088551} - m_TargetAssemblyTypeName: TemplateCourse, Assembly-CSharp - m_MethodName: NextSign - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!114 &1813638491 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1813638488} + m_GameObject: {fileID: 1921588801} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} @@ -2514,8 +3157,8 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 + m_Sprite: {fileID: 1457618957, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} + m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 4 @@ -2524,15 +3167,15 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &1813638492 +--- !u!222 &1921588804 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1813638488} + m_GameObject: {fileID: 1921588801} m_CullTransparentMesh: 1 ---- !u!1 &2070775951 +--- !u!1 &2017030785 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -2540,198 +3183,59 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 2070775954} - - component: {fileID: 2070775953} - - component: {fileID: 2070775952} + - component: {fileID: 2017030786} + - component: {fileID: 2017030788} + - component: {fileID: 2017030787} m_Layer: 5 - m_Name: TEMPORARY PreviewMessage + m_Name: Image Sun (4) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &2070775952 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2070775951} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: 'DEZE LES IS GESTART IN PREVIEW MODUS - - Het is nog niet mogelijk deze - les te spelen via gebaren. Gebruik de ''Gebaar overslaan'' knop om naar het volgende - gebaar te gaan.' - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4278190335 - m_fontColor: {r: 1, g: 0, b: 0, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 1 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 1 - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &2070775953 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2070775951} - m_CullTransparentMesh: 1 ---- !u!224 &2070775954 +--- !u!224 &2017030786 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2070775951} + m_GameObject: {fileID: 2017030785} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 301088548} - m_RootOrder: 6 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0} - m_AnchorMax: {x: 0.5, y: 0} - m_AnchoredPosition: {x: 150, y: 150} - m_SizeDelta: {x: 900, y: 200} - m_Pivot: {x: 0.5, y: 0} ---- !u!1 &2145235735 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 2145235736} - - component: {fileID: 2145235738} - - component: {fileID: 2145235737} - m_Layer: 5 - m_Name: Learnable Sprite - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &2145235736 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2145235735} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 301088548} - m_RootOrder: 0 + m_Father: {fileID: 257279697} + m_RootOrder: 8 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -480, y: -346.49997} - m_SizeDelta: {x: 300, y: 300} + m_AnchoredPosition: {x: 199, y: 600} + m_SizeDelta: {x: 50, y: 50} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &2145235737 +--- !u!114 &2017030787 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2145235735} + m_GameObject: {fileID: 2017030785} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 1, g: 1, b: 1, a: 0} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 7ff2526af24167b4083dab0d9fd486ea, type: 3} + m_Sprite: {fileID: -2086278073, guid: 4d6d852f751f20046ae733db5bdb1af1, type: 3} m_Type: 0 - m_PreserveAspect: 1 + m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 4 m_FillAmount: 1 @@ -2739,129 +3243,11 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &2145235738 +--- !u!222 &2017030788 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2145235735} + m_GameObject: {fileID: 2017030785} m_CullTransparentMesh: 1 ---- !u!1001 &4318122121437849758 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 301088548} - m_Modifications: - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_Pivot.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_Pivot.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_RootOrder - value: 5 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_AnchorMax.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_AnchorMax.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_AnchorMin.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_AnchorMin.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_SizeDelta.x - value: 500 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_SizeDelta.y - value: 150 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_AnchoredPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_AnchoredPosition.y - value: 200 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122119930585317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: signPredictor - value: - objectReference: {fileID: 883853268} - - target: {fileID: 4318122119930585319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_Name - value: Feedback - objectReference: {fileID: 0} - - target: {fileID: 4318122119968934245, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_RootOrder - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4318122120222767926, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_RootOrder - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4318122120334233317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - propertyPath: m_AnchorMax.y - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} ---- !u!1 &4318122121437849759 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 4318122119930585319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} - m_PrefabInstance: {fileID: 4318122121437849758} - m_PrefabAsset: {fileID: 0} diff --git a/Assets/Courses/Scenes/TemplateCourse.unity.meta b/Assets/Courses/Scenes/CourseScreen.unity.meta similarity index 100% rename from Assets/Courses/Scenes/TemplateCourse.unity.meta rename to Assets/Courses/Scenes/CourseScreen.unity.meta diff --git a/Assets/Courses/ScriptableObjects/BasicsCourse.asset b/Assets/Courses/ScriptableObjects/BasicsCourse.asset new file mode 100644 index 0000000..ba94df0 --- /dev/null +++ b/Assets/Courses/ScriptableObjects/BasicsCourse.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f6b23e64e6ffb12459ed4f37d7305852, type: 3} + m_Name: BasicsCourse + m_EditorClassIdentifier: + index: 1 + title: Basis Gebaren + description: In deze les leer je een aantal basisgebaren, die je kan gebruiken + in het dagelijkse leven. + thumbnail: {fileID: 21300000, guid: f2a020e24bfa24842bccecf6b36d5b79, type: 3} + theme: {fileID: 11400000, guid: dd48f91f5d3b2d041b08640872a65d9c, type: 2} diff --git a/Assets/Courses/ScriptableObjects/BasicsCourse.asset.meta b/Assets/Courses/ScriptableObjects/BasicsCourse.asset.meta new file mode 100644 index 0000000..fcf837a --- /dev/null +++ b/Assets/Courses/ScriptableObjects/BasicsCourse.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e2fbe5ef8bbfaf41ae2af179c1ab52e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Courses/ScriptableObjects/ClothesCourse.asset b/Assets/Courses/ScriptableObjects/ClothesCourse.asset index a47938b..b702ca8 100644 --- a/Assets/Courses/ScriptableObjects/ClothesCourse.asset +++ b/Assets/Courses/ScriptableObjects/ClothesCourse.asset @@ -15,5 +15,5 @@ MonoBehaviour: index: 1 title: Kleren en Kleuren description: // TBA - thumbnail: {fileID: 21300000, guid: cede6c6f958f0ae4bbba6282528292cf, type: 3} + thumbnail: {fileID: 21300000, guid: 4913be0505c981a49bdbee0bbe6c33fe, type: 3} theme: {fileID: 11400000, guid: 5755ca304d16d3449991668b383d7dd5, type: 2} diff --git a/Assets/Courses/ScriptableObjects/CourseList.asset b/Assets/Courses/ScriptableObjects/CourseList.asset index 9d59799..ad7c245 100644 --- a/Assets/Courses/ScriptableObjects/CourseList.asset +++ b/Assets/Courses/ScriptableObjects/CourseList.asset @@ -15,6 +15,7 @@ MonoBehaviour: currentCourseIndex: 2 courses: - {fileID: 11400000, guid: 300921292bfd5564b8ce70b834c3f334, type: 2} + - {fileID: 11400000, guid: 1e2fbe5ef8bbfaf41ae2af179c1ab52e, type: 2} - {fileID: 11400000, guid: 622bbd43e3debd044b790f1f3f325f35, type: 2} - {fileID: 11400000, guid: a4c862fb404312b499c146eb0e957820, type: 2} - {fileID: 11400000, guid: fd1ef360b467b0943aca7c2b11ed1314, type: 2} diff --git a/Assets/Courses/ScriptableObjects/Fingerspelling.asset b/Assets/Courses/ScriptableObjects/Fingerspelling.asset index ca95915..6663255 100644 --- a/Assets/Courses/ScriptableObjects/Fingerspelling.asset +++ b/Assets/Courses/ScriptableObjects/Fingerspelling.asset @@ -15,5 +15,5 @@ MonoBehaviour: index: 0 title: Het handalfabet description: In deze les leer je het vingeralfabet of handalfabet. Van A tot Z - thumbnail: {fileID: 21300000, guid: 4eb4ef55f866f114dafb722f4bd05c76, type: 3} + thumbnail: {fileID: 21300000, guid: 27884d61026c41c41bdf4753dedf4e7f, type: 3} theme: {fileID: 11400000, guid: e02921b294fdad940b6e4d57e716d3bf, type: 2} diff --git a/Assets/Courses/ScriptableObjects/HouseCourse.asset b/Assets/Courses/ScriptableObjects/HouseCourse.asset index b215b03..8230c30 100644 --- a/Assets/Courses/ScriptableObjects/HouseCourse.asset +++ b/Assets/Courses/ScriptableObjects/HouseCourse.asset @@ -13,7 +13,7 @@ MonoBehaviour: m_Name: HouseCourse m_EditorClassIdentifier: index: 5 - title: Het huis beschrijven + title: Het huis description: // TBA thumbnail: {fileID: 21300000, guid: c8bc006b29807e34d888ea31e5d53841, type: 3} theme: {fileID: 11400000, guid: adc0467561c43494db61e303d4aeefee, type: 2} diff --git a/Assets/Courses/Scripts/CourseScripts.asmdef b/Assets/Courses/Scripts/CourseScripts.asmdef index 40b6489..cc39d5f 100644 --- a/Assets/Courses/Scripts/CourseScripts.asmdef +++ b/Assets/Courses/Scripts/CourseScripts.asmdef @@ -6,7 +6,9 @@ "AccountsScripts", "InterfacesScripts", "SignPredictor", - "Unity.Barracuda" + "NatML.ML", + "Tween", + "ArchitectureScripts" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Courses/Scripts/CoursesController.cs b/Assets/Courses/Scripts/CoursesController.cs new file mode 100644 index 0000000..f5af8fe --- /dev/null +++ b/Assets/Courses/Scripts/CoursesController.cs @@ -0,0 +1,571 @@ +using DigitalRuby.Tween; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using TMPro; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.Video; + +/// +/// TemplateCourse scene manager +/// +public class CoursesController : AbstractFeedback +{ + /// + /// Reference to the objet holding the title + /// + public TMP_Text courseTitle; + + /// + /// The current user + /// + private User user; + + /// + /// Current user progress for this course + /// + private PersistentDataController.SavedCourseProgress progress = null; + + /// + /// ScriptableObject with list of all courses + /// + public CourseList courselist; + + /// + /// Reference to Course ScriptableObject + /// + private Course course; + + /// + /// Index of the current word/letter in the course.learnables list + /// + private int currentWordIndex = 0; + + /// + /// This holds the amount of words in the course + /// + private int maxWords; + + /// + /// The "finished" screen + /// + public GameObject ResultPanel; + + /// + /// Reference to the title on the results panel + /// + public TMP_Text ResultsTitle; + + /// + /// Reference to the description on the results panel + /// + public TMP_Text ResultsDecription; + + /// + /// Button to go back to courses list + /// + public Button CoursesButton; + + /// + /// DateTime containint the start moment + /// + private DateTime startMoment; + + /// + /// Reference to the timeSpent UI + /// + public TMP_Text timeSpent; + + /// + /// Reference to the feedback field + /// + private TMP_Text feedbackText; + + /// + /// Reference to the progress bar + /// + private Slider feedbackProgress; + + /// + /// Reference to the progress bar image, so we can add fancy colors + /// + private Image feedbackProgressImage; + + public VideoPlayer videoPlayer; + + /// + /// Timer to keep track of how long a incorrect sign is performed + /// + protected DateTime timer; + + /// + /// Current predicted sign + /// + protected string predictedSign = null; + + /// + /// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs + /// + protected string previousIncorrectSign = null; + + /// + /// Keeps track of what type of panel is currently being used + /// + protected int panelId = 0; + + /// + /// Boolean used to check whether the user has already answered the question + /// + private bool hasAnswered = false; + + /// + /// Boolean used to check whether SlideIn animation is playing + /// + private bool isNextSignInTransit = false; + + /// + /// Reference to course progress bar + /// + public SlicedSlider progressBar; + + /// + /// Reference to the animator of the confetti animation + /// + public Animator confettiAnimation; + + /// + /// Panel with video&image prefab + /// + public GameObject panelSignWithVideoAndImagePrefab; + + /// + /// Panel with image prefab + /// + public GameObject panelSignWithImagePrefab; + + /// + /// Panel with multiplechoice prefab + /// + public GameObject panelMultipleChoicePrefab; + + /// + /// Reference to the canvas to put the panels into + /// + public Transform canvas; + + /// + /// Reference to the previous panel, + /// so it can be deleted when its done playing its exit animation + /// + private GameObject previousPanel = null; + + /// + /// This function is called when the script is initialised. + /// It inactivatis the popup, finds a webcam to use and links it via the WebcamTexture to the display RawImage. + /// It takes the correct course from the courselist, using the courseIndex. + /// Then it checks whether or not the User has started the course yet, to possibly create a new progress atribute for the course. + /// Then it sets up the course-screen to display relevant information from the course-scriptable. + /// + void Start() + { + StartCourseController(); + signPredictor.SetSignsList(GetSignsList()); + signPredictor.SetModel(course.theme.modelIndex); + AddSelfAsListener(); + } + + /// + /// Fetches all the strings of the signs of the course + /// + /// The signsList that needs to be passed to the signPredictor + private List GetSignsList() + { + List signsList = new List(); + foreach (Learnable learnable in course.theme.learnables) + { + signsList.Add(learnable.name); + } + + return signsList; + } + + /// + /// Holds the course-specific logic to start the controller, it is seperated to allow the course to be reset (if that would become needed) + /// + public void StartCourseController() + { + // Setting up course + course = courselist.courses[courselist.currentCourseIndex]; + maxWords = course.theme.learnables.Count; + + // Reload from disk (course may be reset) + PersistentDataController.GetInstance().Load(); + // Create entry in current user for keeping track of progress + user = UserList.GetCurrentUser(); + progress = user.GetCourseProgress(course.index); + if (progress == null) + { + progress = new PersistentDataController.SavedCourseProgress(); + progress.courseIndex = course.index; + int index = 0; + foreach (Learnable learnable in course.theme.learnables) + { + progress.AddLearnable(learnable.name, index++); + } + user.AddCourseProgress(progress); + } + UserList.Save(); + progressBar.fillAmount = progress.progress; + + currentWordIndex = 0; + previousPanel = SetupPanel(); + + // Hide the result panel + ResultPanel.SetActive(false); + // Set the startTime + startMoment = DateTime.Now; + } + + /// + /// Fetch the next sign and its panel type + /// + /// A tuple of {next sign index, panel type} + /// + /// The different panel types:

+ /// 0 : panelSignWithVideoAndImagePrefab

+ /// 1 : panelMultipleChoicePrefab

+ /// 2 : panelSignWithImagePrefab + ///
+ private Tuple FetchSign() + { + PersistentDataController.SavedLearnableProgress learnable = progress.GetRandomLearnable(); + int panelChosen; + if (course.theme.modelIndex == ModelIndex.NONE) + { + // only multiple choice works in preview mode + panelChosen = 1; + } + else if (learnable.progress > 2.0f) + { + panelChosen = 2; + } + else if (learnable.progress > 1.0f) + { + panelChosen = 1; + } + else + { + panelChosen = 0; + } + return Tuple.Create(learnable.index, panelChosen); + } + + /// + /// This function is called when the next-sign button is pressed. + /// It increased the wordindex and fetches new videos/images if index + public void NextSign() + { + // This function is also called (async) when pressing the 'Gebaar overslaan' button, + // so check for condition so we don't skip multiple signs + if (isNextSignInTransit || maxWords <= progress.completedLearnables) + return; + + progress.progress = (float)progress.completedLearnables / (float)maxWords; + progressBar.fillAmount = progress.progress; + + // Update UI if course is not finished yet + if (progress.completedLearnables < maxWords) + { + // Set next sign/video/image + StartCoroutine(CRNextSign()); + } + // Finish course and record progress + if (progress.completedLearnables == maxWords) + { + FinishCourse(); + } + } + + /// + /// Coroutine for going to the next sign + /// + /// + private IEnumerator CRNextSign() + { + isNextSignInTransit = true; + GameObject newPanel = SetupPanel(); + previousPanel.transform.SetAsFirstSibling(); + newPanel.GetComponent().SetTrigger("Slide Panel In"); + if (previousPanel != null) + previousPanel.GetComponent().SetTrigger("Slide Panel Out"); + + yield return new WaitForSeconds(1.0f); + + confettiAnimation.ResetTrigger("Display Confetti"); + GameObject.Destroy(previousPanel); + previousPanel = newPanel; + hasAnswered = false; + isNextSignInTransit = false; + } + + /// + /// Setup a new panel + /// + /// Reference to the GameObject of the panel + private GameObject SetupPanel() + { + (currentWordIndex, panelId) = FetchSign().ToValueTuple(); + switch (panelId) + { + case 0: + { + GameObject panel = GameObject.Instantiate(panelSignWithVideoAndImagePrefab, canvas); + panel.transform.SetAsFirstSibling(); + + PanelWithVideoAndImage script = panel.GetComponent(); + script.signs = course.theme.learnables; + script.currentSignIndex = currentWordIndex; + script.isPreview = (course.theme.modelIndex == ModelIndex.NONE); + script.videoPlayer = videoPlayer; + feedbackProgress = script.feedbackProgressBar; + feedbackProgressImage = script.feedbackProgressImage; + feedbackText = script.feedbackText; + script.Display(); + signPredictor.SwapScreen(script.webcamScreen); + courseTitle.text = "Voer het gebaar uit voor \"" + course.theme.learnables[currentWordIndex].name + "\""; + return panel; + } + case 1: + { + GameObject panel = GameObject.Instantiate(panelMultipleChoicePrefab, canvas); + panel.transform.SetAsFirstSibling(); + + PanelMultipleChoice script = panel.GetComponent(); + script.signs = course.theme.learnables; + script.currentSignIndex = currentWordIndex; + script.videoPlayer = videoPlayer; + script.courseController = this; + script.progress = progress; + script.isFingerSpelling = course.theme.title == "Handalfabet"; + script.Display(); + signPredictor.SwapScreen(script.webcamScreen); + courseTitle.text = "Welk gebaar zie je hier?"; + return panel; + } + case 2: + { + GameObject panel = GameObject.Instantiate(panelSignWithImagePrefab, canvas); + panel.transform.SetAsFirstSibling(); + + PanelWithImage script = panel.GetComponent(); + script.signs = course.theme.learnables; + script.currentSignIndex = currentWordIndex; + script.isPreview = (course.theme.modelIndex == ModelIndex.NONE); + feedbackProgress = script.feedbackProgressBar; + feedbackProgressImage = script.feedbackProgressImage; + feedbackText = script.feedbackText; + script.Display(); + signPredictor.SwapScreen(script.webcamScreen); + courseTitle.text = "Voer het gebaar uit voor \"" + course.theme.learnables[currentWordIndex].name + "\""; + return panel; + } + } + return null; + } + + /// + /// finishcourse is called to save the "finished" progress to the user. + /// + public void FinishCourse() + { + // Show the "finished" screen + ResultPanel.SetActive(true); + + // Set the correct title + ResultsTitle.text = course.title + " voltooid!"; + + // Set the correct description + ResultsDecription.text = "Goed gedaan! Je kan nu spelletjes spelen met " + course.title + " om verder te oefenen!"; + + // Set the total time spent UI + TimeSpan time = DateTime.Now - startMoment; + timeSpent.text = time.ToString(@"hh\:mm\:ss"); + + // Link button + CoursesButton.onClick.AddListener(() => { SystemController.GetInstance().BackToPreviousScene(); }); + + progress.progress = 1.0f; + UserList.Save(); + } + + /// + /// The updateFunction that is called when new probabilities become available + /// + /// + protected override IEnumerator UpdateFeedback() + { + // Check if the current word index is still in bounds, and if the current panel type is not multiple choice + if (currentWordIndex < course.theme.learnables.Count && panelId != 1 && !hasAnswered) + { + // Get current sign + Learnable sign = course.theme.learnables[currentWordIndex]; + string currentSign = sign.name.ToUpper().Replace(" ", "-"); + + // Get the predicted sign + if (signPredictor != null && signPredictor.learnableProbabilities != null && + currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign)) + { + //Debug.Log($"{signPredictor.learnableProbabilities.Aggregate("", (t, e) => $"{t}{e.Key}={e.Value}, ")}"); + float accCurrentSign = signPredictor.learnableProbabilities[currentSign]; + + // Get highest predicted sign + string predictedSign = signPredictor.learnableProbabilities.Aggregate((a, b) => a.Value > b.Value ? a : b).Key; + float accPredictSign = signPredictor.learnableProbabilities[predictedSign]; + Learnable predSign = course.theme.learnables.Find(l => l.name.ToUpper().Replace(" ", "-") == predictedSign); + + // If there is a feedback-object, we wil change its appearance + if (feedbackText != null && feedbackProgressImage != null) + { + Color col; + if (accCurrentSign > sign.thresholdPercentage) + { + feedbackText.text = "Goed"; + col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); + } + else if (accCurrentSign > 0.9 * sign.thresholdPercentage) + { + feedbackText.text = "Bijna"; + col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f); + } + else if (accPredictSign > predSign.thresholdPercentage) + { + feedbackText.text = $"Verkeerde gebaar: '{predSign.name}'"; + col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + accCurrentSign = 0.0f; + } + else + { + feedbackText.text = $"Detecteren ..."; + col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + //accCurrentSign = 0.0f; + } + + feedbackText.color = col; + feedbackProgressImage.color = col; + + // Tween the feedback-bar + float oldValue = feedbackProgress.value; + // use an exponential scale + float newValue = Mathf.Exp(4 * (Mathf.Clamp(accCurrentSign / sign.thresholdPercentage, 0.0f, 1.0f) - 1.0f)); + feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) => + { + if (feedbackProgress != null) + { + feedbackProgress.value = t.CurrentValue; + } + }); + } + + // The internal logic for the courses + if (accPredictSign > sign.thresholdPercentage) + { + // Correct sign + if (predictedSign == currentSign) + { + yield return new WaitForSeconds(1.0f); + NextSignIfCorrect(currentSign, predictedSign); + timer = DateTime.Now; + previousIncorrectSign = null; + predictedSign = null; + } + // Incorrect sign + else + { + if (previousIncorrectSign != predictedSign) + { + timer = DateTime.Now; + previousIncorrectSign = predictedSign; + } + else if (predictedSign != null && currentSign != null && + (DateTime.Now - timer).TotalSeconds > 2.0f) + { + NextSignIfCorrect(currentSign, predictedSign); + timer = DateTime.Now; + predictedSign = null; + previousIncorrectSign = null; + } + } + } + } + else if (feedbackProgress != null) + { + feedbackProgress.value = 0.0f; + } + } + } + + /// + /// Function to check equality between the current sign and the sign that the model predicted, if they are equal then the next sign is fetched. + /// + /// + public void NextSignIfCorrect(string current, string predicted) + { + if (!hasAnswered) + { + if (current == predicted) + { + hasAnswered = true; + var p = progress.learnables.Find((l) => l.name.ToUpper().Replace(" ", "-") == predicted); + progress.UpdateLearnable(p.name, 1.5f); + confettiAnimation.SetTrigger("Display Confetti"); + StartCoroutine(WaitNextSign()); + } + else + { + // currently ignore wrong signs as "J" doesn't work well enough + } + } + + } + + private IEnumerator WaitNextSign() + { + // Wait for 0.75 seconds + yield return new WaitForSeconds(0.75f); + NextSign(); + } + + /// + /// Function to check equality between the current sign and the sign that the model predicted, if they are equal then the next sign is fetched. + /// + /// + public void NextSignMultipleChoice(string current, string predicted) + { + if (!hasAnswered) + { + hasAnswered = true; + if (current == predicted) + { + progress.UpdateLearnable(predicted, 1.5f); + confettiAnimation.SetTrigger("Display Confetti"); + } + else + { + progress.UpdateLearnable(predicted, -1.0f); + } + } + } + + /// + /// Callback for the 'back' button + /// + public void ReturnToActivityScreen() + { + UserList.Save(); + SystemController.GetInstance().BackToPreviousScene(); + } +} diff --git a/Assets/Courses/Scripts/TemplateCourse.cs.meta b/Assets/Courses/Scripts/CoursesController.cs.meta similarity index 100% rename from Assets/Courses/Scripts/TemplateCourse.cs.meta rename to Assets/Courses/Scripts/CoursesController.cs.meta diff --git a/Assets/Courses/Scripts/PanelMultipleChoice.cs b/Assets/Courses/Scripts/PanelMultipleChoice.cs new file mode 100644 index 0000000..3a940a1 --- /dev/null +++ b/Assets/Courses/Scripts/PanelMultipleChoice.cs @@ -0,0 +1,216 @@ +using System.Collections; +using System.Collections.Generic; +using TMPro; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.Video; + + +public class PanelMultipleChoice : MonoBehaviour +{ + /// + /// Reference to the webcam screen + /// + public RawImage webcamScreen; + + /// + /// Video 'play' sprite + /// + public Sprite playSprite; + + /// + /// Video 'pause' sprite + /// + public Sprite pauseSprite; + + /// + /// Reference to its course controller to be able to go to call NextSignMultipleChoice to go to the next panel + /// + public CoursesController courseController; + + /// + /// Reference to instructional video player + /// + public VideoPlayer videoPlayer; + + /// + /// Refrence to the video play/pause button + /// + public Image playButton; + + /// + /// Reference to the image for displaying the current words sprite + /// + public Transform optionContainer; + + /// + /// Reference to the image for displaying the current words sprite, for a fingerspelling courses + /// + public Transform optionFingerspellingContainer; + + /// + /// Reference to the option prefab + /// + public GameObject optionPrefab; + + /// + /// Reference to the option prefab, for a fingerspelling course + /// + public GameObject optionFingerspellingPrefab; + + /// + /// Reference to the saved progress + /// + public PersistentDataController.SavedCourseProgress progress; + + /// + /// The current sign that will be displayed + /// + private Learnable currentSign; + + /// + /// Reference to all signs in this course + /// + public List signs; + + /// + /// Index of the current sign + /// + public int currentSignIndex; + + /// + /// Boolean used to check whether the current course is a fingerspelling course + /// + public bool isFingerSpelling; + + /// + /// Boolean used to check whether the user has already answered the question + /// + private bool hasAnswered = false; + + /// + /// Get a list of wrongs answers + /// + /// The index of the correct sign + /// + public List GetWrongOptions(int notThisIndex) + { + List randomSigns = new List(); + // TODO: find more koosjer way to do this + while (randomSigns.Count < 3) + { + int index = progress.GetRandomLearnable().index; + if (index != notThisIndex && !randomSigns.Contains(signs[index])) + { + randomSigns.Add(signs[index]); + } + } + + return randomSigns; + } + + /// + /// Update the display of this panel + /// + public void Display() + { + currentSign = signs[currentSignIndex]; + videoPlayer.aspectRatio = VideoAspectRatio.FitInside; + videoPlayer.clip = currentSign.clip; + videoPlayer.Play(); + // Gets three random selected signs from the list signs which are not equal to currentSign + List allOptions = GetWrongOptions(currentSignIndex); + + // Add the correct sign at a random position in the list of all options + int randomIndex = UnityEngine.Random.Range(0, allOptions.Count + 1); + allOptions.Insert(randomIndex, currentSign); + + var prefab = isFingerSpelling ? optionFingerspellingPrefab : optionPrefab; + var container = isFingerSpelling ? optionFingerspellingContainer : optionContainer; + foreach (Learnable option in allOptions) + { + GameObject multipleChoiceOption = GameObject.Instantiate(prefab, container); + if (!isFingerSpelling) + multipleChoiceOption.transform.Find("TextOption").GetComponent().text = option.name; + multipleChoiceOption.transform.Find("ImageOption").GetComponent().sprite = option.image; + + Button button = multipleChoiceOption.GetComponent @@ -57,11 +41,45 @@ public class JustSignController : MonoBehaviour ///
private Song currentSong; + /// + /// Reference to the perfect hitzone + /// + public RectTransform hitZonePerfect; /// - /// The zone that the player should be hitting with his or her inputs + /// Reference to the good hitzone /// - public GameObject hitZone; + public RectTransform hitZoneGood; + + /// + /// Reference to the meh hitzone + /// + public RectTransform hitZoneMeh; + + /// + /// Score obtained when getting a perfect hit + /// + private int perfectScore = 50; + + /// + /// Score obtained when getting a good hit + /// + private int goodScore = 20; + + /// + /// Score obtained when getting a meh hit + /// + private int mehScore = 10; + + /// + /// Score obtained when getting a terrible hit + /// + private int terribleScore = -3; + + /// + /// Score obtained when symbol goes offscreen + /// + private int offscreenScore = -5; /// /// Symbol prefab @@ -88,75 +106,20 @@ public class JustSignController : MonoBehaviour /// private List activeSymbols = new List(); - /// - /// The current score - /// - private int score; - - /// - /// Have the symbols started spawning or not - /// - private bool gameIsActive = false; - - /// - /// Width and height of the symbols - /// - private int symbolSize = 280; - /// /// Controls movement speed of symbols (higher -> faster) /// - private int moveSpeed = 200; - + private int moveSpeed = 100; + /// /// Starting X-coordinate of a symbol = (-1920 - symbolsize) / 2 /// - private int trackX = -1100; + private int trackX = 1920 / 2; /// /// Starting Y-coordinate of a symbol /// - private int trackY = -200; - - /// - /// Max distance from hit zone to get perfect score - /// - private int perfectBoundary = 10; - - /// - /// Score obtained when getting a perfect hit - /// - private int perfectScore = 5; - - /// - /// Max distance from hit zone to get good score - /// - private int goodBoundary = 120; - - /// - /// Score obtained when getting a good hit - /// - private int goodScore = 3; - - /// - /// Max distance from hit zone to get meh score - /// - private int mehBoundary = 200; - - /// - /// Score obtained when getting a meh hit - /// - private int mehScore = 1; - - /// - /// Score obtained when getting a terrible hit - /// - private int terribleScore = -3; - - /// - /// Score obtained when symbol goes offscreen - /// - private int offscreenScore = -5; + private int trackY = 0; /// /// Time at which the last symbol was spawned @@ -198,31 +161,6 @@ public class JustSignController : MonoBehaviour /// private int incorrectSigns; - /// - /// Reference to the scoreboard entries container - /// - public Transform scoreboardEntriesContainer; - - /// - /// The GameObjects representing the letters - /// - private List scoreboardEntries = new List(); - - /// - /// Reference to the ScoreboardEntry prefab - /// - public GameObject scoreboardEntry; - - /// - /// Reference to the user list to access the current user - /// - public UserList userList; - - /// - /// Reference to the current user - /// - private User user; - /// /// LPM /// @@ -259,45 +197,58 @@ public class JustSignController : MonoBehaviour public TMP_Text scoreText; /// - /// Reference to the gameEnded panel, so we can update its display + /// Reference to the feedback field /// - public GameObject gameEndedPanel; + public TMP_Text feedbackText; /// - /// Start is called before the first frame update + /// Reference to the progress bar image, so we can add fancy colors /// - public void Start() + public Image feedbackProgressImage; + + /// + /// Sprite shown when perfect score + /// + public Sprite perfectSprite; + + /// + /// Sprite shown when good score + /// + public Sprite goodSprite; + + /// + /// Sprite shown when meh score + /// + public Sprite mehSprite; + + /// + /// Sprite shown when terrible score (too soon) + /// + public Sprite terribleSprite; + + /// + /// Sprite shown when sign leaves screen + /// + public Sprite tooLateSprite; + + /// + /// Reference to display the feedback image + /// + public Image imageFeedback; + + /// + /// Message to display when there is no model + /// + public GameObject previewMessage; + + /// + /// Reference to the score, feedback and image + /// + public GameObject userFeedback; + + protected override Theme signPredictorTheme { - perfectSigns = 0; - goodSigns = 0; - mehSigns = 0; - terribleSigns = 0; - incorrectSigns = 0; - score = 0; - gameEndedPanel.SetActive(false); - // Create entry in current user for keeping track of progress - userList.Load(); - user = userList.GetCurrentUser(); - Progress progress = user.GetMinigameProgress(minigame.index); - if (progress == null) - { - progress = new Progress(); - progress.AddOrUpdate("minigameIndex", minigame.index); - progress.AddOrUpdate>("highestScores", new List()); - progress.AddOrUpdate>("latestScores", new List()); - user.minigames.Add(progress); - } - userList.Save(); - - scoreDisplay.text = "Score: " + score.ToString(); - currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex]; - words.AddRange(currentTheme.learnables); - currentSong = songList.songs[songList.currentSongIndex]; - AudioSource.PlayClipAtPoint(currentSong.song, Vector3.zero, 1.0f); - beginTime = Time.time; - lastSymbolTime = beginTime + currentSong.duration - 1920.0f / moveSpeed; - - StartCoroutine(WaitThenStart(currentSong.firstSymbolTime)); + get { return currentTheme; } } /// @@ -314,94 +265,62 @@ public class JustSignController : MonoBehaviour /// Update is called once per frame /// void Update() - { - if (gameIsActive) { - int matchedSymbolIndex = -1; - for (int i = 0; i < activeWords.Count; i++) { - if (activeWords[i].ToLower() == answerField.text.ToLower()) { - matchedSymbolIndex = i; - } - } - - // Destroy the oldest symbol if the current input matches it - if (matchedSymbolIndex >= 0) { - int difference = Math.Abs((int) (activeSymbols[matchedSymbolIndex].transform.position.x - hitZone.transform.position.x)); - if (difference < perfectBoundary) { - feedBack.text = "Perfect!"; - perfectSigns++; - score += perfectScore; - } else if (difference < goodBoundary) { - feedBack.text = "Good!"; - goodSigns++; - score += goodScore; - } else if (difference < mehBoundary) { - feedBack.text = "Meh..."; - mehSigns++; - score += mehScore; - } else { - feedBack.text = "Terrible!"; - terribleSigns++; - score += terribleScore; - } - - DestroySymbolAt(matchedSymbolIndex); - answerField.text = ""; - } - + { + if (gameIsActive) + { // Destroy the oldest symbol if it leaves the screen - if (activeSymbols.Count > 0) { - if (activeSymbols[0].GetComponent().localPosition.x > -trackX) { + if (activeSymbols.Count > 0) + { + if (activeSymbols[0].GetComponent().localPosition.x > trackX) + { DestroySymbolAt(0); incorrectSigns++; - feedBack.text = "Te laat!"; - score += offscreenScore; + timingFeedback.text = $"Te laat! \n {offscreenScore}"; + imageFeedback.sprite = tooLateSprite; } } // Spawn new symbol every spawn period float currentTime = Time.time; - if (currentTime - lastSpawn > currentSong.spawnPeriod && lastSymbolTime > currentTime) { + if (currentTime - lastSpawn > currentSong.spawnPeriod && lastSymbolTime > currentTime) + { lastSpawn = currentTime; SpawnNewSymbol(); } // Check if the song has ended and activate scorescreen if it has - if (currentTime - beginTime > currentSong.duration) { - ActivateEnd(); + if (currentTime - beginTime > currentSong.duration) + { + // The boolean that is passed is irrelevant for this game + ActivateEnd(true); } // Move all active symbols to the right - foreach (GameObject symbol in activeSymbols) { + foreach (GameObject symbol in activeSymbols) + { RectTransform rectTransform = symbol.GetComponent(); rectTransform.localPosition = new Vector3(rectTransform.localPosition.x + Time.deltaTime * moveSpeed, trackY, 0); } - scoreDisplay.text = "Score: " + score.ToString(); + scoreDisplay.text = $"Score: {CalculateScore()}"; } } /// - /// Display Scoreboard + Metrics + /// Calculate the score /// - public void ActivateEnd() + /// The calculated score + public override int CalculateScore() { - gameIsActive = false; - while (activeSymbols.Count > 0) - { - DestroySymbolAt(0); - } - // TODO: Scoreboard - SaveScores(); - SetScoreMetrics(); - SetScoreBoard(); - gameEndedPanel.SetActive(true); + return goodSigns * goodScore + perfectSigns * perfectScore + mehScore * mehSigns + terribleScore * terribleSigns + incorrectSigns * offscreenScore; } /// /// Destroy the symbol at the given index /// /// The index of the symbol to destroy - void DestroySymbolAt(int index) { + void DestroySymbolAt(int index) + { activeWords.RemoveAt(index); GameObject symbol = activeSymbols[index]; activeSymbols.RemoveAt(index); @@ -411,198 +330,191 @@ public class JustSignController : MonoBehaviour /// /// Create a new symbol at the start of the track /// - void SpawnNewSymbol() { + void SpawnNewSymbol() + { // Pick a word that isn't in use yet List unusedWordIndices = new List(); - for (int i = 0; i < words.Count; i++) { - if (!activeWords.Contains(words[i].name)) { + for (int i = 0; i < words.Count; i++) + { + if (!activeWords.Contains(words[i].name)) + { unusedWordIndices.Add(i); } } - Learnable newLearnable = words[unusedWordIndices[UnityEngine.Random.Range(0, unusedWordIndices.Count)]]; + Learnable newLearnable = words[unusedWordIndices[Random.Range(0, unusedWordIndices.Count)]]; string nextSymbol = newLearnable.name; - GameObject newSymbolObject = GameObject.Instantiate(symbolPrefab, symbolContainer); + GameObject newSymbolObject = GameObject.Instantiate(symbolPrefab, new Vector3(0, trackY, 0), Quaternion.identity, symbolContainer); // Dynamically load appearance - Image image = newSymbolObject.GetComponent(); + Image image = newSymbolObject.transform.Find("Image").GetComponent(); image.sprite = newLearnable.image; - image.rectTransform.sizeDelta = new Vector2(symbolSize, symbolSize); // Place the word that the symbol represents under the image TMP_Text text = newSymbolObject.GetComponentInChildren(); text.text = nextSymbol; - text.color = Color.black; - text.rectTransform.localPosition = new Vector3(0, -160, 0); - activeWords.Add(nextSymbol); + activeWords.Add(nextSymbol.ToUpper()); activeSymbols.Add(newSymbolObject); } /// - /// Update and save the scores + /// The logic to process the signs sent by the signPredictor /// - public void SaveScores() + /// The accuracy of the passed sign + /// The name of the passed sign + protected override void ProcessMostProbableSign(float accuracy, string predictedSign) { - // Calculate new score - int newScore = this.score; + Learnable predSign = currentTheme.learnables.Find(l => l.name.ToUpper() == predictedSign); - // Save the score as a tuple: < int score, string time ago> - Score score = new Score(); - score.scoreValue = newScore; - score.time = DateTime.Now.ToString(); - - // Save the new score - user = userList.GetCurrentUser(); - Progress progress = user.GetMinigameProgress(minigame.index); - - // Get the current list of scores - List latestScores = progress.Get>("latestScores"); - List highestScores = progress.Get>("highestScores"); - - // Add the new score - latestScores.Add(score); - highestScores.Add(score); - - // Sort the scores - highestScores.Sort((a, b) => b.scoreValue.CompareTo(a.scoreValue)); - - // Only save the top 10 scores, so this list doesn't keep growing endlessly - progress.AddOrUpdate>("latestScores", latestScores.Take(10).ToList()); - progress.AddOrUpdate>("highestScores", highestScores.Take(10).ToList()); - - userList.Save(); - } - - /// - /// Set score metrics - /// - private void SetScoreMetrics() - { - // In de zone - perfectSignsText.text = perfectSigns.ToString(); - - // Aanvaardbaar - goodSignsText.text = goodSigns.ToString(); - - // Nipt - mehSignsText.text = mehSigns.ToString(); - - // Slechte timing - terribleSignsText.text = terribleSigns.ToString(); - - // Niet Geraden - notFoundSignsText.text = incorrectSigns.ToString(); - - // LPM - int duration = songList.songs[songList.currentSongIndex].duration; - int correctSigns = goodSigns + perfectSigns + mehSigns + terribleSigns; - lpmText.text = (60f * correctSigns / duration).ToString("#") + " GPM"; - - // Score - scoreText.text = "Score: " + score.ToString(); - } - - /// - /// Sets the scoreboard - /// - private void SetScoreBoard() - { - // Clean the previous scoreboard entries - for (int i = 0; i < scoreboardEntries.Count; i++) + // If there is a feedback-object, we wil change its appearance + if (feedbackText != null && feedbackProgressImage != null) { - Destroy(scoreboardEntries[i]); - } - scoreboardEntries.Clear(); - - // Instantiate new entries - // Get all scores from all users - List> allScores = new List>(); - foreach (User user in userList.GetUsers()) - { - // Get user's progress for this minigame - Progress progress = user.GetMinigameProgress(minigame.index); - if (progress != null) + Color col; + if (accuracy > predSign.thresholdPercentage) { - // Add scores to dictionary - List scores = progress.Get>("highestScores"); - foreach (Score score in scores) - { - allScores.Add(new Tuple(user.username, score)); - } + feedbackText.text = $"Herkent '{predictedSign}'"; + col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); } - } - - // Sort allScores based on Score.scoreValue - allScores.Sort((a, b) => b.Item2.scoreValue.CompareTo(a.Item2.scoreValue)); - - // Instantiate scoreboard entries - int rank = 1; - foreach (Tuple tup in allScores.Take(10)) - { - string username = tup.Item1; - Score score = tup.Item2; - - GameObject entry = Instantiate(scoreboardEntry, scoreboardEntriesContainer); - scoreboardEntries.Add(entry); - - // Set the player icon - entry.transform.Find("Image").GetComponent().sprite = userList.GetUserByUsername(username).avatar; - - // Set the player name - entry.transform.Find("PlayerName").GetComponent().text = username; - - // Set the score - entry.transform.Find("Score").GetComponent().text = score.scoreValue.ToString(); - - // Set the rank - entry.transform.Find("Rank").GetComponent().text = rank.ToString(); - - // Set the ago - // Convert the score.time to Datetime - DateTime time = DateTime.Parse(score.time); - DateTime currentTime = DateTime.Now; - TimeSpan diff = currentTime.Subtract(time); - - string formatted; - if (diff.Days > 0) + else if (accuracy > 0.9 * predSign.thresholdPercentage) { - formatted = $"{diff.Days}d "; - } - else if (diff.Hours > 0) - { - formatted = $"{diff.Hours}h "; - } - else if (diff.Minutes > 0) - { - formatted = $"{diff.Minutes}m "; + feedbackText.text = $"Lijkt op '{predictedSign}'"; + col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f); } else { - formatted = "now"; + feedbackText.text = "Detecteren..."; + col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); } - entry.transform.Find("Ago").GetComponent().text = formatted; + feedbackText.color = col; + feedbackProgressImage.color = col; - - // Alternating colors looks nice - if (rank % 2 == 0) + float oldValue = feedbackProgress.value; + // use an exponential scale + float newValue = Mathf.Exp(4 * (Mathf.Clamp(accuracy / predSign.thresholdPercentage, 0.0f, 1.0f) - 1.0f)); + feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) => { - Image image = entry.transform.GetComponent(); - image.color = new Color(image.color.r, image.color.g, image.color.b, 0f); - } + if (feedbackProgress != null) + { + feedbackProgress.value = t.CurrentValue; + } + }); + } - // Make new score stand out - if (diff.TotalSeconds < 1) + // The logic for the internal workings of the game + if (accuracy > predSign.thresholdPercentage) + { + int matchedSymbolIndex = activeWords.IndexOf(predictedSign.ToUpper()); + + // Destroy the oldest symbol if the current input matches it + if (0 <= matchedSymbolIndex) { - Image image = entry.transform.GetComponent(); - image.color = new Color(0, 229, 255, 233); - } + float x = activeSymbols[matchedSymbolIndex].transform.localPosition.x; - rank++; + // parameters to define the Perfect hit zone + float perfectRange = hitZonePerfect.sizeDelta.x; + float perfectCenter = hitZonePerfect.localPosition.x; + // parameters to define the Good hit zone + float goodRange = hitZoneGood.sizeDelta.x; + float goodCenter = hitZoneGood.localPosition.x; + // parameters to define the Meh hit zone + float mehRange = hitZoneMeh.sizeDelta.x; + float mehCenter = hitZoneMeh.localPosition.x; + + if (perfectCenter - perfectRange / 2 <= x && x <= perfectCenter + perfectRange / 2) + { + timingFeedback.text = $"Perfect! \n +{perfectScore}"; + imageFeedback.sprite = perfectSprite; + perfectSigns++; + timingFeedback.color = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); + } + else if (goodCenter - goodRange / 2 <= x && x <= goodCenter + goodRange / 2) + { + timingFeedback.text = $"Goed \n +{goodScore}"; + imageFeedback.sprite = goodSprite; + goodSigns++; + timingFeedback.color = new Color(0xf7 / 255.0f, 0xad / 255.0f, 0x19 / 255.0f); + } + else if (mehCenter - mehRange / 2 <= x && x <= mehCenter + mehRange / 2) + { + timingFeedback.text = $"Bijna... \n +{mehScore}"; + imageFeedback.sprite = mehSprite; + mehSigns++; + timingFeedback.color = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f); + } + else + { + timingFeedback.text = $"Te vroeg! \n {terribleScore}"; + imageFeedback.sprite = terribleSprite; + terribleSigns++; + timingFeedback.color = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + } + + DestroySymbolAt(matchedSymbolIndex); + } } } + /// + /// The logic to set the scoreboard of justsign + /// + /// Shows whether or not the player won, is not relevant for JustSIgn + protected override void SetScoreBoard(bool victory) + { + gameEndedPanel.GetComponent().GenerateContent( + perfectSigns: perfectSigns, + goodSigns: goodSigns, + mehSigns: mehSigns, + terribleSigns: terribleSigns, + incorrectSigns: incorrectSigns, + duration: currentSong.duration, + score: CalculateScore() + ); + } + + /// + /// The justsign-specific logic that needs to be called at the start of the game + /// + protected override void StartGameLogic() + { + // Set the current theme so that it can be passed along + + currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex]; + + userFeedback.SetActive(currentTheme.modelIndex != ModelIndex.NONE); + previewMessage.SetActive(currentTheme.modelIndex == ModelIndex.NONE); + perfectSigns = 0; + goodSigns = 0; + mehSigns = 0; + terribleSigns = 0; + incorrectSigns = 0; + timingFeedback.text = ""; + imageFeedback.sprite = minigame.thumbnail; + gameEndedPanel.SetActive(false); + + scoreDisplay.text = $"Score: {CalculateScore()}"; + words.AddRange(currentTheme.learnables); + currentSong = songList.songs[songList.currentSongIndex]; + AudioSource.PlayClipAtPoint(currentSong.song, Vector3.zero, 1.0f); + beginTime = Time.time; + lastSymbolTime = beginTime + currentSong.duration - 1920.0f / moveSpeed; + + StartCoroutine(WaitThenStart(currentSong.firstSymbolTime)); + } + + /// + /// The justsign-specific logic that needs to be called at the end of a game + /// + /// + protected override void EndGameLogic(bool victory) + { + gameIsActive = false; + while (activeSymbols.Count > 0) + { + DestroySymbolAt(0); + } + } } diff --git a/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs b/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs new file mode 100644 index 0000000..f54de98 --- /dev/null +++ b/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using TMPro; +using UnityEngine; +using UnityEngine.UI; +/// +/// The JustSign-variant of the ScoreBoard +/// +public class JustSignGameEndedPanel : AbstractGameEndedPanel +{ + /// + /// Tell the scoreboard that the scoreboard is for JustSign + /// + protected override MinigameIndex minigameIndex + { + get { return MinigameIndex.JUST_SIGN; } + } + + /// + /// The field that will display the amount of perfect signs + /// + public TMP_Text perfectSignsText; + + /// + /// The field that will display the amount of good signs + /// + public TMP_Text goodSignsText; + + /// + /// The field that will display the amount of meh signs + /// + public TMP_Text mehSignsText; + + /// + /// The field that will display the amount of terrible signs + /// + public TMP_Text terribleSignsText; + + /// + /// The field that will display the amount of not found signs + /// + public TMP_Text notFoundSignsText; + + /// + /// The field that will display the signs per minute + /// + public TMP_Text gpmText; + + /// + /// Score + /// + public TMP_Text scoreText; + + /// + /// Generate the content of the gameEnded panel + /// + /// The amount of perfect signs + /// The amount of good signs + /// The amount of meh signs + /// The emount of terrible signs + /// The amount of incorrect signs + /// The duration of the song that was played + /// The score obtained by the player + public void GenerateContent(int perfectSigns, int goodSigns, int mehSigns, int terribleSigns, int incorrectSigns, int duration, int score) + { + // In de zone + perfectSignsText.text = perfectSigns.ToString(); + + // Aanvaardbaar + goodSignsText.text = goodSigns.ToString(); + + // Nipt + mehSignsText.text = mehSigns.ToString(); + + // Slechte timing + terribleSignsText.text = terribleSigns.ToString(); + + // Niet Geraden + notFoundSignsText.text = incorrectSigns.ToString(); + + // LPM + int correctSigns = goodSigns + perfectSigns + mehSigns + terribleSigns; + gpmText.text = (60f * correctSigns / duration).ToString("#") + " GPM"; + + // Score + scoreText.text = $"Score: {score}"; + SetScoreBoard(); + } +} diff --git a/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs.meta b/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs.meta new file mode 100644 index 0000000..8ceccbe --- /dev/null +++ b/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a86c239be1aa1543ba8a4ace5f658b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/JustSign/Scripts/JustSignScripts.asmdef b/Assets/JustSign/Scripts/JustSignScripts.asmdef new file mode 100644 index 0000000..8db4bcf --- /dev/null +++ b/Assets/JustSign/Scripts/JustSignScripts.asmdef @@ -0,0 +1,22 @@ +{ + "name": "JustSignScripts", + "rootNamespace": "", + "references": [ + "GUID:e83ddf9a537a96b4a804a16bb7872ec1", + "GUID:6055be8ebefd69e48b49212b09b47b2f", + "GUID:1631ed2680c61245b8211d943c1639a8", + "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25", + "GUID:58e104b97fb3752438ada2902a36dcbf", + "GUID:d0b6b39a21908f94fbbd9f2c196a9725", + "GUID:403dd94a93598934eb522dc36df43d7b" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/Burst/Unity.Barracuda.BurstBLAS.asmdef.meta b/Assets/JustSign/Scripts/JustSignScripts.asmdef.meta similarity index 76% rename from Packages/com.unity.barracuda/Runtime/Plugins/Burst/Unity.Barracuda.BurstBLAS.asmdef.meta rename to Assets/JustSign/Scripts/JustSignScripts.asmdef.meta index ef32c0d..1a4de81 100644 --- a/Packages/com.unity.barracuda/Runtime/Plugins/Burst/Unity.Barracuda.BurstBLAS.asmdef.meta +++ b/Assets/JustSign/Scripts/JustSignScripts.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2fab472a0d46c4307939f2d23202cd1b +guid: 643048e31db889c4c8ab5a04e9a70473 AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Assets/JustSign/Scripts/JustSignWebcam.cs b/Assets/JustSign/Scripts/JustSignWebcam.cs deleted file mode 100644 index 8a1f4bb..0000000 --- a/Assets/JustSign/Scripts/JustSignWebcam.cs +++ /dev/null @@ -1,72 +0,0 @@ -using UnityEngine; -using UnityEngine.UI; - -/// -/// Class to manage all webcam stuff inside the SpellingBee minigame -/// -public class JustSignWebcam : MonoBehaviour -{ - /// - /// Index of the current camera - /// - int camdex = 0; - - /// - /// Texture to paste on the display - /// - WebCamTexture tex; - - /// - /// Display for the video feed - /// - public RawImage display; - - /// - /// Setup the webcam correctly - /// - void Awake() - { - WebCamDevice device = WebCamTexture.devices[camdex]; - tex = new WebCamTexture(device.name); - display.texture = tex; - - tex.Play(); - } - - /// - /// Swap webcam by cycling through the `WebCamTexture.devices` list - /// - public void SwapCam() - { - if (WebCamTexture.devices.Length > 0) - { - // Stop the old camera - display.texture = null; - tex.Stop(); - tex = null; - - // Find the new camera - camdex += 1; - camdex %= WebCamTexture.devices.Length; - - // Start the new camera - WebCamDevice device = WebCamTexture.devices[camdex]; - tex = new WebCamTexture(device.name); - display.texture = tex; - - tex.Play(); - } - } - - /// - /// Scene changing is implemented here to avoid problems with webcam - /// - public void GotoThemeSelection() - { - display.texture = null; - tex.Stop(); - tex = null; - - SystemController.GetInstance().BackToPreviousScene(); - } -} diff --git a/Assets/JustSign/Scripts/JustSignWebcam.cs.meta b/Assets/JustSign/Scripts/JustSignWebcam.cs.meta deleted file mode 100644 index 0f20cdc..0000000 --- a/Assets/JustSign/Scripts/JustSignWebcam.cs.meta +++ /dev/null @@ -1,13 +0,0 @@ -fileFormatVersion: 2 -guid: d9291edb7593521fbb7e0a486724fd3c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: - - minigameList: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} - - display: {instanceID: 0} - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/JustSign/Songs/We Will Rock You - 1min.mp3 b/Assets/JustSign/Songs/We Will Rock You - 1min.mp3 new file mode 100644 index 0000000..eba3ce3 Binary files /dev/null and b/Assets/JustSign/Songs/We Will Rock You - 1min.mp3 differ diff --git a/Assets/JustSign/Songs/We Will Rock You - 1min.mp3.meta b/Assets/JustSign/Songs/We Will Rock You - 1min.mp3.meta new file mode 100644 index 0000000..38d5ee5 --- /dev/null +++ b/Assets/JustSign/Songs/We Will Rock You - 1min.mp3.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: d2d246582fe87b54cbca0e1a5b0f739f +AudioImporter: + externalObjects: {} + serializedVersion: 6 + defaultSettings: + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + preloadAudioData: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/JustSign/Songs/We Will Rock You - 30sec.mp3 b/Assets/JustSign/Songs/We Will Rock You - 30sec.mp3 new file mode 100644 index 0000000..d305fc4 Binary files /dev/null and b/Assets/JustSign/Songs/We Will Rock You - 30sec.mp3 differ diff --git a/Assets/JustSign/Songs/We Will Rock You - 30sec.mp3.meta b/Assets/JustSign/Songs/We Will Rock You - 30sec.mp3.meta new file mode 100644 index 0000000..e1d913b --- /dev/null +++ b/Assets/JustSign/Songs/We Will Rock You - 30sec.mp3.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: 67374b610386f4840b84569282792772 +AudioImporter: + externalObjects: {} + serializedVersion: 6 + defaultSettings: + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + preloadAudioData: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/JustSign/Songs/We Will Rock You.mp3 b/Assets/JustSign/Songs/We Will Rock You.mp3 new file mode 100644 index 0000000..507e2b9 Binary files /dev/null and b/Assets/JustSign/Songs/We Will Rock You.mp3 differ diff --git a/Assets/JustSign/Songs/We Will Rock You.mp3.meta b/Assets/JustSign/Songs/We Will Rock You.mp3.meta new file mode 100644 index 0000000..c266694 --- /dev/null +++ b/Assets/JustSign/Songs/We Will Rock You.mp3.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: c6d598be536f9cb4585670869e7041bd +AudioImporter: + externalObjects: {} + serializedVersion: 6 + defaultSettings: + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + preloadAudioData: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MediaPipeUnity/Common/Scripts/KeypointManager.cs b/Assets/MediaPipeUnity/Common/Scripts/KeypointManager.cs index 6a27b87..811e198 100644 --- a/Assets/MediaPipeUnity/Common/Scripts/KeypointManager.cs +++ b/Assets/MediaPipeUnity/Common/Scripts/KeypointManager.cs @@ -74,12 +74,15 @@ public class KeypointManager } - if (width > height){ - delta_x = ((float)0.1)*width; - delta_y = delta_x + ((width - height)/2); - }else{ - delta_y = ((float)0.1)*height; - delta_x = delta_y + ((height - width)/2); + if (width > height) + { + delta_x = ((float)0.1) * width; + delta_y = delta_x + ((width - height) / 2); + } + else + { + delta_y = ((float)0.1) * height; + delta_x = delta_y + ((height - width) / 2); } float starting_x = min_x - delta_x; @@ -124,10 +127,10 @@ public class KeypointManager float eye_left_x = pose_x[1]; float eye_left_y = pose_y[1]; - float starting_x = shoulder_center_x - (bbox_size/2) * shoulder_distance; - float starting_y = eye_left_y - shoulder_distance/2; + float starting_x = shoulder_center_x - (bbox_size / 2) * shoulder_distance; + float starting_y = eye_left_y - shoulder_distance / 2; - float ending_x = shoulder_center_x + (bbox_size/2) * shoulder_distance; + float ending_x = shoulder_center_x + (bbox_size / 2) * shoulder_distance; float ending_y = starting_y + (bbox_size - ((float)0.5)) * shoulder_distance; float bbox_center_x = (starting_x + ending_x) / 2; diff --git a/Assets/MediaPipeUnity/Common/Scripts/KeypointManagerEmbedding.cs b/Assets/MediaPipeUnity/Common/Scripts/KeypointManagerEmbedding.cs new file mode 100644 index 0000000..2434ddf --- /dev/null +++ b/Assets/MediaPipeUnity/Common/Scripts/KeypointManagerEmbedding.cs @@ -0,0 +1,263 @@ +using Mediapipe; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +public class KeypointManagerEmbedding +{ + + private int leftShoulderIndex = 11; + private int rightShoulderIndex = 12; + private int neckIndex = 33; + private int noseIndex = 0; + private int leftEyeIndex = 2; + + private List pose_indices = new List { 0, 33, 5, 2, 8, 7, 12, 11, 14, 13, 16, 15 }; + private List hand_indices = new List { 0, 8, 7, 6, 5, 12, 11, 10, 9, 16, 15, 14, 13, 20, 19, 18, 17, 4, 3, 2, 1 }; + + private static int BUFFER_SIZE = 10; + private List>> keypointsBuffer; + + public KeypointManagerEmbedding() + { + keypointsBuffer = new List>>(); + } + + private (List, List) NormalizeHand(List handX, List handY) + { + var xValues = new List(); + var yValues = new List(); + for (int i = 0; i < handX.Count; i++) + { + if (handX[i] != 0) + { + xValues.Add(handX[i]); + } + if (handY[i] != 0) + { + yValues.Add(handY[i]); + } + } + + if (xValues.Count == 0 || yValues.Count == 0) + { + return (handX, handY); + } + + float width = xValues.Max() - xValues.Min(); + float height = yValues.Max() - yValues.Min(); + float delta_x, delta_y; + + if (width > height) + { + delta_x = 0.1f * width; + delta_y = delta_x + ((width - height) / 2f); + } + else + { + delta_y = 0.1f * height; + delta_x = delta_y + ((height - width) / 2f); + } + + var startingPoint = new Vector2(xValues.Min() - delta_x, yValues.Min() - delta_y); + var endingPoint = new Vector2(xValues.Max() + delta_x, yValues.Max() + delta_y); + + if (endingPoint.x - startingPoint.x == 0f || endingPoint.y - startingPoint.y == 0f) + { + return (handX, handY); + } + + // normalize keypoints + for (int i = 0; i < handX.Count; i++) + { + handX[i] = (handX[i] - startingPoint.x) / (endingPoint.x - startingPoint.x); + handY[i] = (handY[i] - startingPoint.y) / (endingPoint.y - startingPoint.y); + } + + return (handX, handY); + } + + private (List, List) NormalizePose(List poseX, List poseY) + { + var leftShoulder = new Vector2(poseX[leftShoulderIndex], poseY[leftShoulderIndex]); + var rightShoulder = new Vector2(poseX[rightShoulderIndex], poseY[rightShoulderIndex]); + var neck = new Vector2(poseX[neckIndex], poseY[neckIndex]); + var nose = new Vector2(poseX[noseIndex], poseY[noseIndex]); + + // Prevent from even starting the analysis if some necessary elements are not present + if ((leftShoulder.x == 0 || rightShoulder.x == 0 || + (leftShoulder.x == rightShoulder.x && leftShoulder.y == rightShoulder.y)) && + (neck.x == 0 || nose.x == 0 || (neck.x == nose.x && neck.y == nose.y))) + { + return (poseX, poseY); + } + + float shoulderDistance, headMetric; + if (leftShoulder.x != 0 && rightShoulder.x != 0 && + (leftShoulder.x != rightShoulder.x || leftShoulder.y != rightShoulder.y)) + { + shoulderDistance = Mathf.Sqrt(Mathf.Pow(leftShoulder.x - rightShoulder.x, 2) + Mathf.Pow(leftShoulder.y - rightShoulder.y, 2)); + headMetric = shoulderDistance; + } + else + { + float neckNoseDistance = Mathf.Sqrt(Mathf.Pow(neck.x - nose.x, 2) + Mathf.Pow(neck.y - nose.y, 2)); + headMetric = neckNoseDistance; + } + + // Set the starting and ending point of the normalization bounding box + var startingPoint = new Vector2(poseX[neckIndex] - 3 * headMetric, poseY[leftEyeIndex] + headMetric); + var endingPoint = new Vector2(poseX[neckIndex] + 3 * headMetric, startingPoint.y - 6 * headMetric); + + if (startingPoint.x < 0) + { + startingPoint.x = 0; + } + if (startingPoint.y < 0) + { + startingPoint.y = 0; + } + if (endingPoint.x < 0) + { + endingPoint.x = 0; + } + if (endingPoint.y < 0) + { + endingPoint.y = 0; + } + + // Normalize the keypoints + for (int i = 0; i < poseX.Count; i++) + { + poseX[i] = (poseX[i] - startingPoint.x) / (endingPoint.x - startingPoint.x); + poseY[i] = (poseY[i] - endingPoint.y) / (startingPoint.y - endingPoint.y); + } + + return (poseX, poseY); + } + + private (List, List) CalculateNeck(List keypointsX, List keypointsY) + { + var leftShoulder = new Vector2(keypointsX[11], keypointsY[11]); + var rightShoulder = new Vector2(keypointsX[12], keypointsY[12]); + + var neck = new Vector2((leftShoulder.x + rightShoulder.x) / 2, (leftShoulder.y + rightShoulder.y) / 2); + + // add neck to keypoints + keypointsX.Add(neck.x); + keypointsY.Add(neck.y); + + return (keypointsX, keypointsY); + } + + + public void AddLandmarks(NormalizedLandmarkList poseLandmarks, NormalizedLandmarkList leftHandLandmarks, NormalizedLandmarkList rightHandLandmarks) + { + List pose_x = new List(); + List pose_y = new List(); + List left_hand_x = new List(); + List left_hand_y = new List(); + List right_hand_x = new List(); + List right_hand_y = new List(); + + if (poseLandmarks == null || (leftHandLandmarks == null && rightHandLandmarks == null)) + { + return; + } + + if (poseLandmarks != null) + { + foreach (NormalizedLandmark landmark in poseLandmarks.Landmark) + { + pose_x.Add(landmark.X); + pose_y.Add(landmark.Y); + } + }else{ + for (int i = 0; i < 33; i++) + { + pose_x.Add(0); + pose_y.Add(0); + } + } + + // Add neck to pose + (pose_x, pose_y) = CalculateNeck(pose_x, pose_y); + + // normalize pose + (pose_x, pose_y) = NormalizePose(pose_x, pose_y); + + // now filter the pose keypoints based on the pose indeces + List> filtered_pose = new List>(); + foreach (int index in pose_indices) + { + filtered_pose.Add(new List { pose_x[index] - 0.5f, pose_y[index] - 0.5f }); + } + + // add hand landmarks + if (leftHandLandmarks != null) + { + foreach (NormalizedLandmark landmark in leftHandLandmarks.Landmark) + { + left_hand_x.Add(landmark.X); + left_hand_y.Add(landmark.Y); + } + }else{ + for (int i = 0; i < 21; i++) + { + left_hand_x.Add(0); + left_hand_y.Add(0); + } + } + + if (rightHandLandmarks != null) + { + foreach (NormalizedLandmark landmark in rightHandLandmarks.Landmark) + { + right_hand_x.Add(landmark.X); + right_hand_y.Add(landmark.Y); + } + }else{ + for (int i = 0; i < 21; i++) + { + right_hand_x.Add(0); + right_hand_y.Add(0); + } + } + + // normalize the hands + (left_hand_x, left_hand_y) = NormalizeHand(left_hand_x, left_hand_y); + (right_hand_x, right_hand_y) = NormalizeHand(right_hand_x, right_hand_y); + + // now filter the hand keypoints based on the hand indeces + List> filtered_left_hand = new List>(); + List> filtered_right_hand = new List>(); + + foreach (int index in hand_indices) + { + filtered_left_hand.Add(new List { left_hand_x[index] - 0.5f, left_hand_y[index] - 0.5f }); + filtered_right_hand.Add(new List { right_hand_x[index] - 0.5f, right_hand_y[index] - 0.5f }); + } + + // add the filtered keypoints together in one list + List> filtered_keypoints = new List>(); + filtered_keypoints.AddRange(filtered_pose); + filtered_keypoints.AddRange(filtered_left_hand); + filtered_keypoints.AddRange(filtered_right_hand); + + keypointsBuffer.Add(filtered_keypoints); + + if (keypointsBuffer.Count > BUFFER_SIZE) + { + keypointsBuffer.RemoveAt(0); + } + } + + public List>> GetKeypoints() + { + if (keypointsBuffer.Count < BUFFER_SIZE){ + return null; + } + return keypointsBuffer; + } + +} \ No newline at end of file diff --git a/Assets/MediaPipeUnity/Common/Scripts/KeypointManagerEmbedding.cs.meta b/Assets/MediaPipeUnity/Common/Scripts/KeypointManagerEmbedding.cs.meta new file mode 100644 index 0000000..cdf5e4c --- /dev/null +++ b/Assets/MediaPipeUnity/Common/Scripts/KeypointManagerEmbedding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8978a7c17464d4fa8ab9f33be45a2bb6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MediaPipeUnity/Interfaces.meta b/Assets/MediaPipeUnity/Interfaces.meta new file mode 100644 index 0000000..80634de --- /dev/null +++ b/Assets/MediaPipeUnity/Interfaces.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 73c615986873dc246893879daf74c05d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MediaPipeUnity/Interfaces/Listener.cs b/Assets/MediaPipeUnity/Interfaces/Listener.cs new file mode 100644 index 0000000..05880f4 --- /dev/null +++ b/Assets/MediaPipeUnity/Interfaces/Listener.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +/// +/// Listener interface with an IEnumerator as its processing-function. +/// +public interface Listener +{ + /// + /// The function that is called by the publisher. + /// + /// + public IEnumerator ProcessIncomingCall(); +} diff --git a/Assets/MediaPipeUnity/Interfaces/Listener.cs.meta b/Assets/MediaPipeUnity/Interfaces/Listener.cs.meta new file mode 100644 index 0000000..704b3ba --- /dev/null +++ b/Assets/MediaPipeUnity/Interfaces/Listener.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e4c1da9896d9ba2449549a016b5fd15e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MediaPipeUnity/Interfaces/SignPredictorInterfaces.asmdef b/Assets/MediaPipeUnity/Interfaces/SignPredictorInterfaces.asmdef new file mode 100644 index 0000000..a39877a --- /dev/null +++ b/Assets/MediaPipeUnity/Interfaces/SignPredictorInterfaces.asmdef @@ -0,0 +1,14 @@ +{ + "name": "SignPredictorInterfaces", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/Unity.Barracuda.ONNX.asmdef.meta b/Assets/MediaPipeUnity/Interfaces/SignPredictorInterfaces.asmdef.meta similarity index 76% rename from Packages/com.unity.barracuda/Runtime/ONNX/Unity.Barracuda.ONNX.asmdef.meta rename to Assets/MediaPipeUnity/Interfaces/SignPredictorInterfaces.asmdef.meta index 6c2115f..c87212f 100644 --- a/Packages/com.unity.barracuda/Runtime/ONNX/Unity.Barracuda.ONNX.asmdef.meta +++ b/Assets/MediaPipeUnity/Interfaces/SignPredictorInterfaces.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: fbc9f7bf5edea4a74a8942a98af6fe07 +guid: f55a02e98b01bc849b30d9650ccd8f15 AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Assets/MediaPipeUnity/Prefabs/Feedback.prefab b/Assets/MediaPipeUnity/Prefabs/Feedback.prefab index ee82a36..7fd2444 100644 --- a/Assets/MediaPipeUnity/Prefabs/Feedback.prefab +++ b/Assets/MediaPipeUnity/Prefabs/Feedback.prefab @@ -9,7 +9,6 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 4318122119930585316} - - component: {fileID: 4318122119930585317} m_Layer: 5 m_Name: Feedback m_TagString: Untagged @@ -39,22 +38,6 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 200} m_SizeDelta: {x: 500, y: 150} m_Pivot: {x: 0.5, y: 0} ---- !u!114 &4318122119930585317 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4318122119930585319} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 44e682a32ee15cc489bf50f3a06f717b, type: 3} - m_Name: - m_EditorClassIdentifier: - feedbackText: {fileID: 4318122120222767928} - feedbackProgress: {fileID: 4318122119968934242} - feedbackProgressImage: {fileID: 4318122120334233319} - signPredictor: {fileID: 0} --- !u!1 &4318122119968934244 GameObject: m_ObjectHideFlags: 0 @@ -113,7 +96,7 @@ MonoBehaviour: m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} m_SelectOnRight: {fileID: 0} - m_Transition: 1 + m_Transition: 0 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} @@ -133,7 +116,7 @@ MonoBehaviour: m_PressedTrigger: Pressed m_SelectedTrigger: Selected m_DisabledTrigger: Disabled - m_Interactable: 1 + m_Interactable: 0 m_TargetGraphic: {fileID: 0} m_FillRect: {fileID: 4318122120334233317} m_HandleRect: {fileID: 0} @@ -213,15 +196,15 @@ MonoBehaviour: m_Calls: [] m_text: Detecteren ... m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4282188031 - m_fontColor: {r: 1, g: 0, b: 0.23945475, a: 1} + rgba: 4282206709 + m_fontColor: {r: 0.9607843, g: 0.28627452, b: 0.23921569, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -244,8 +227,8 @@ MonoBehaviour: m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 1 - m_HorizontalAlignment: 2 + m_fontStyle: 0 + m_HorizontalAlignment: 1 m_VerticalAlignment: 512 m_textAlignment: 65535 m_characterSpacing: 0 @@ -339,14 +322,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 0, b: 0, a: 1} + m_Color: {r: 0.9607843, g: 0.28627452, b: 0.23921569, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -415,14 +398,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 0.5803922, g: 0.58431375, b: 0.6, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 diff --git a/Assets/MediaPipeUnity/ScriptableObjects.meta b/Assets/MediaPipeUnity/ScriptableObjects.meta new file mode 100644 index 0000000..256bc92 --- /dev/null +++ b/Assets/MediaPipeUnity/ScriptableObjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 438a3ced42dd6fc4ab38e3a16c1e43a7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MediaPipeUnity/ScriptableObjects/ModelList.asset b/Assets/MediaPipeUnity/ScriptableObjects/ModelList.asset new file mode 100644 index 0000000..fe97b4a --- /dev/null +++ b/Assets/MediaPipeUnity/ScriptableObjects/ModelList.asset @@ -0,0 +1,25 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 78a3f61c93a08c04496c49ffd10b9021, type: 3} + m_Name: ModelList + m_EditorClassIdentifier: + models: + - index: 0 + modelWINDOWS: {fileID: 0} + modelMAC: {fileID: 0} + - index: 1 + modelWINDOWS: {fileID: 8538825877217656561, guid: fdbf401e965a6bf4a87637cd519f2715, type: 3} + modelMAC: {fileID: 8538825877217656561, guid: be31548ec7e7544fe9828b14657bb40b, type: 3} + - index: 2 + modelWINDOWS: {fileID: 8538825877217656561, guid: fa63c40c78ba548468cad97b15cdc6c9, type: 3} + modelMAC: {fileID: 8538825877217656561, guid: 17fb70e1c284e44da8083b36bb6afcb8, type: 3} + currentModelIndex: 2 diff --git a/Assets/MediaPipeUnity/ScriptableObjects/ModelList.asset.meta b/Assets/MediaPipeUnity/ScriptableObjects/ModelList.asset.meta new file mode 100644 index 0000000..6b6b05c --- /dev/null +++ b/Assets/MediaPipeUnity/ScriptableObjects/ModelList.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39516e4e6e56f0f4f80647d9c4d8034c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MediaPipeUnity/Scripts/AbstractFeedback.cs b/Assets/MediaPipeUnity/Scripts/AbstractFeedback.cs new file mode 100644 index 0000000..0804d48 --- /dev/null +++ b/Assets/MediaPipeUnity/Scripts/AbstractFeedback.cs @@ -0,0 +1,36 @@ +using System.Collections; +using UnityEngine; + +/// +/// Class to display feedback during a course +/// +public abstract class AbstractFeedback : MonoBehaviour, Listener +{ + /// + /// Reference to the sign predictor + /// + public SignPredictor signPredictor; + + /// + /// The function that is called by the publisher on all its listeners + /// + /// + public IEnumerator ProcessIncomingCall() + { + yield return StartCoroutine(UpdateFeedback()); + } + + /// + /// A function to add yourself as listener to the signPredictor you are holding + /// + public void AddSelfAsListener() + { + signPredictor.listeners.Add(this); + } + + /// + /// The function that holds the logic to process the new probabilities of the signPredictor + /// + /// + protected abstract IEnumerator UpdateFeedback(); +} \ No newline at end of file diff --git a/Assets/MediaPipeUnity/Scripts/AbstractFeedback.cs.meta b/Assets/MediaPipeUnity/Scripts/AbstractFeedback.cs.meta new file mode 100644 index 0000000..5fdbcf9 --- /dev/null +++ b/Assets/MediaPipeUnity/Scripts/AbstractFeedback.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b5ac794337a54143a6e3077483d96c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MediaPipeUnity/Scripts/Feedback.cs b/Assets/MediaPipeUnity/Scripts/Feedback.cs deleted file mode 100644 index bbb88a0..0000000 --- a/Assets/MediaPipeUnity/Scripts/Feedback.cs +++ /dev/null @@ -1,182 +0,0 @@ -using DigitalRuby.Tween; -using Mediapipe.Unity.Tutorial; -using System; -using System.Collections; -using TMPro; -using UnityEngine; -using UnityEngine.Events; -using UnityEngine.UI; - -/// -/// Class to display feedback during a course -/// -public class Feedback : MonoBehaviour -{ - /// - /// Reference to the feedback field - /// - public TMP_Text feedbackText; - - /// - /// Reference to the progress bar - /// - public Slider feedbackProgress; - - /// - /// Reference to the progress bar image, so we can add fancy colors - /// - public Image feedbackProgressImage; - - /// - /// Reference to the sign predictor - /// - public SignPredictor signPredictor; - - /// - /// Callback for getting the correct sign - /// - public Func getSignCallback; - - /// - /// Callback to initiate the next sign - /// - public UnityAction predictSignCallback; - - /// - /// Timer to keep track of how long a incorrect sign is performed - /// - private DateTime timer; - - /// - /// Current predicted sign - /// - private string predictedSign = null; - - /// - /// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs - /// - private string previousIncorrectSign = null; - - /// - /// Start is called before the first frame update - /// - void Start() - { - // Start the coroutine to update the scale every 200 milliseconds - StartCoroutine(UpdateFeedback()); - } - - /// - /// UpdateScale updates the progress bar every 200ms, updated the feedback text, and progress bar color - /// If a high enough accuracy is detected, it will go to the next sign - /// - /// - IEnumerator UpdateFeedback() - { - while (true) - { - if (getSignCallback != null && predictSignCallback != null) - { - - // Get current sign - string currentSign = getSignCallback(); - // Get the predicted sign - if (signPredictor != null && signPredictor.learnableProbabilities != null && - currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign)) - { - float accuracy = signPredictor.learnableProbabilities[currentSign]; - if (feedbackText != null && feedbackProgressImage != null){ - if (accuracy > 0.98) - { - // TODO: fix emojis - feedbackText.text = "✨ Perfect ✨"; - Color col = new Color(0xff / 255.0f, 0xcc / 255.0f, 0x00 / 255.0f); - feedbackText.color = col; - feedbackProgressImage.color = col; - } - else if (accuracy > 0.95) - { - feedbackText.text = "Super!"; - Color col = new Color(0x00 / 255.0f, 0xff / 255.0f, 0xcc / 255.0f); - feedbackText.color = col; - feedbackProgressImage.color = col; - } - else if (accuracy > 0.90) - { - feedbackText.text = "Goed"; - feedbackText.color = Color.green; - feedbackProgressImage.color = Color.green; - } - else if (accuracy > 0.80) - { - feedbackText.text = "Bijna..."; - Color col = new Color(0xff / 255.0f, 0x66 / 255.0f, 0x00 / 255.0f); - feedbackText.color = col; - feedbackProgressImage.color = col; - } - else - { - feedbackText.text = "Detecteren..."; - feedbackText.color = Color.red; - feedbackProgressImage.color = Color.red; - } - - float oldValue = feedbackProgress.value; - // use an exponential scale - float newValue = Mathf.Exp(4 * (accuracy - 1.0f)); - feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) => - { - if (feedbackProgress != null) - { - feedbackProgress.value = t.CurrentValue; - } - }); - } - - // Check whether (in)correct sign has high accuracy - foreach (var kv in signPredictor.learnableProbabilities) - { - if (kv.Value > 0.90) - { - predictedSign = kv.Key; - // Correct sign - if (predictedSign == currentSign) - { - yield return new WaitForSeconds(1.0f); - predictSignCallback(predictedSign); - timer = DateTime.Now; - predictedSign = null; - previousIncorrectSign = null; - } - // Incorrect sign - else - { - if (previousIncorrectSign != predictedSign) - { - timer = DateTime.Now; - previousIncorrectSign = predictedSign; - } - else if (DateTime.Now - timer > TimeSpan.FromSeconds(2.0f)) - { - predictSignCallback(predictedSign); - timer = DateTime.Now; - predictedSign = null; - previousIncorrectSign = null; - } - } - break; - } - } - } - else if(feedbackProgress != null) - { - - feedbackProgress.value = 0.0f; - } - } - - // Wait for 200 milliseconds before updating the scale again - yield return new WaitForSeconds(0.2f); - } - } -} \ No newline at end of file diff --git a/Assets/MediaPipeUnity/Scripts/Feedback.cs.meta b/Assets/MediaPipeUnity/Scripts/Feedback.cs.meta deleted file mode 100644 index cd8d001..0000000 --- a/Assets/MediaPipeUnity/Scripts/Feedback.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 44e682a32ee15cc489bf50f3a06f717b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/MediaPipeUnity/Scripts/SignPredictor.asmdef b/Assets/MediaPipeUnity/Scripts/SignPredictor.asmdef index cc93292..37a4332 100644 --- a/Assets/MediaPipeUnity/Scripts/SignPredictor.asmdef +++ b/Assets/MediaPipeUnity/Scripts/SignPredictor.asmdef @@ -3,10 +3,12 @@ "rootNamespace": "", "references": [ "GUID:6055be8ebefd69e48b49212b09b47b2f", - "GUID:5c2b5ba89f9e74e418232e154bc5cc7a", "GUID:04c4d86a70aa56c55a78c61f1ab1a56d", "GUID:edc93f477bb73a743a97d6882ed330b3", - "GUID:58e104b97fb3752438ada2902a36dcbf" + "GUID:58e104b97fb3752438ada2902a36dcbf", + "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25", + "GUID:f55a02e98b01bc849b30d9650ccd8f15", + "GUID:d23f64cfd3b314bb4a18a8284c99bf5e" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/MediaPipeUnity/Scripts/SignPredictor.cs b/Assets/MediaPipeUnity/Scripts/SignPredictor.cs index b1d8338..ba4d1ab 100644 --- a/Assets/MediaPipeUnity/Scripts/SignPredictor.cs +++ b/Assets/MediaPipeUnity/Scripts/SignPredictor.cs @@ -1,320 +1,535 @@ -// Copyright (c) 2021 homuler -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. - -// ATTENTION!: This code is for a tutorial. - +using Mediapipe; +using Mediapipe.Unity; +using NatML; +using NatML.Features; +using NatML.Internal; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Unity.Barracuda; +using System.Threading.Tasks; using UnityEngine; using UnityEngine.UI; -namespace Mediapipe.Unity.Tutorial + +[System.Serializable] +public class EmbeddingData { - public class SignPredictor : MonoBehaviour + public float[] embeddings; + public string label_name; + public int labels; +} + +[System.Serializable] +public class EmbeddingDataList +{ + public List dataList; +} + +public class DistanceEmbedding +{ + public float distance; + public EmbeddingData embeddingData; + + public DistanceEmbedding(float distance, EmbeddingData embeddingData) + { + this.distance = distance; + this.embeddingData = embeddingData; + } +} + +public class DistanceComparer : IComparer +{ + public int Compare(DistanceEmbedding x, DistanceEmbedding y) + { + return x.distance.CompareTo(y.distance); + } +} + +/// +/// +/// +public class SignPredictor : MonoBehaviour +{ + /// + /// Predictor class which is used to predict the sign using an MLEdgeModel + /// + public class NatMLSignPredictorEmbed : IMLPredictor> { /// - /// Reference to the model used in the SignPredictor + /// The MLEdgeModel used for predictions /// - public NNModel model; + private readonly MLEdgeModel edgeModel; /// - /// Reference to the model info file + /// The type used to create features which are input for the model /// - public TextAsset modelInfoFile; + private MLFeatureType featureType; /// - /// Config file to set up the graph + /// Creation of a NatMLSignPredictor instance /// - [SerializeField] - private TextAsset configAsset; - - /// - /// Index to indicate which camera is being used - /// - private int camdex = 0; - - /// - /// The screen object on which the video is displayed - /// - [SerializeField] - private RawImage screen; - - /// - /// A secondary optional screen object on which the video is displayed - /// - [SerializeField] - private RawImage screen2; - - /// - /// MediaPipe graph - /// - private CalculatorGraph graph; - - /// - /// Resource manager for graph resources - /// - private ResourceManager resourceManager; - - /// - /// Webcam texture - /// - private WebCamTexture webcamTexture; - - /// - /// Input texture - /// - private Texture2D inputTexture; - - /// - /// Screen pixel data - /// - private Color32[] pixelData; - - /// - /// Stopwatch to give a timestamp to video frames - /// - private Stopwatch stopwatch; - - /// - /// The mediapipe stream which contains the pose landmarks - /// - private OutputStream posestream; - - /// - /// The mediapipe stream which contains the left hand landmarks - /// - private OutputStream leftstream; - - /// - /// The mediapipe stream which contains the right hand landmarks - /// - private OutputStream rightstream; - - /// - /// create precense stream - /// - public OutputStream> presenceStream; - - /// - /// A keypointmanager which does normalization stuff, keeps track of the landmarks - /// - private KeypointManager keypointManager; - - /// - /// The worker on which we schedule the signpredictor model execution - /// - private IWorker worker; - - /// - /// Width of th webcam - /// - private int width; - - /// - /// Height of the webcam - /// - private int height; - - /// - /// The enumerator of the worker which executes the sign predictor model - /// - private IEnumerator enumerator; - - /// - /// The prediction of the sign predictor model - /// - public Dictionary learnableProbabilities; - - /// - /// Bool indicating whether or not the resource manager has already been initialized - /// - private static bool resourceManagerIsInitialized = false; - - /// - /// an inputTensor for the sign predictor - /// - private Tensor inputTensor; - - /// - /// Google Mediapipe setup & run - /// - /// IEnumerator - /// - private IEnumerator Start() + /// + public NatMLSignPredictorEmbed(MLEdgeModel edgeModel) { - // Webcam setup - if (WebCamTexture.devices.Length == 0) + this.edgeModel = edgeModel; + featureType = edgeModel.inputs[0]; + } + + /// + /// Predicts the sign using the MLEdgeModel + /// + /// + /// + public List Predict(params MLFeature[] inputs) + { + List predictions = null; + IMLEdgeFeature iedgeFeature = (IMLEdgeFeature)inputs[0]; + MLEdgeFeature edgeFeature = iedgeFeature.Create(featureType); + MLFeatureCollection result = edgeModel.Predict(edgeFeature); + if (0 < result.Count) { - throw new System.Exception("Web Camera devices are not found"); + predictions = new MLArrayFeature(result[0]).Flatten().ToArray().ToList(); } - // Start the webcam - WebCamDevice webCamDevice = WebCamTexture.devices[0]; - webcamTexture = new WebCamTexture(webCamDevice.name); + edgeFeature.Dispose(); + result.Dispose(); + return predictions; + } - webcamTexture.Play(); - yield return new WaitUntil(() => webcamTexture.width > 16); + /// + /// Disposing the MLEdgeModel + /// + public void Dispose() + { + edgeModel.Dispose(); + } + } - // Set webcam aspect ratio - width = webcamTexture.width; - height = webcamTexture.height; - float webcamAspect = (float)webcamTexture.width / (float)webcamTexture.height; - screen.rectTransform.sizeDelta = new Vector2(screen.rectTransform.sizeDelta.y * webcamAspect, (screen.rectTransform.sizeDelta.y)); - screen.texture = webcamTexture; - if(screen2 != null) + /// + /// Predictor class which is used to predict the sign using an MLEdgeModel + /// + public class NatMLSignPredictor : IMLPredictor> + { + /// + /// The MLEdgeModel used for predictions + /// + private readonly MLEdgeModel edgeModel; + + /// + /// The type used to create features which are input for the model + /// + private MLFeatureType featureType; + + /// + /// Creation of a NatMLSignPredictor instance + /// + /// + public NatMLSignPredictor(MLEdgeModel edgeModel) + { + this.edgeModel = edgeModel; + featureType = edgeModel.inputs[0]; + } + + /// + /// Predicts the sign using the MLEdgeModel + /// + /// + /// + public List Predict(params MLFeature[] inputs) + { + List predictions = null; + IMLEdgeFeature iedgeFeature = (IMLEdgeFeature)inputs[0]; + MLEdgeFeature edgeFeature = iedgeFeature.Create(featureType); + MLFeatureCollection result = edgeModel.Predict(edgeFeature); + if (0 < result.Count) { - screen2.rectTransform.sizeDelta = new Vector2(screen2.rectTransform.sizeDelta.y * webcamAspect, (screen2.rectTransform.sizeDelta.y)); + predictions = new MLArrayFeature(result[0]).Flatten().ToArray().ToList(); + predictions = predictions.ConvertAll((c) => Mathf.Exp(c)); + float sum = predictions.Sum(); + predictions = predictions.ConvertAll((c) => c / sum); } - - // TODO this method is kinda meh you should use - inputTexture = new Texture2D(width, height, TextureFormat.RGBA32, false); - pixelData = new Color32[width * height]; - - if (!resourceManagerIsInitialized) - { - resourceManager = new StreamingAssetsResourceManager(); - yield return resourceManager.PrepareAssetAsync("pose_detection.bytes"); - yield return resourceManager.PrepareAssetAsync("pose_landmark_full.bytes"); - yield return resourceManager.PrepareAssetAsync("face_landmark.bytes"); - yield return resourceManager.PrepareAssetAsync("hand_landmark_full.bytes"); - yield return resourceManager.PrepareAssetAsync("face_detection_short_range.bytes"); - yield return resourceManager.PrepareAssetAsync("hand_recrop.bytes"); - yield return resourceManager.PrepareAssetAsync("handedness.txt"); - resourceManagerIsInitialized = true; - } - - stopwatch = new Stopwatch(); - - // Setting up the graph - graph = new CalculatorGraph(configAsset.text); - - posestream = new OutputStream(graph, "pose_landmarks", "pose_landmarks_presence"); - leftstream = new OutputStream(graph, "left_hand_landmarks", "left_hand_landmarks_presence"); - rightstream = new OutputStream(graph, "right_hand_landmarks", "right_hand_landmarks_presence"); - - posestream.StartPolling().AssertOk(); - leftstream.StartPolling().AssertOk(); - rightstream.StartPolling().AssertOk(); - - graph.StartRun().AssertOk(); - stopwatch.Start(); + edgeFeature.Dispose(); + result.Dispose(); + return predictions; + } + /// + /// Disposing the MLEdgeModel + /// + public void Dispose() + { + edgeModel.Dispose(); + } + } + + public List listeners = new List(); + + /// + /// Predictor which is used to create the asyncPredictor (should not be used if asyncPredictor exists) + /// + private NatMLSignPredictorEmbed predictor_embed; + + private NatMLSignPredictor predictor; + + + /// + /// The asynchronous predictor which is used to predict the sign using an MLEdgemodel + /// + private MLAsyncPredictor> asyncPredictor; + + /// + /// Reference to the model used in the SignPredictor + /// + private MLEdgeModel model; + + /// + /// Modellist used to change model using ModelIndex + /// + public ModelList modelList; + + /// + /// Chosen model data based on the operating system + /// + private MLModelData modelData; + + /// + /// Reference to the model info file + /// + public TextAsset modelInfoFile; + public TextAsset modelInfoFileEmbedding; + + /// + /// Config file to set up the graph + /// + [SerializeField] + private TextAsset configAsset; + + /// + /// Index to indicate which camera is being used + /// + private int camdex = 0; + + /// + /// The screen object on which the video is displayed + /// + [SerializeField] + private RawImage screen; + + /// + /// MediaPipe graph + /// + private CalculatorGraph graph; + + /// + /// Resource manager for graph resources + /// + private ResourceManager resourceManager; + + /// + /// Webcam texture + /// + private WebCamTexture webcamTexture = null; + + /// + /// Input texture + /// + private Texture2D inputTexture; + + /// + /// Screen pixel data + /// + private Color32[] pixelData; + + /// + /// Stopwatch to give a timestamp to video frames + /// + private Stopwatch stopwatch; + + /// + /// The mediapipe stream which contains the pose landmarks + /// + private OutputStream posestream; + + /// + /// The mediapipe stream which contains the left hand landmarks + /// + private OutputStream leftstream; + + /// + /// The mediapipe stream which contains the right hand landmarks + /// + private OutputStream rightstream; + + /// + /// create precense stream + /// + public OutputStream> presenceStream; + + /// + /// A keypointmanager which does normalization stuff, keeps track of the landmarks + /// + private KeypointManager keypointManager; + + /// + /// A keypointmanager which does normalization stuff, keeps track of the landmarks (for embedding model) + /// + private KeypointManagerEmbedding keypointManagerEmbedding; + + /// + /// Width of th webcam + /// + private int width; + + /// + /// Height of the webcam + /// + private int height; + + /// + /// The prediction of the sign predictor model + /// + public Dictionary learnableProbabilities; + + /// + /// Bool indicating whether or not the resource manager has already been initialized + /// + private static bool resourceManagerIsInitialized = false; + + private List signs; + private EmbeddingDataList embeddingDataList; + + private ModelIndex modelID; + + /// + /// Google Mediapipe setup & run + /// + /// IEnumerator + /// + private IEnumerator Start() + { + // Webcam setup + if (WebCamTexture.devices.Length == 0) + { + throw new System.Exception("Web Camera devices are not found"); + } + // Start the webcam + WebCamDevice webCamDevice = WebCamTexture.devices[0]; + webcamTexture = new WebCamTexture(webCamDevice.name); + + webcamTexture.Play(); + + yield return new WaitUntil(() => webcamTexture.width > 16); + + // Set webcam aspect ratio + width = webcamTexture.width; + height = webcamTexture.height; + float webcamAspect = (float)webcamTexture.width / (float)webcamTexture.height; + screen.rectTransform.sizeDelta = new Vector2(screen.rectTransform.sizeDelta.y * webcamAspect, (screen.rectTransform.sizeDelta.y)); + screen.texture = webcamTexture; + + // TODO this method is kinda meh you should use + inputTexture = new Texture2D(width, height, TextureFormat.RGBA32, false); + pixelData = new Color32[width * height]; + + if (!resourceManagerIsInitialized) + { + resourceManager = new StreamingAssetsResourceManager(); + yield return resourceManager.PrepareAssetAsync("pose_detection.bytes"); + yield return resourceManager.PrepareAssetAsync("pose_landmark_full.bytes"); + yield return resourceManager.PrepareAssetAsync("face_landmark.bytes"); + yield return resourceManager.PrepareAssetAsync("hand_landmark_full.bytes"); + yield return resourceManager.PrepareAssetAsync("face_detection_short_range.bytes"); + yield return resourceManager.PrepareAssetAsync("hand_recrop.bytes"); + yield return resourceManager.PrepareAssetAsync("handedness.txt"); + resourceManagerIsInitialized = true; + } + + stopwatch = new Stopwatch(); + + // Setting up the graph + graph = new CalculatorGraph(configAsset.text); + + posestream = new OutputStream(graph, "pose_landmarks", "pose_landmarks_presence"); + leftstream = new OutputStream(graph, "left_hand_landmarks", "left_hand_landmarks_presence"); + rightstream = new OutputStream(graph, "right_hand_landmarks", "right_hand_landmarks_presence"); + + posestream.StartPolling().AssertOk(); + leftstream.StartPolling().AssertOk(); + rightstream.StartPolling().AssertOk(); + + graph.StartRun().AssertOk(); + stopwatch.Start(); + + // Check if a model is ready to load + yield return new WaitUntil(() => modelList.HasValidModel()); + + // Create Model + Task t = Task.Run(() => MLEdgeModel.Create(modelList.GetCurrentModel())); + yield return new WaitUntil(() => t.IsCompleted); + model = t.Result; + + modelID = modelList.GetCurrentModelIndex(); + + if (modelID == ModelIndex.FINGERSPELLING) + { + predictor = new NatMLSignPredictor(model); + asyncPredictor = predictor.ToAsync(); + // Creating a KeypointManager keypointManager = new KeypointManager(modelInfoFile); - // check if model exists at path - //var model = ModelLoader.Load(Resources.Load("Models/Fingerspelling/model_A-L")); - worker = model.CreateWorker(); - StartCoroutine(SignRecognitionCoroutine()); StartCoroutine(MediapipeCoroutine()); } - - /// - /// Coroutine which executes the mediapipe pipeline - /// - /// - private IEnumerator MediapipeCoroutine() + else { - while (true) - { - inputTexture.SetPixels32(webcamTexture.GetPixels32(pixelData)); - var imageFrame = new ImageFrame(ImageFormat.Types.Format.Srgba, width, height, width * 4, inputTexture.GetRawTextureData()); - var currentTimestamp = stopwatch.ElapsedTicks / (System.TimeSpan.TicksPerMillisecond / 1000); - graph.AddPacketToInputStream("input_video", new ImageFramePacket(imageFrame, new Timestamp(currentTimestamp))).AssertOk(); - //Debug.Log(Time.timeAsDouble + " Added new packet to mediapipe graph"); - yield return new WaitForEndOfFrame(); + predictor_embed = new NatMLSignPredictorEmbed(model); + asyncPredictor = predictor_embed.ToAsync(); + // Creating a KeypointManager + keypointManagerEmbedding = new KeypointManagerEmbedding(); - NormalizedLandmarkList _poseLandmarks = null; - NormalizedLandmarkList _leftHandLandmarks = null; - NormalizedLandmarkList _rightHandLandmarks = null; + // read the embedding data + embeddingDataList = JsonUtility.FromJson($"{{\"dataList\":{modelInfoFileEmbedding}}}"); + // Start the Coroutine + StartCoroutine(SignRecognitionCoroutineEmbed()); + StartCoroutine(MediapipeCoroutineEmbed()); - //Debug.Log("Extracting keypoints"); - - yield return new WaitUntil(() => { posestream.TryGetNext(out _poseLandmarks, false); return true; }); - yield return new WaitUntil(() => { leftstream.TryGetNext(out _leftHandLandmarks, false); return true; }); - yield return new WaitUntil(() => { rightstream.TryGetNext(out _rightHandLandmarks, false); return true; }); - //Debug.Log(Time.timeAsDouble + " Retrieved landmarks "); - - keypointManager.AddLandmarks(_poseLandmarks, _leftHandLandmarks, _rightHandLandmarks); - } } - /// - /// Coroutine which calls the sign predictor model - /// - /// - private IEnumerator SignRecognitionCoroutine() + } + + /// + /// Coroutine which executes the mediapipe pipeline + /// + /// + private IEnumerator MediapipeCoroutine() + { + while (true) { - while (true) + inputTexture.SetPixels32(webcamTexture.GetPixels32(pixelData)); + var imageFrame = new ImageFrame(ImageFormat.Types.Format.Srgba, width, height, width * 4, inputTexture.GetRawTextureData()); + var currentTimestamp = stopwatch.ElapsedTicks / (System.TimeSpan.TicksPerMillisecond / 1000); + graph.AddPacketToInputStream("input_video", new ImageFramePacket(imageFrame, new Timestamp(currentTimestamp))).AssertOk(); + yield return new WaitForEndOfFrame(); + + NormalizedLandmarkList _poseLandmarks = null; + NormalizedLandmarkList _leftHandLandmarks = null; + NormalizedLandmarkList _rightHandLandmarks = null; + + yield return new WaitUntil(() => { posestream.TryGetNext(out _poseLandmarks); return true; }); + yield return new WaitUntil(() => { leftstream.TryGetNext(out _leftHandLandmarks); return true; }); + yield return new WaitUntil(() => { rightstream.TryGetNext(out _rightHandLandmarks); return true; }); + + keypointManager.AddLandmarks(_poseLandmarks, _leftHandLandmarks, _rightHandLandmarks); + } + } + + /// + /// Coroutine which executes the mediapipe pipeline + /// + /// + private IEnumerator MediapipeCoroutineEmbed() + { + while (true) + { + inputTexture.SetPixels32(webcamTexture.GetPixels32(pixelData)); + var imageFrame = new ImageFrame(ImageFormat.Types.Format.Srgba, width, height, width * 4, inputTexture.GetRawTextureData()); + var currentTimestamp = stopwatch.ElapsedTicks / (System.TimeSpan.TicksPerMillisecond / 1000); + graph.AddPacketToInputStream("input_video", new ImageFramePacket(imageFrame, new Timestamp(currentTimestamp))).AssertOk(); + yield return new WaitForEndOfFrame(); + + NormalizedLandmarkList _poseLandmarks = null; + NormalizedLandmarkList _leftHandLandmarks = null; + NormalizedLandmarkList _rightHandLandmarks = null; + + yield return new WaitUntil(() => { posestream.TryGetNext(out _poseLandmarks); return true; }); + yield return new WaitUntil(() => { leftstream.TryGetNext(out _leftHandLandmarks); return true; }); + yield return new WaitUntil(() => { rightstream.TryGetNext(out _rightHandLandmarks); return true; }); + + keypointManagerEmbedding.AddLandmarks(_poseLandmarks, _leftHandLandmarks, _rightHandLandmarks); + } + } + + + private float MinkowskiDistance(List x, float[] y, int p) + { + int dimensions = x.Count; + float sum = 0; + + for (int i = 0; i < dimensions; i++) + { + sum += Mathf.Pow(Mathf.Abs(x[i] - y[i]), p); + } + + return Mathf.Pow(sum, 1.0f / p); + } + + private List GetDistances(List embedding, int p = 2) + { + List distances = new List(); + DistanceComparer comparer = new DistanceComparer(); + + foreach (EmbeddingData data in embeddingDataList.dataList) + { + float distance = MinkowskiDistance(embedding, data.embeddings, p); + + DistanceEmbedding newDistanceEmbedding = new DistanceEmbedding(distance, data); + + // Find the appropriate index to insert the new item to maintain the sorted order + int index = distances.BinarySearch(newDistanceEmbedding, comparer); + + // If the index is negative, it represents the bitwise complement of the nearest larger element + if (index < 0) { - List> input = keypointManager.GetKeypoints(); - if (input != null) + index = ~index; + } + + // Insert the new item at the appropriate position + distances.Insert(index, newDistanceEmbedding); + } + + return distances; + } + + /// + /// Coroutine which calls the sign predictor model + /// + /// + private IEnumerator SignRecognitionCoroutine() + { + while (true) + { + List> inputData = keypointManager.GetKeypoints(); + if (inputData != null && asyncPredictor.readyForPrediction) + { + // Getting the size of the input data + int framecount = inputData.Count; + int keypointsPerFrame = inputData[0].Count; + + // Creating ArrayFeature + int[] shape = { framecount, keypointsPerFrame }; + float[] input = new float[framecount * keypointsPerFrame]; + int i = 0; + inputData.ForEach((e) => e.ForEach((f) => input[i++] = f)); + MLArrayFeature feature = new MLArrayFeature(input, shape); + + // Predicting + Task> task = Task.Run(async () => await asyncPredictor.Predict(feature)); + yield return new WaitUntil(() => task.IsCompleted); + List result = task.Result; + if (0 < result.Count) { - - //UnityEngine.Debug.Log("input: " + input.Count); - - int frameCount = input.Count; - int keypoints_per_frame = input[0].Count; - - // Create a tensor with the input - inputTensor = new Tensor(frameCount, keypoints_per_frame); - - // Fill the tensor with the input - for (int i = 0; i < frameCount; i++) - { - for (int j = 0; j < keypoints_per_frame; j++) - { - inputTensor[i, j] = input[i][j]; - } - } - - int stepsPerFrame = 190; - enumerator = worker.StartManualSchedule(inputTensor); - int step = 0; - while (enumerator.MoveNext()) - { - if (++step % stepsPerFrame == 0) - { - //Debug.Log(Time.timeAsDouble + " : " + step); - yield return null; - } - } - - var output = worker.PeekOutput(); - - inputTensor.Dispose(); - - // Get the output as an array - float[] outputArray = output.ToReadOnlyArray(); - //Debug.Log($"out = [{outputArray.Aggregate(" ", (t, f) => $"{t}{f} ")}]"); - - // Calculate the softmax of the output - float max = outputArray.Max(); - float[] softmaxedOutput = outputArray.Select(x => Mathf.Exp(x - max)).ToArray(); - float sum = softmaxedOutput.Sum(); - float[] softmaxedOutput2 = softmaxedOutput.Select(x => x / sum).ToArray(); - - // Get the index of the highest probability - int maxIndex = softmaxedOutput2.ToList().IndexOf(softmaxedOutput2.Max()); - - // Get the letter from the index - char letter = (char)(maxIndex + 65); - float accuracy = (Mathf.RoundToInt(softmaxedOutput2[maxIndex] * 100)); - - // Set the letterProbabilities, currently used by Courses learnableProbabilities = new Dictionary(); - for (int i = 0; i < softmaxedOutput2.Length; i++) + + for (int j = 0; j < result.Count; j++) { - learnableProbabilities.Add(((char)(i + 65)).ToString(), softmaxedOutput2[i]); + learnableProbabilities.Add(signs[j].ToUpper(), result[j]); + } + foreach (Listener listener in listeners) + { + yield return listener.ProcessIncomingCall(); } - //Debug.Log($"prob = [{learnableProbabilities.Aggregate(" ", (t, kv) => $"{t}{kv.Key}:{kv.Value} ")}]"); } else { @@ -322,77 +537,178 @@ namespace Mediapipe.Unity.Tutorial yield return null; } } + + yield return null; } - /// - /// Propper destruction on the Mediapipegraph - /// - private void OnDestroy() + } + + /// + /// Coroutine which calls the sign predictor embedding model + /// + /// + private IEnumerator SignRecognitionCoroutineEmbed() + { + while (true) { - if (webcamTexture != null) + List>> inputData = keypointManagerEmbedding.GetKeypoints(); + if (inputData != null && asyncPredictor.readyForPrediction) { - webcamTexture.Stop(); + // Getting the size of the input data + int framecount = inputData.Count; + int keypointsPerFrame = inputData[0].Count; + + // Creating ArrayFeature + int[] shape = { 1, framecount, keypointsPerFrame, 2 }; + float[] input = new float[framecount * keypointsPerFrame * 2]; + + int i = 0; + + inputData.ForEach((e) => e.ForEach((f) => f.ForEach((k) => input[i++] = k))); + + MLArrayFeature feature = new MLArrayFeature(input, shape); + + // Predicting + Task> task = Task.Run(async () => await asyncPredictor.Predict(feature)); + + + yield return new WaitUntil(() => task.IsCompleted); + + List result = task.Result; + if (0 < result.Count) + { + List distances = GetDistances(result, 2); + + var probs = new Dictionary(); + + for (int j = 0; j < distances.Count; j++) + { + DistanceEmbedding distanceEmbedding = distances[j]; + // check if already in dictionary + if (probs.ContainsKey(distanceEmbedding.embeddingData.label_name)) + { + // if so, check if the distance is smaller + if (probs[distanceEmbedding.embeddingData.label_name] > distanceEmbedding.distance) + { + // if so, replace the distance + probs[distanceEmbedding.embeddingData.label_name] = distanceEmbedding.distance; + } + } + else + { + // if not, add the distance to the dictionary + probs.Add(distanceEmbedding.embeddingData.label_name, distanceEmbedding.distance); + } + } + + // convert distances to probabilities, the closer to 1.5 the better the prediction + var newProbs = new Dictionary(); + float sum = 0.0f; + foreach (KeyValuePair entry in probs) + { + float probability = 1 / (1 + Mathf.Exp(2 * (entry.Value - 1.85f))); + newProbs.Add(entry.Key, probability); + sum += probability; + } + + learnableProbabilities = new Dictionary(); + foreach (var kv in newProbs) + learnableProbabilities.Add(kv.Key, kv.Value / sum); + + //UnityEngine.Debug.Log($"{learnableProbabilities.Aggregate("", (t, e) => $"{t}{e.Key}={e.Value}, ")}"); + + foreach (Listener listener in listeners) + { + yield return listener.ProcessIncomingCall(); + } + } + } - if (graph != null) - { - try - { - graph.CloseInputStream("input_video").AssertOk(); - graph.WaitUntilDone().AssertOk(); - } - finally - { - - graph.Dispose(); - } - } - // inputTensor must still be disposed, if it exists - inputTensor?.Dispose(); - worker?.Dispose(); + yield return null; } - /// - /// So long as there are cameras to use, you swap the camera you are using to another in the list. - /// - public void SwapCam() + } + + /// + /// Propper destruction on the Mediapipegraph + /// + private void OnDestroy() + { + if (webcamTexture != null) { - if (WebCamTexture.devices.Length > 0) - { - // Stop the old camera - // If there was no camera playing before, then you dont have to reset the texture, as it wasn't assigned in the first place. - if (webcamTexture.isPlaying) - { - screen.texture = null; - webcamTexture.Stop(); - webcamTexture = null; - } - // Find the new camera - camdex += 1; - camdex %= WebCamTexture.devices.Length; - // Start the new camera - WebCamDevice device = WebCamTexture.devices[camdex]; - webcamTexture = new WebCamTexture(device.name); - screen.texture = webcamTexture; + webcamTexture.Stop(); + } - webcamTexture.Play(); + if (graph != null) + { + try + { + graph.CloseInputStream("input_video").AssertOk(); + graph.WaitUntilDone().AssertOk(); + } + finally + { + graph.Dispose(); } } - /// - /// Swaps the display screens - /// - public void SwapScreen() - { - if(screen2.texture == null && screen.texture != null) - { - screen2.texture = webcamTexture; - screen.texture = null; - } - else if (screen2.texture != null && screen.texture == null) - { - screen.texture = webcamTexture; - screen2.texture = null; - } + if (asyncPredictor != null) + { + asyncPredictor.Dispose(); } } + + /// + /// So long as there are cameras to use, you swap the camera you are using to another in the list. + /// + public void SwapCam() + { + if (WebCamTexture.devices.Length > 0) + { + // Stop the old camera + // If there was no camera playing before, then you dont have to reset the texture, as it wasn't assigned in the first place. + if (webcamTexture.isPlaying) + { + screen.texture = null; + webcamTexture.Stop(); + webcamTexture = null; + } + // Find the new camera + camdex += 1; + camdex %= WebCamTexture.devices.Length; + // Start the new camera + WebCamDevice device = WebCamTexture.devices[camdex]; + webcamTexture = new WebCamTexture(device.name); + screen.texture = webcamTexture; + + webcamTexture.Play(); + } + } + + + public void SetModel(ModelIndex index) + { + this.modelList.SetCurrentModel(index); + } + + /// + /// Swaps the display screens + /// + public void SwapScreen(RawImage screen) + { + this.screen = screen; + //width = webcamTexture.width; + //height = webcamTexture.height; + if (webcamTexture != null) + { + float webcamAspect = (float)webcamTexture.width / (float)webcamTexture.height; + this.screen.rectTransform.sizeDelta = new Vector2(this.screen.rectTransform.sizeDelta.y * webcamAspect, (this.screen.rectTransform.sizeDelta.y)); + this.screen.texture = webcamTexture; + } + } + + public void SetSignsList(List signs) + { + this.signs = signs; + } } diff --git a/Assets/Minigames.meta b/Assets/Minigames.meta new file mode 100644 index 0000000..c8b700b --- /dev/null +++ b/Assets/Minigames.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 353d02d53aeb14341835f87efae01039 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Minigames/Scripts.meta b/Assets/Minigames/Scripts.meta new file mode 100644 index 0000000..9fd5eb6 --- /dev/null +++ b/Assets/Minigames/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5e1253d871fce14ab568e5c9ad4ced2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SpellingBee/Scripts/GameEndedPanel.cs b/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs similarity index 57% rename from Assets/SpellingBee/Scripts/GameEndedPanel.cs rename to Assets/Minigames/Scripts/AbstractGameEndedPanel.cs index e6dfff4..905533e 100644 --- a/Assets/SpellingBee/Scripts/GameEndedPanel.cs +++ b/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs @@ -4,52 +4,19 @@ using System.Linq; using TMPro; using UnityEngine; using UnityEngine.UI; - -public class GameEndedPanel : MonoBehaviour +/// +/// Abstract class for all minigame-gameEndedPanels +/// +public abstract class AbstractGameEndedPanel : MonoBehaviour { - public UserList userList; - /// - /// "VERLOREN" or "GEWONNEN" + /// The index of minigame that needs a GameEndedPanel /// - public TMP_Text endText; - - /// - /// LPM - /// - public TMP_Text lpmText; - - /// - /// Letters ( right | wrong ) - /// - public TMP_Text lettersRightText; - public TMP_Text lettersWrongText; - - /// - /// Letters - /// - public TMP_Text lettersTotalText; - - /// - /// Accuracy - /// - public TMP_Text accuracyText; - - /// - /// Words - /// - public TMP_Text wordsText; - - /// - /// Time - /// - public TMP_Text timeText; - - /// - /// Score - /// - public TMP_Text scoreText; - + protected abstract MinigameIndex minigameIndex + { + get; + } + /// /// Reference to the scoreboard entries container /// @@ -65,55 +32,10 @@ public class GameEndedPanel : MonoBehaviour ///
public GameObject scoreboardEntry; - /// - /// Generate the content of the GameEnded panel - /// - /// Time of starting the minigame - /// Total number of words - /// Total number of correctly spelled letters - /// Total number of incorrectly spelled letters - /// "VERLOREN" or "GEWONNEN" - /// Final score - public void GenerateContent(DateTime startTime, int totalWords, int correctLetters, int incorrectLetters, string result, int score) - { - // Final result - endText.text = result; - - // LPM - TimeSpan duration = DateTime.Now.Subtract(startTime); - lpmText.text = (60f * correctLetters / duration.TotalSeconds).ToString("#") + " LPM"; - - // Letters ( right | wrong ) total - lettersRightText.text = correctLetters.ToString(); - lettersWrongText.text = incorrectLetters.ToString(); - lettersTotalText.text = (correctLetters + incorrectLetters).ToString(); - - // Accuracy - if (correctLetters + incorrectLetters > 0) - { - accuracyText.text = ((correctLetters) * 100f / (correctLetters + incorrectLetters)).ToString("#.##") + "%"; - } - else - { - accuracyText.text = "-"; - } - - // Words - wordsText.text = $"{totalWords}"; - - // Time - timeText.text = duration.ToString(@"mm\:ss"); - - // Score - scoreText.text = $"Score: {score}"; - SetScoreBoard(); - } - - /// /// Sets the scoreboard /// - private void SetScoreBoard() + protected void SetScoreBoard() { // Clean the previous scoreboard entries for (int i = 0; i < scoreboardEntries.Count; i++) @@ -125,17 +47,17 @@ public class GameEndedPanel : MonoBehaviour // Instantiate new entries // Get all scores from all users List> allScores = new List>(); - foreach (User user in userList.GetUsers()) + foreach (User user in UserList.GetUsers()) { // Get user's progress for this minigame - Progress progress = user.GetMinigameProgress(MinigameIndex.SPELLING_BEE); + var progress = user.GetMinigameProgress(minigameIndex); if (progress != null) { // Add scores to dictionary - List scores = progress.Get>("highestScores"); + List scores = progress.highestScores; foreach (Score score in scores) { - allScores.Add(new Tuple(user.username, score)); + allScores.Add(new Tuple(user.GetUsername(), score)); } } } @@ -154,7 +76,7 @@ public class GameEndedPanel : MonoBehaviour scoreboardEntries.Add(entry); // Set the player icon - entry.transform.Find("Image").GetComponent().sprite = userList.GetUserByUsername(username).avatar; + entry.transform.Find("Image").GetComponent().sprite = UserList.GetUserByUsername(username).GetAvatar(); // Set the player name entry.transform.Find("PlayerName").GetComponent().text = username; diff --git a/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs.meta b/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs.meta new file mode 100644 index 0000000..def7668 --- /dev/null +++ b/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73d452eb6e118ec4091d6cdd82f3550c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Minigames/Scripts/AbstractMinigameController.cs b/Assets/Minigames/Scripts/AbstractMinigameController.cs new file mode 100644 index 0000000..c888f8d --- /dev/null +++ b/Assets/Minigames/Scripts/AbstractMinigameController.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +/// +/// Shared abstract class for the minigameControllers +/// +public abstract class AbstractMinigameController : AbstractFeedback +{ + [Header("AbstractVariables")] + /// + /// We keep the minigamelist so that the minigame-index doesn't get reset + /// DO NOT REMOVE + /// + public MinigameList minigamelist; + + /// + /// A bool to denote whether or not the game is still being played + /// + protected bool gameIsActive; + + /// + /// Reference to the progress bar + /// + public Slider feedbackProgress; + + /// + /// Reference to the current user + /// + private User user; + + /// + /// Reference to the minigame ScriptableObject + /// + protected Minigame minigame; + + /// + /// Each minigame has a webcamTexture, this will be used in children-methods + /// + public RawImage webcamScreen; + + /// + /// Reference to the gameEnded panel, so we can update its display + /// + public GameObject gameEndedPanel; + + /// + /// The theme that will be used by the signpredictor, this needs to be passed from the concrete class. + /// This theme CAN be different from the theme that words are fetched from (Think SpellingBee and Hangman) + /// + protected abstract Theme signPredictorTheme + { + get; + } + + /// + /// Start is called before the first frame update, seal it to prevent minigames from changing it + /// + protected void Start() + { + // Get the scriptable of the current minigame + minigame = minigamelist.minigames[minigamelist.currentMinigameIndex]; + + // Start the game-specific start-logic + StartController(); + + // Prepare the signPredictor + signPredictor.SetModel(signPredictorTheme.modelIndex); + signPredictor.SwapScreen(webcamScreen); + signPredictor.SetSignsList(GetSignsList()); + AddSelfAsListener(); + } + + /// + /// All minigames use the same principle, they grab the most probable sign and use said sign to show feedback to the user + /// Because we don't want minigames to write their own UpdateFeedbacks this function will be sealed + /// + /// + /// + protected override sealed IEnumerator UpdateFeedback() + { + // Get the predicted sign + if (signPredictor != null && signPredictor.learnableProbabilities != null && gameIsActive) + { + // Get highest predicted sign + string predictedSign = signPredictor.learnableProbabilities.Aggregate((a, b) => a.Value > b.Value ? a : b).Key; + float accuracy = signPredictor.learnableProbabilities[predictedSign]; + + // vvv TEMPORARY STUFF vvv + if (predictedSign == "J" && accuracy <= 0.97f) + { + predictedSign = signPredictor.learnableProbabilities.Aggregate((x, y) => x.Value > y.Value && x.Key != "J" ? x : y).Key; + } + accuracy = signPredictor.learnableProbabilities[predictedSign]; + // ^^^ TEMPORARY STUFF ^^^ + + ProcessMostProbableSign(accuracy, predictedSign); + } + + // This part is the only reason that feedbackProgress is needed in the abstract + else if (feedbackProgress != null) + { + + feedbackProgress.value = 0.0f; + } + + yield return null; + } + + /// + /// Each game keeps a score, this score needs to be saved at some point + /// + public void SaveScores() + { + // Calculate new score + int newScore = CalculateScore(); + + // Save the score as a tuple: < int score, string time ago> + Score score = new Score(); + score.scoreValue = newScore; + score.time = DateTime.Now.ToString(); + + // Save the new score + var progress = user.GetMinigameProgress(minigame.index); + + // Get the current list of scores + List latestScores = progress.latestScores; + List highestScores = progress.highestScores; + + // Add the new score + latestScores.Add(score); + highestScores.Add(score); + + // Sort the scores + highestScores.Sort((a, b) => b.scoreValue.CompareTo(a.scoreValue)); + + // Only save the top 10 scores, so this list doesn't keep growing endlessly + progress.latestScores = latestScores.Take(10).ToList(); + progress.highestScores = highestScores.Take(10).ToList(); + + PersistentDataController.GetInstance().Save(); + } + /// + /// The function that activates when the game ends, handles some endgame logic and displays the EndPanel + /// + /// + public void ActivateEnd(bool victory) + { + EndGameLogic(victory); + SaveScores(); + SetScoreBoard(victory); + + gameEndedPanel.SetActive(true); + } + + /// + /// Once the most probable sign has been fetched, they can be processed + /// + /// The accuracy of the passed sign + /// The name of the passed sign + protected abstract void ProcessMostProbableSign(float accuracy, string predictedSign); + + /// + /// Each minigame has their own way of calculating their score + /// + /// The score that the user has at that point + public abstract int CalculateScore(); + + /// + /// Each minigame has an AbstractGameEndedPanel at the end, but they each have their own unique concrete instance + /// + /// 1 if the player won, 0 if they lost. Some games need this + protected abstract void SetScoreBoard(bool victory); + + /// + /// Each minigame puts their GameLogic to be called at (re)start in a seperate function from Start() + /// + public void StartController() + { + StartGameLogic(); + + // Create entry in current user for keeping track of progress + user = UserList.GetCurrentUser(); + var progress = user.GetMinigameProgress(minigame.index); + if (progress == null) + { + progress = new PersistentDataController.SavedMinigameProgress(); + progress.minigameIndex = minigame.index; + user.AddMinigameProgress(progress); + } + UserList.Save(); + } + + /// + /// Logic to be called at the start of the game + /// + protected abstract void StartGameLogic(); + + /// + /// Function that contains all the logic to end the game + /// + /// 1 if the player won, 0 if they lost. Some games need this + protected abstract void EndGameLogic(bool victory); + + /// + /// All non-fingerspelling-minigames have the same logic for the GetSignsList + /// + /// The signsList that needs to be passed to the signPredictor + private List GetSignsList() + { + List signsList = new List(); + foreach (Learnable learnable in signPredictorTheme.learnables) + { + signsList.Add(learnable.name); + } + + return signsList; + } +} diff --git a/Assets/Minigames/Scripts/AbstractMinigameController.cs.meta b/Assets/Minigames/Scripts/AbstractMinigameController.cs.meta new file mode 100644 index 0000000..a91101a --- /dev/null +++ b/Assets/Minigames/Scripts/AbstractMinigameController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a32c0ecc5507e4542a79c1b96a47b0a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Minigames/Scripts/MinigameScripts.asmdef b/Assets/Minigames/Scripts/MinigameScripts.asmdef new file mode 100644 index 0000000..96a7380 --- /dev/null +++ b/Assets/Minigames/Scripts/MinigameScripts.asmdef @@ -0,0 +1,20 @@ +{ + "name": "MinigameScripts", + "rootNamespace": "", + "references": [ + "GUID:d0b6b39a21908f94fbbd9f2c196a9725", + "GUID:e83ddf9a537a96b4a804a16bb7872ec1", + "GUID:1631ed2680c61245b8211d943c1639a8", + "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25", + "GUID:6055be8ebefd69e48b49212b09b47b2f" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Editor/Unity.Barracuda.Editor.asmdef.meta b/Assets/Minigames/Scripts/MinigameScripts.asmdef.meta similarity index 76% rename from Packages/com.unity.barracuda/Editor/Unity.Barracuda.Editor.asmdef.meta rename to Assets/Minigames/Scripts/MinigameScripts.asmdef.meta index 7f0c301..9b1396f 100644 --- a/Packages/com.unity.barracuda/Editor/Unity.Barracuda.Editor.asmdef.meta +++ b/Assets/Minigames/Scripts/MinigameScripts.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9f1e7d835703842dda0e25142ed6c3c9 +guid: 403dd94a93598934eb522dc36df43d7b AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Assets/SpellingBee/PlayModeTests/GameControllerTests.cs b/Assets/SpellingBee/PlayModeTests/GameControllerTests.cs deleted file mode 100644 index b115206..0000000 --- a/Assets/SpellingBee/PlayModeTests/GameControllerTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Collections; -using System.Linq; -using System.IO; - -using NUnit.Framework; -using TMPro; -using UnityEngine; -using UnityEngine.TestTools; -using UnityEngine.SceneManagement; - - -public class GameControllerTests -{ - - [UnitySetUp] - public IEnumerator SetupFunction() - { - string path = $"{Application.persistentDataPath}/unit_test_users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; - - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } - - SystemController.GetInstance().LoadNextScene("SpellingBee/Scenes/Game"); - yield return new WaitForSeconds(0.2f); - } - - [UnityTest] - public IEnumerator CheckScoreTest() - { - GameController gameController = (GameController)GameObject.FindObjectOfType(typeof(GameController)); - yield return new WaitForSeconds(0.2f); - Assert.AreEqual(0, gameController.CalculateScore()); - gameController.NextWord(); - Assert.AreEqual(5, gameController.CalculateScore()); - gameController.NextLetter(true); - Assert.AreEqual(6, gameController.CalculateScore()); - } - - [UnityTest] - public IEnumerator ActivateGameOverTest() - { - GameController gameController = (GameController)GameObject.FindObjectOfType(typeof(GameController)); - gameController.ActivateGameOver(); - - yield return new WaitForSeconds(0.2f); - GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel)); - Assert.NotNull(gameEndedPanel); - Assert.AreEqual("VERLOREN", gameEndedPanel.endText.text); - - } - - [UnityTest] - public IEnumerator ActivateWinTests() - { - GameController gameController = (GameController)GameObject.FindObjectOfType(typeof(GameController)); - gameController.ActivateWin(); - - yield return new WaitForSeconds(0.2f); - GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel)); - Assert.NotNull(gameEndedPanel); - Assert.AreEqual("GEWONNEN", gameEndedPanel.endText.text); - } - - [UnityTest] - public IEnumerator CheckGameOverTest() - { - GameController gameController = (GameController)GameObject.FindObjectOfType(typeof(GameController)); - gameController.AddSeconds(-60); - - yield return new WaitForSeconds(0.1f); - GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel)); - Assert.NotNull(gameEndedPanel); - Assert.AreEqual("VERLOREN", gameEndedPanel.endText.text); - } -} diff --git a/Assets/SpellingBee/PlayModeTests/GameEndedPanelTests.cs b/Assets/SpellingBee/PlayModeTests/GameEndedPanelTests.cs index 0f9a041..df4428a 100644 --- a/Assets/SpellingBee/PlayModeTests/GameEndedPanelTests.cs +++ b/Assets/SpellingBee/PlayModeTests/GameEndedPanelTests.cs @@ -1,52 +1,45 @@ -using System.Collections; -using System.Linq; -using System.IO; - using NUnit.Framework; -using TMPro; +using System.Collections; +using System.IO; +using UnityEditor; using UnityEngine; using UnityEngine.TestTools; -using UnityEngine.SceneManagement; - -public class GameEndedPanelTests +public class SpellingBeeGameEndedPanelTests { - [UnitySetUp] public IEnumerator SetupFunction() { string path = $"{Application.persistentDataPath}/unit_test_users.json"; - var oneUser = "{\"currentUserIndex\": 0,\"storedUsers\": [{\"username\": \"TEST\",\"avatar\": {\"instanceID\": 40848},\"playtime\": 0.0,\"courses\": [],\"minigames\": []}]}"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; - using (StreamWriter writer = new StreamWriter(path)) - { - writer.Write(oneUser); - } - - SystemController.GetInstance().LoadNextScene("SpellingBee/Scenes/Game"); + File.WriteAllText(path, oneUser); + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); + SystemController.GetInstance().LoadNextScene("SpellingBee/Scenes/SpellingBeeGame"); yield return new WaitForSeconds(0.2f); } [UnityTest] public IEnumerator ScoreTest() { - GameController gameController = (GameController)GameObject.FindObjectOfType(typeof(GameController)); - gameController.NextWord(); - gameController.NextLetter(false); - gameController.NextLetter(true); - gameController.NextLetter(false); + SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + spellingBeeController.NextWord(); + spellingBeeController.NextLetter(false); + spellingBeeController.NextLetter(true); + spellingBeeController.NextLetter(false); yield return new WaitForSeconds(1f); - gameController.ActivateWin(); + spellingBeeController.ActivateEnd(true); - GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel)); - Assert.NotNull(gameEndedPanel); - Assert.AreEqual("Score: 6", gameEndedPanel.scoreText.text); - Assert.AreEqual("1", gameEndedPanel.lettersRightText.text); - Assert.AreEqual("2", gameEndedPanel.lettersWrongText.text); - Assert.AreEqual("3", gameEndedPanel.lettersTotalText.text); - Assert.AreEqual("00:01", gameEndedPanel.timeText.text); + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel)); + Assert.NotNull(SpellingBeeGameEndedPanel); + Assert.AreEqual("Score: 0", SpellingBeeGameEndedPanel.scoreText.text); + Assert.AreEqual("1", SpellingBeeGameEndedPanel.lettersRightText.text); + Assert.AreEqual("2", SpellingBeeGameEndedPanel.lettersWrongText.text); + Assert.AreEqual("3", SpellingBeeGameEndedPanel.lettersTotalText.text); + Assert.AreEqual("00:01", SpellingBeeGameEndedPanel.timeText.text); } } diff --git a/Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs b/Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs new file mode 100644 index 0000000..d8db61d --- /dev/null +++ b/Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs @@ -0,0 +1,71 @@ +using NUnit.Framework; +using System.Collections; +using System.IO; +using UnityEditor; +using UnityEngine; +using UnityEngine.TestTools; + +public class SpellingBeeControllerTests +{ + [UnitySetUp] + public IEnumerator SetupFunction() + { + string path = $"{Application.persistentDataPath}/unit_test_users.json"; + string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + + File.WriteAllText(path, oneUser); + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); + SystemController.GetInstance().LoadNextScene("SpellingBee/Scenes/SpellingBeeGame"); + yield return new WaitForSeconds(0.2f); + } + + [UnityTest] + public IEnumerator CheckScoreTest() + { + SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + yield return new WaitForSeconds(0.2f); + Assert.AreEqual(0, spellingBeeController.CalculateScore()); + spellingBeeController.NextWord(); + Assert.AreEqual(0, spellingBeeController.CalculateScore()); + spellingBeeController.NextLetter(true); + Assert.AreEqual(10, spellingBeeController.CalculateScore()); + } + + [UnityTest] + public IEnumerator ActivateGameOverTest() + { + SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + spellingBeeController.ActivateEnd(false); + + yield return new WaitForSeconds(0.2f); + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel)); + Assert.NotNull(SpellingBeeGameEndedPanel); + Assert.AreEqual("VERLOREN", SpellingBeeGameEndedPanel.endText.text); + + } + + [UnityTest] + public IEnumerator ActivateWinTests() + { + SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + spellingBeeController.ActivateEnd(true); + + yield return new WaitForSeconds(0.2f); + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel)); + Assert.NotNull(SpellingBeeGameEndedPanel); + Assert.AreEqual("GEWONNEN", SpellingBeeGameEndedPanel.endText.text); + } + + [UnityTest] + public IEnumerator CheckGameOverTest() + { + SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + spellingBeeController.AddSeconds(-60); + + yield return new WaitForSeconds(0.1f); + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel)); + Assert.NotNull(SpellingBeeGameEndedPanel); + Assert.AreEqual("VERLOREN", SpellingBeeGameEndedPanel.endText.text); + } +} diff --git a/Assets/SpellingBee/PlayModeTests/GameControllerTests.cs.meta b/Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs.meta similarity index 100% rename from Assets/SpellingBee/PlayModeTests/GameControllerTests.cs.meta rename to Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs.meta diff --git a/Assets/SpellingBee/PlayModeTests/SpellingBeePlayModeTests.asmdef b/Assets/SpellingBee/PlayModeTests/SpellingBeePlayModeTests.asmdef index a332ab7..90cc80d 100644 --- a/Assets/SpellingBee/PlayModeTests/SpellingBeePlayModeTests.asmdef +++ b/Assets/SpellingBee/PlayModeTests/SpellingBeePlayModeTests.asmdef @@ -7,7 +7,10 @@ "InterfacesScripts", "Unity.TextMeshPro", "SpellingBeeScripts", - "AccountsScripts" + "AccountsScripts", + "ArchitectureScripts", + "SignPredictor", + "MinigameScripts" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/SpellingBee/Prefabs/Letter.prefab b/Assets/SpellingBee/Prefabs/Letter.prefab index b65670f..fdcf5b5 100644 --- a/Assets/SpellingBee/Prefabs/Letter.prefab +++ b/Assets/SpellingBee/Prefabs/Letter.prefab @@ -145,8 +145,8 @@ MonoBehaviour: m_Calls: [] m_text: A m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] diff --git a/Assets/SpellingBee/Prefabs/ScoreboardEntry.prefab b/Assets/SpellingBee/Prefabs/ScoreboardEntry.prefab index 1f7a6fa..00bd74e 100644 --- a/Assets/SpellingBee/Prefabs/ScoreboardEntry.prefab +++ b/Assets/SpellingBee/Prefabs/ScoreboardEntry.prefab @@ -68,8 +68,8 @@ MonoBehaviour: m_Calls: [] m_text: Player name m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -279,8 +279,8 @@ MonoBehaviour: m_Calls: [] m_text: xh m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -414,8 +414,8 @@ MonoBehaviour: m_Calls: [] m_text: xxx m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -549,8 +549,8 @@ MonoBehaviour: m_Calls: [] m_text: 1 m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] diff --git a/Assets/SpellingBee/Scenes/Game.unity b/Assets/SpellingBee/Scenes/SpellingBeeGame.unity similarity index 86% rename from Assets/SpellingBee/Scenes/Game.unity rename to Assets/SpellingBee/Scenes/SpellingBeeGame.unity index 0f7aabc..4d0fafa 100644 --- a/Assets/SpellingBee/Scenes/Game.unity +++ b/Assets/SpellingBee/Scenes/SpellingBeeGame.unity @@ -191,8 +191,8 @@ MonoBehaviour: m_Calls: [] m_text: XXX m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -326,6 +326,217 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &160423966 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 160423967} + - component: {fileID: 160423969} + - component: {fileID: 160423968} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &160423967 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160423966} + m_LocalRotation: {x: 0, y: -1, z: 0, w: 0} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 180, y: 0, z: 180} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &160423968 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160423966} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: b64232b71c9f17a4d9494ad951a74dfa, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &160423969 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 160423966} + m_CullTransparentMesh: 1 +--- !u!1 &229512365 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 229512366} + - component: {fileID: 229512368} + - component: {fileID: 229512367} + m_Layer: 5 + m_Name: Game Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &229512366 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 229512365} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 906197777} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -25} + m_SizeDelta: {x: 1200, y: 100} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &229512367 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 229512365} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Spelling Bee + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 90 + m_fontSizeBase: 90 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 1 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &229512368 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 229512365} + m_CullTransparentMesh: 1 --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -478,8 +689,8 @@ MonoBehaviour: m_Calls: [] m_text: XXX% m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -681,8 +892,8 @@ MonoBehaviour: m_Calls: [] m_text: Tijd m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -816,8 +1027,8 @@ MonoBehaviour: m_Calls: [] m_text: Accuraatheid m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -959,8 +1170,8 @@ MonoBehaviour: m_Calls: [] m_text: 'Score: XXX' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -1047,7 +1258,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_RootOrder - value: 7 + value: 8 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchorMax.x @@ -1067,11 +1278,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.x - value: 300 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_SizeDelta.y - value: 120 + value: 50 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalPosition.x @@ -1103,11 +1314,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -10 objectReference: {fileID: 0} - target: {fileID: 8299246693487308515, guid: 3bccdf365a4fbea4d8fa1aa461d3dc5c, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -1164,7 +1375,7 @@ RectTransform: - {fileID: 1761838460} - {fileID: 862382568} m_Father: {fileID: 906197777} - m_RootOrder: 6 + m_RootOrder: 9 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1221,7 +1432,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 5aa929dce1f59b340b4a0cca1bb68edc, type: 3} m_Name: m_EditorClassIdentifier: - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} + scoreboardEntriesContainer: {fileID: 1499197559} + scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3} endText: {fileID: 1502459770} lpmText: {fileID: 1172084829} lettersRightText: {fileID: 994850063} @@ -1231,8 +1443,6 @@ MonoBehaviour: wordsText: {fileID: 1754130538} timeText: {fileID: 1052827058} scoreText: {fileID: 653157662} - scoreboardEntriesContainer: {fileID: 1499197559} - scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3} --- !u!1 &778704239 GameObject: m_ObjectHideFlags: 0 @@ -1295,8 +1505,8 @@ MonoBehaviour: ' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -1575,14 +1785,16 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: + - {fileID: 160423967} + - {fileID: 229512366} + - {fileID: 1843239269} + - {fileID: 1985911005} - {fileID: 1743003086} - {fileID: 1338727893} - {fileID: 1346005056} - - {fileID: 1843239269} - - {fileID: 1812475781} - {fileID: 967164044} - - {fileID: 757133118} - {fileID: 667202413} + - {fileID: 757133118} m_Father: {fileID: 1768150806} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -1604,14 +1816,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_Color: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Sprite: {fileID: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1638,31 +1850,31 @@ PrefabInstance: m_Modifications: - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_Pivot.x - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_Pivot.y - value: 1 + value: 0.5 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_RootOrder - value: 5 + value: 7 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_AnchorMax.x - value: 1 + value: 0.5 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0.5 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_AnchorMin.x - value: 1 + value: 0.5 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0.5 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_SizeDelta.x @@ -1702,11 +1914,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_AnchoredPosition.x - value: -200 + value: 71 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_AnchoredPosition.y - value: -600 + value: -200 objectReference: {fileID: 0} - target: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_LocalEulerAnglesHint.x @@ -1728,6 +1940,34 @@ PrefabInstance: propertyPath: m_Name value: Feedback objectReference: {fileID: 0} + - target: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_fontStyle + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_fontColor.b + value: 0.23921569 + objectReference: {fileID: 0} + - target: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_fontColor.g + value: 0.28627452 + objectReference: {fileID: 0} + - target: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_fontColor.r + value: 0.9607843 + objectReference: {fileID: 0} + - target: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_fontColor32.rgba + value: 4282206709 + objectReference: {fileID: 0} + - target: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_VerticalAlignment + value: 512 + objectReference: {fileID: 0} + - target: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + propertyPath: m_HorizontalAlignment + value: 1 + objectReference: {fileID: 0} - target: {fileID: 4318122120334233317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -1741,13 +1981,35 @@ RectTransform: m_PrefabAsset: {fileID: 0} --- !u!114 &967164045 stripped MonoBehaviour: - m_CorrespondingSourceObject: {fileID: 4318122119930585317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_CorrespondingSourceObject: {fileID: 4318122120334233319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} m_PrefabInstance: {fileID: 967164043} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 44e682a32ee15cc489bf50f3a06f717b, type: 3} + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &967164046 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4318122119968934242, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 967164043} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 67db9e8f0e2ae9c40bc1e2b64352a6b4, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &967164047 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3} + m_PrefabInstance: {fileID: 967164043} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} m_Name: m_EditorClassIdentifier: --- !u!1 &978093274 @@ -1810,8 +2072,8 @@ MonoBehaviour: m_Calls: [] m_text: Letters m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -2166,8 +2428,8 @@ MonoBehaviour: m_Calls: [] m_text: XXX m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -2233,6 +2495,141 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &1130901868 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1130901869} + - component: {fileID: 1130901871} + - component: {fileID: 1130901870} + m_Layer: 5 + m_Name: Timing Feedback + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1130901869 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1130901868} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1985911005} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 75} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0} +--- !u!114 &1130901870 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1130901868} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: +10 + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4284404875 + m_fontColor: {r: 0.54509807, g: 0.83137256, b: 0.36862746, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 60 + m_fontSizeBase: 60 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1130901871 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1130901868} + m_CullTransparentMesh: 1 --- !u!1 &1172084826 GameObject: m_ObjectHideFlags: 0 @@ -2301,8 +2698,8 @@ MonoBehaviour: m_Calls: [] m_text: XXX LPM m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -2428,8 +2825,8 @@ MonoBehaviour: m_Calls: [] m_text: Replay m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -2563,8 +2960,8 @@ MonoBehaviour: m_Calls: [] m_text: Gebruiker m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -2765,8 +3162,8 @@ MonoBehaviour: ' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -2990,13 +3387,13 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 1 + m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 1, y: 1} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: -325, y: -300} - m_SizeDelta: {x: 250, y: 250} - m_Pivot: {x: 1, y: 1} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -123, y: 110} + m_SizeDelta: {x: 450, y: 450} + m_Pivot: {x: 1, y: 0.5} --- !u!1 &1346005055 GameObject: m_ObjectHideFlags: 0 @@ -3027,11 +3424,11 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 2 + m_RootOrder: 6 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0} m_AnchorMax: {x: 0.5, y: 0} - m_AnchoredPosition: {x: 0, y: 75} + m_AnchoredPosition: {x: 0, y: 125} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0} --- !u!114 &1346005057 @@ -3142,9 +3539,9 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 1768150807} - m_TargetAssemblyTypeName: GameController, SpellingBeeScripts - m_MethodName: Start + - m_Target: {fileID: 1496768391} + m_TargetAssemblyTypeName: SpellingBeeController, SpellingBeeScripts + m_MethodName: StartController m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} @@ -3252,8 +3649,8 @@ MonoBehaviour: m_Calls: [] m_text: Woorden m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -3389,8 +3786,8 @@ MonoBehaviour: ' m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -3540,6 +3937,67 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1422864840} m_CullTransparentMesh: 1 +--- !u!1 &1496768389 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1496768390} + - component: {fileID: 1496768391} + m_Layer: 0 + m_Name: SpellingBeeController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1496768390 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1496768389} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1496768391 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1496768389} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 44fbed5ae228de39b9f727def7578d06, type: 3} + m_Name: + m_EditorClassIdentifier: + signPredictor: {fileID: 1592592444} + minigamelist: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} + feedbackProgress: {fileID: 967164046} + webcamScreen: {fileID: 1743003084} + gameEndedPanel: {fileID: 757133117} + themeList: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2} + fingerspelling: {fileID: 11400000, guid: e02921b294fdad940b6e4d57e716d3bf, type: 2} + letterPrefab: {fileID: 4639383499500021565, guid: c3e66e8957864914cb022af914df6a28, type: 3} + letterContainer: {fileID: 1346005056} + wordImage: {fileID: 1338727891} + timerText: {fileID: 1843239267} + bonusTimeText: {fileID: 1812475780} + Scoreboard: {fileID: 862382568} + feedbackText: {fileID: 967164047} + feedbackProgressImage: {fileID: 967164045} + scoreDisplay: {fileID: 1985911006} + scoreBonus: {fileID: 1130901870} --- !u!1 &1499197558 GameObject: m_ObjectHideFlags: 0 @@ -3661,8 +4119,8 @@ MonoBehaviour: m_Calls: [] m_text: GAME OVER m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -3900,11 +4358,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 043ccd99cf82b3cc9bf2e00956ce2b93, type: 3} m_Name: m_EditorClassIdentifier: - model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3} + modelList: {fileID: 11400000, guid: 39516e4e6e56f0f4f80647d9c4d8034c, type: 2} modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3} + modelInfoFileEmbedding: {fileID: 4900000, guid: 4e303164823194bc4be87f4c9550cfd0, type: 3} configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3} screen: {fileID: 1743003084} - screen2: {fileID: 0} --- !u!4 &1592592445 Transform: m_ObjectHideFlags: 0 @@ -3980,8 +4438,8 @@ MonoBehaviour: m_Calls: [] m_text: Geleden m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -4093,7 +4551,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Texture: {fileID: 8400000, guid: 60bb0835fc4bbb043b9b3d8ef48f96a8, type: 2} + m_Texture: {fileID: 8400000, guid: b0382d4acabd441499108c97444d642a, type: 2} m_UVRect: serializedVersion: 2 x: 1 @@ -4117,17 +4575,17 @@ RectTransform: m_GameObject: {fileID: 1743003083} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} + m_LocalScale: {x: 0.75, y: 0.75, z: 0.75} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 906197777} - m_RootOrder: 0 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 200, y: -300} - m_SizeDelta: {x: 960, y: 540} - m_Pivot: {x: 0, y: 1} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 71, y: 110} + m_SizeDelta: {x: 900, y: 600} + m_Pivot: {x: 0, y: 0.5} --- !u!1 &1754130535 GameObject: m_ObjectHideFlags: 0 @@ -4196,8 +4654,8 @@ MonoBehaviour: m_Calls: [] m_text: XXX m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -4450,7 +4908,6 @@ GameObject: - component: {fileID: 1768150805} - component: {fileID: 1768150804} - component: {fileID: 1768150803} - - component: {fileID: 1768150807} m_Layer: 5 m_Name: Canvas m_TagString: Untagged @@ -4487,10 +4944,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 m_MatchWidthOrHeight: 0 m_PhysicalUnit: 3 @@ -4533,37 +4990,13 @@ RectTransform: m_Children: - {fileID: 906197777} m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} ---- !u!114 &1768150807 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1768150802} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 44fbed5ae228de39b9f727def7578d06, type: 3} - m_Name: - m_EditorClassIdentifier: - themeList: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2} - userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2} - minigame: {fileID: 11400000, guid: 8a087d241d652634eb4f6352267ea7dc, type: 2} - minigamelist: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2} - letterPrefab: {fileID: 4639383499500021565, guid: c3e66e8957864914cb022af914df6a28, type: 3} - letterContainer: {fileID: 1346005056} - wordImage: {fileID: 1338727891} - timerText: {fileID: 1843239267} - bonusTimeText: {fileID: 1812475780} - Scoreboard: {fileID: 862382568} - feedback: {fileID: 967164045} - gameEndedPanel: {fileID: 757133117} --- !u!1 &1812475780 GameObject: m_ObjectHideFlags: 0 @@ -4594,14 +5027,14 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 906197777} - m_RootOrder: 4 + m_Father: {fileID: 1843239269} + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 1} - m_AnchorMax: {x: 0.5, y: 1} - m_AnchoredPosition: {x: 0, y: -50} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 66, y: 75} m_SizeDelta: {x: 100, y: 100} - m_Pivot: {x: 0.5, y: 1} + m_Pivot: {x: 0.5, y: 0} --- !u!114 &1812475782 MonoBehaviour: m_ObjectHideFlags: 0 @@ -4624,15 +5057,15 @@ MonoBehaviour: m_Calls: [] m_text: +5 m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4280090368 - m_fontColor: {r: 0, g: 1, b: 0.11084986, a: 1} + rgba: 4284404875 + m_fontColor: {r: 0.54509807, g: 0.83137256, b: 0.36862746, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -4649,14 +5082,14 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 78 - m_fontSizeBase: 78 + m_fontSize: 60 + m_fontSizeBase: 60 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 m_fontStyle: 0 - m_HorizontalAlignment: 4 + m_HorizontalAlignment: 2 m_VerticalAlignment: 512 m_textAlignment: 65535 m_characterSpacing: 0 @@ -4739,15 +5172,15 @@ MonoBehaviour: m_Calls: [] m_text: 00:00 m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} - m_sharedMaterial: {fileID: -1030930060397404263, guid: 3602bedf0ebe5b64596873f09eddf57b, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4294967295 - m_fontColor: {r: 1, g: 1, b: 1, a: 1} + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -4771,7 +5204,7 @@ MonoBehaviour: m_fontSizeMin: 18 m_fontSizeMax: 72 m_fontStyle: 0 - m_HorizontalAlignment: 2 + m_HorizontalAlignment: 4 m_VerticalAlignment: 512 m_textAlignment: 65535 m_characterSpacing: 0 @@ -4825,14 +5258,15 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 1812475781} m_Father: {fileID: 906197777} - m_RootOrder: 3 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} - m_AnchoredPosition: {x: 0, y: -100} - m_SizeDelta: {x: 300, y: 150} + m_AnchoredPosition: {x: -252, y: -75} + m_SizeDelta: {x: 300, y: 100} m_Pivot: {x: 0.5, y: 1} --- !u!1 &1898716846 GameObject: @@ -5029,8 +5463,8 @@ MonoBehaviour: m_Calls: [] m_text: (letters per minuut) m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -5104,3 +5538,139 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1984101844} m_CullTransparentMesh: 1 +--- !u!1 &1985911004 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1985911005} + - component: {fileID: 1985911007} + - component: {fileID: 1985911006} + m_Layer: 5 + m_Name: Score + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1985911005 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1985911004} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1130901869} + m_Father: {fileID: 906197777} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 275, y: -75} + m_SizeDelta: {x: 450, y: 100} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &1985911006 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1985911004} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Score: XXX' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4284235525 + m_fontColor: {r: 0.019607844, g: 0.24705882, b: 0.36078432, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 78 + m_fontSizeBase: 78 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1985911007 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1985911004} + m_CullTransparentMesh: 1 diff --git a/Assets/SpellingBee/Scenes/Game.unity.meta b/Assets/SpellingBee/Scenes/SpellingBeeGame.unity.meta similarity index 100% rename from Assets/SpellingBee/Scenes/Game.unity.meta rename to Assets/SpellingBee/Scenes/SpellingBeeGame.unity.meta diff --git a/Assets/SpellingBee/ScriptableObjects/SpellingBee.asset b/Assets/SpellingBee/ScriptableObjects/SpellingBee.asset index f35d4e6..f9c8777 100644 --- a/Assets/SpellingBee/ScriptableObjects/SpellingBee.asset +++ b/Assets/SpellingBee/ScriptableObjects/SpellingBee.asset @@ -14,11 +14,9 @@ MonoBehaviour: m_EditorClassIdentifier: index: 0 title: Spelling Bee - description: In deze minigame krijg je verschillende woorden voorgeschoteld die - je zo snel mogelijk moet spellen met behulp van het vingeralfabet + description: Leer spellen als een pro themeList: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2} - thumbnail: {fileID: 21300000, guid: f2a020e24bfa24842bccecf6b36d5b79, type: 3} - minigameEntryPoint: SpellingBee/Scenes/Game - controls: Je begint dit spel met 5 seconden tijd, voor elk juist antwoord krijg - je extra tijd. Hoe sneller je het spel uitspeelt, hoe meer punten je scoort. - Verloopt de timer, dan heb je het spelletje verloren + thumbnail: {fileID: 21300000, guid: 99ff017f7243eeb4db0c08a6b832d744, type: 3} + minigameEntryPoint: SpellingBee/Scenes/SpellingBeeGame + controls: Een spelletje tegen de tijd. Spel zoveel mogelijk woorden binnen de tijd! + Voor elke juiste letter krijg je extra tijd, hou het zo lang mogelijk uit. diff --git a/Assets/SpellingBee/Scripts/GameController.cs b/Assets/SpellingBee/Scripts/GameController.cs deleted file mode 100644 index 94b5f95..0000000 --- a/Assets/SpellingBee/Scripts/GameController.cs +++ /dev/null @@ -1,456 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using TMPro; -using UnityEngine; -using UnityEngine.UI; - -public partial class GameController : MonoBehaviour -{ - /// - /// All of the words that can be used in this session - /// - //private string[] words; - private List words = new List(); - - /// - /// Where we currently are in the word - /// - private int letterIndex; - - /// - /// Where we currently are in the word list - /// - private int wordIndex; - - /// - /// The word that is currently being spelled - /// - private string currentWord; - - /// - /// All of the available themes - /// - public ThemeList themeList; - - /// - /// The theme we are currently using - /// - private Theme currentTheme; - - /// - /// Current value of timer in seconds - /// - private float timerValue; - - /// - /// Indicates if the game is still going - /// - private bool gameEnded; - - /// - /// Amount of seconds user gets per letter of the current word - /// Set to 1 for testing; should be increased later - /// - private const int secondsPerLetter = 5; - - /// - /// Counter that keeps track of how many letters have been spelled correctly - /// - private int correctLetters; - - /// - /// Counter that keeps track of how many letters have been spelled incorrectly - /// - private int incorrectLetters; - - /// - /// Counter that keeps track of how many words have been spelled correctly - /// - private int spelledWords; - - /// - /// Timer that keeps track of when the game was started - /// - private DateTime startTime; - - /// - /// Reference to the user list to access the current user - /// - public UserList userList; - - /// - /// Reference to the current user - /// - private User user; - - /// - /// Reference to the minigame ScriptableObject - /// - public Minigame minigame; - - /// - /// We keep the minigamelist as well so that the minigame-index doesn't get reset - /// DO NOT REMOVE - /// - public MinigameList minigamelist; - - /// - /// Letter prefab - /// - public GameObject letterPrefab; - - /// - /// Reference to letter container - /// - public Transform letterContainer; - - /// - /// The Image component for displaying the appropriate sprite - /// - public Image wordImage; - - /// - /// Timer display - /// - public TMP_Text timerText; - - /// - /// Bonus time display - /// - public GameObject bonusTimeText; - - /// - /// Timer to display the bonus time - /// - private float bonusActiveRemaining = 0.0f; - - /// - /// The GameObjects representing the letters - /// - private List letters = new List(); - - /// - /// Reference to the scoreboard - /// - public Transform Scoreboard; - - /// - /// Accuracy feeback object - /// - public Feedback feedback; - - /// - /// Reference to the gameEnded panel, so we can update its display - /// - public GameObject gameEndedPanel; - - /// - /// Start is called before the first frame update - /// - public void Start() - { - correctLetters = 0; - incorrectLetters = 0; - - words.Clear(); - // We use -1 instead of 0 so SetNextWord can simply increment it each time - spelledWords = -1; - wordIndex = 0; - - gameEnded = false; - timerValue = 30.0f; - bonusActiveRemaining = 0.0f; - startTime = DateTime.Now; - - gameEndedPanel.SetActive(false); - bonusTimeText.SetActive(false); - - // Create entry in current user for keeping track of progress - userList.Load(); - user = userList.GetCurrentUser(); - Progress progress = user.GetMinigameProgress(minigame.index); - if (progress == null) - { - progress = new Progress(); - progress.AddOrUpdate("minigameIndex", MinigameIndex.SPELLING_BEE); - progress.AddOrUpdate>("highestScores", new List()); - progress.AddOrUpdate>("latestScores", new List()); - user.minigames.Add(progress); - } - userList.Save(); - - currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex]; - feedback.signPredictor.model = currentTheme.model; - words.AddRange(currentTheme.learnables); - ShuffleWords(); - NextWord(); - - // Set calllbacks - feedback.getSignCallback = () => - { - if (letterIndex < currentWord.Length) - { - return currentWord[letterIndex].ToString().ToUpper(); - } - return null; - }; - feedback.predictSignCallback = (sign) => - { - bool successful = sign.ToUpper() == currentWord[letterIndex].ToString().ToUpper(); - if (successful) - { - AddSeconds(secondsPerLetter); - } - NextLetter(successful); - }; - } - - /// - /// Update is called once per frame - /// - public void Update() - { - if (!gameEnded) - { - timerValue -= Time.deltaTime; - if (bonusActiveRemaining <= 0.0 && bonusTimeText.activeSelf) - { - bonusTimeText.SetActive(false); - } - else - { - bonusActiveRemaining -= Time.deltaTime; - } - - if (timerValue <= 0.0f) - { - timerValue = 0.0f; - ActivateGameOver(); - } - - int minutes = Mathf.FloorToInt(timerValue / 60.0f); - int seconds = Mathf.FloorToInt(timerValue % 60.0f); - - timerText.text = string.Format("{0:00}:{1:00}", minutes, seconds); - - } - } - - /// - /// Randomly shuffle the list of words - /// - public void ShuffleWords() - { - for (int i = words.Count - 1; i > 0; i--) - { - // Generate a random index between 0 and i (inclusive) - int j = UnityEngine.Random.Range(0, i + 1); - - // Swap the values at indices i and j - (words[j], words[i]) = (words[i], words[j]); - } - } - - /// - /// Calculate the score - /// - /// The calculated score - public int CalculateScore() - { - return spelledWords * 5 + correctLetters; - } - - /// - /// Displays the game over panel and score values - /// - public void ActivateGameOver() - { - gameEnded = true; - DeleteWord(); - - // Save the scores and show the scoreboard - SaveScores(); - gameEndedPanel.GetComponent().GenerateContent( - startTime: startTime, - totalWords: spelledWords, - correctLetters: correctLetters, - incorrectLetters: incorrectLetters, - result: "VERLOREN", - score: CalculateScore() - ); - - gameEndedPanel.SetActive(true); - } - - /// - /// Display win screen - /// - public void ActivateWin() - { - gameEnded = true; - DeleteWord(); - - // Save the scores and show the scoreboard - SaveScores(); - gameEndedPanel.GetComponent().GenerateContent( - startTime: startTime, - totalWords: spelledWords, - correctLetters: correctLetters, - incorrectLetters: incorrectLetters, - result: "GEWONNEN", - score: CalculateScore() - ); - - gameEndedPanel.SetActive(true); - } - - /// - /// Update and save the scores - /// - public void SaveScores() - { - // Calculate new score - int newScore = CalculateScore(); - - // Save the score as a tuple: < int score, string time ago> - Score score = new Score(); - score.scoreValue = newScore; - score.time = DateTime.Now.ToString(); - - // Save the new score - user = userList.GetCurrentUser(); - Progress progress = user.GetMinigameProgress(minigame.index); - - // Get the current list of scores - List latestScores = progress.Get>("latestScores"); - List highestScores = progress.Get>("highestScores"); - - // Add the new score - latestScores.Add(score); - highestScores.Add(score); - - // Sort the scores - highestScores.Sort((a, b) => b.scoreValue.CompareTo(a.scoreValue)); - - // Only save the top 10 scores, so this list doesn't keep growing endlessly - progress.AddOrUpdate>("latestScores", latestScores.Take(10).ToList()); - progress.AddOrUpdate>("highestScores", highestScores.Take(10).ToList()); - - userList.Save(); - } - - /// - /// Delete all letter objects - /// - public void DeleteWord() - { - for (int i = 0; i < letters.Count; i++) - { - Destroy(letters[i]); - } - letters.Clear(); - } - - /// - /// Adds seconds to timer - /// - /// - public void AddSeconds(int seconds) - { - timerValue += (float)seconds; - bonusTimeText.SetActive(true); - bonusActiveRemaining = 2.0f; - } - - /// - /// Display the next letter - /// - /// true if the letter was correctly signed, false otherwise - public void NextLetter(bool successful) - { - if (gameEnded) { return; } - - // Change color of current letter (skip spaces) - if (successful) - { - correctLetters++; - letters[letterIndex].GetComponent().color = Color.green; - } - else - { - incorrectLetters++; - letters[letterIndex].GetComponent().color = new Color(0.5f, 0.0f, 0.0f); - } - - do - { - letterIndex++; - } while (letterIndex < currentWord.Length && currentWord[letterIndex] == ' '); - - // Change the color of the next letter or change to new word - if (letterIndex < currentWord.Length) - { - letters[letterIndex].GetComponent().color = Color.yellow; - } - else - { - StartCoroutine(Wait()); - NextWord(); - } - } - - /// - /// Display next word in the series - /// - public void NextWord() - { - DeleteWord(); - spelledWords++; - - if (wordIndex < words.Count) - { - currentWord = words[wordIndex].name; - letterIndex = 0; - - DisplayWord(currentWord); - wordIndex++; - } - else - { - ActivateWin(); - } - } - - /// - /// Displays the word that needs to be spelled - /// - /// The word to display - public void DisplayWord(string word) - { - for (int i = 0; i < word.Length; i++) - { - // Create instance of prefab - GameObject instance = GameObject.Instantiate(letterPrefab, letterContainer); - letters.Add(instance); - - // Dynamically load appearance - char c = Char.ToUpper(word[i]); - Image background = instance.GetComponent(); - background.color = i == 0 ? Color.yellow : c != ' ' ? Color.red : Color.clear; - TMP_Text txt = instance.GetComponentInChildren(); - txt.text = Char.ToString(c); - } - wordImage.sprite = words[wordIndex].image; - } - - /// - /// wait for 2 seconds - /// - /// - private IEnumerator Wait() - { - yield return new WaitForSecondsRealtime(2); - } -} diff --git a/Assets/SpellingBee/Scripts/GameController.cs.meta b/Assets/SpellingBee/Scripts/GameController.cs.meta deleted file mode 100644 index be352cc..0000000 --- a/Assets/SpellingBee/Scripts/GameController.cs.meta +++ /dev/null @@ -1,25 +0,0 @@ -fileFormatVersion: 2 -guid: 44fbed5ae228de39b9f727def7578d06 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: - - input: {instanceID: 0} - - endText: {instanceID: 0} - - correctWordsText: {instanceID: 0} - - correctLettersText: {instanceID: 0} - - gameEndedPanel: {instanceID: 0} - - replayButton: {instanceID: 0} - - userList: {instanceID: 0} - - minigame: {instanceID: 0} - - letterPrefab: {instanceID: 0} - - letterContainer: {instanceID: 0} - - wordImage: {instanceID: 0} - - timerText: {instanceID: 0} - - Scoreboard: {instanceID: 0} - - scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3} - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SpellingBee/Scripts/SpellingBeeController.cs b/Assets/SpellingBee/Scripts/SpellingBeeController.cs new file mode 100644 index 0000000..37f41b2 --- /dev/null +++ b/Assets/SpellingBee/Scripts/SpellingBeeController.cs @@ -0,0 +1,637 @@ +using DigitalRuby.Tween; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public partial class SpellingBeeController : AbstractMinigameController +{ + /// + /// All of the words that can be used in this session + /// + //private string[] words; + private List words = new List(); + + /// + /// Where we currently are in the word + /// + private int letterIndex; + + /// + /// Where we currently are in the word list + /// + private int wordIndex; + + /// + /// The word that is currently being spelled + /// + private string currentWord; + + /// + /// All of the available themes + /// + public ThemeList themeList; + + /// + /// The theme we are currently using + /// + private Theme currentTheme; + + /// + /// Current value of timer in seconds + /// + private float timerValue; + + /// + /// List of learnables to get the threshold for the letters + /// + public Theme fingerspelling; + + /// + /// Amount of seconds user gets per letter of the current word + /// Set to 1 for testing; should be increased later + /// + private const int secondsPerLetter = 5; + + /// + /// Counter that keeps track of how many letters have been spelled correctly + /// + private int correctLetters; + + /// + /// Counter that keeps track of how many letters have been spelled incorrectly + /// + private int incorrectLetters; + + /// + /// Counter that keeps track of how many words have been spelled correctly + /// + private int spelledWords; + + /// + /// Timer that keeps track of when the game was started + /// + private DateTime startTime; + + /// + /// Letter prefab + /// + public GameObject letterPrefab; + + /// + /// Reference to letter container + /// + public Transform letterContainer; + + /// + /// The Image component for displaying the appropriate sprite + /// + public Image wordImage; + + /// + /// Timer display + /// + public TMP_Text timerText; + + /// + /// Bonus time display + /// + public GameObject bonusTimeText; + + /// + /// Timer to display the bonus time + /// + private float bonusActiveRemaining = 0.0f; + + /// + /// The GameObjects representing the letters + /// + private List letters = new List(); + + /// + /// Reference to the scoreboard + /// + public Transform Scoreboard; + + /// + /// Reference to the feedback field + /// + public TMP_Text feedbackText; + + /// + /// Reference to the progress bar image, so we can add fancy colors + /// + public Image feedbackProgressImage; + + /// + /// Timer to keep track of how long a incorrect sign is performed + /// + protected DateTime timer; + + /// + /// Current predicted sign + /// + protected string predictedSign = null; + + /// + /// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs + /// + protected string previousIncorrectSign = null; + + /// + /// Reference to display the score + /// + public TMP_Text scoreDisplay; + + /// + /// Reference to display the points lost/won + /// + public TMP_Text scoreBonus; + + /// + /// Score obtained when spelling a letter + /// + private int correctLettersScore = 10; + + /// + /// Score obtained when spelling the wrong letter :o + /// + private int incorrectLettersScore = -5; + + /// + /// Set the AbstractMinigameController variable to inform it of the theme for the signPredictor + /// + protected override Theme signPredictorTheme + { + get { return fingerspelling; } + } + + /// + /// Update is called once per frame + /// + public void Update() + { + if (gameIsActive) + { + timerValue -= Time.deltaTime; + if (bonusActiveRemaining <= 0.0 && bonusTimeText.activeSelf) + { + bonusTimeText.SetActive(false); + scoreBonus.text = ""; + } + else + { + bonusActiveRemaining -= Time.deltaTime; + } + + if (timerValue <= 0.0f) + { + timerValue = 0.0f; + //ActivateGameOver(); + ActivateEnd(false); + } + + int minutes = Mathf.FloorToInt(timerValue / 60.0f); + int seconds = Mathf.FloorToInt(timerValue % 60.0f); + + timerText.text = string.Format("{0:00}:{1:00}", minutes, seconds); + + } + } + + /// + /// Randomly shuffle the list of words + /// + public void ShuffleWords() + { + for (int i = words.Count - 1; i > 0; i--) + { + // Generate a random index between 0 and i (inclusive) + int j = UnityEngine.Random.Range(0, i + 1); + + // Swap the values at indices i and j + (words[j], words[i]) = (words[i], words[j]); + } + } + + /// + /// Calculate the score + /// + /// The calculated score + public override int CalculateScore() + { + return correctLetters * correctLettersScore + incorrectLetters * incorrectLettersScore; + } + + /// + /// Delete all letter objects + /// + public void DeleteWord() + { + for (int i = 0; i < letters.Count; i++) + { + Destroy(letters[i]); + } + letters.Clear(); + } + + /// + /// Adds seconds to timer + /// + /// + public void AddSeconds(int seconds) + { + timerValue += (float)seconds; + bonusTimeText.SetActive(true); + bonusActiveRemaining = 1.0f; + } + + /// + /// Display the next letter + /// + /// true if the letter was correctly signed, false otherwise + public void NextLetter(bool successful) + { + if (!gameIsActive) { return; } + + // Change color of current letter (skip spaces) + if (successful) + { + correctLetters++; + letters[letterIndex].GetComponent().color = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); + scoreDisplay.text = $"Score: {CalculateScore()}"; + scoreBonus.text = $"+{correctLettersScore}"; + scoreBonus.color = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); + } + else + { + incorrectLetters++; + letters[letterIndex].GetComponent().color = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + scoreDisplay.text = $"Score: {CalculateScore()}"; + scoreBonus.text = $"{incorrectLettersScore}"; + scoreBonus.color = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + } + + do + { + letterIndex++; + } while (letterIndex < currentWord.Length && currentWord[letterIndex] == ' '); + + // Change the color of the next letter or change to new word + if (letterIndex < currentWord.Length) + { + letters[letterIndex].GetComponent().color = new Color(0x9f / 255.0f, 0xe7 / 255.0f, 0xf5 / 255.0f); + } + else + { + StartCoroutine(Wait()); + NextWord(); + } + } + + /// + /// Display next word in the series + /// + public void NextWord() + { + DeleteWord(); + spelledWords++; + + if (wordIndex < words.Count) + { + currentWord = words[wordIndex].name; + letterIndex = 0; + + DisplayWord(currentWord); + wordIndex++; + } + else + { + //ActivateWin(); + ActivateEnd(true); + } + } + + /// + /// Displays the word that needs to be spelled + /// + /// The word to display + public void DisplayWord(string word) + { + for (int i = 0; i < word.Length; i++) + { + // Create instance of prefab + GameObject instance = GameObject.Instantiate(letterPrefab, letterContainer); + letters.Add(instance); + + // Dynamically load appearance + char c = Char.ToUpper(word[i]); + Image background = instance.GetComponent(); + background.color = i == 0 ? new Color(0x9f / 255.0f, 0xe7 / 255.0f, 0xf5 / 255.0f) : Color.clear; + TMP_Text txt = instance.GetComponentInChildren(); + txt.text = Char.ToString(c); + } + wordImage.sprite = words[wordIndex].image; + } + + /// + /// wait for 2 seconds + /// + /// + private IEnumerator Wait() + { + yield return new WaitForSecondsRealtime(2); + } + + /// + /// Get the threshold for a given sign + /// + /// + /// + private float GetTresholdPercentage(string sign) + { + Learnable letter = fingerspelling.learnables.Find(l => l.name == sign); + return letter.thresholdPercentage; + } + /* + /// + /// The updateFunction that is called when new probabilities become available + /// + /// + protected override IEnumerator UpdateFeedback() + { + // Get current sign + string currentSign = GetSign(); + // Get the predicted sign + if (signPredictor != null && signPredictor.learnableProbabilities != null && + currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign) && gameIsActive) + { + float accCurrentSign = signPredictor.learnableProbabilities[currentSign]; + float thresholdCurrentSign = GetTresholdPercentage(currentSign); + + // Get highest predicted sign + string predictedSign = signPredictor.learnableProbabilities.Aggregate((a, b) => a.Value > b.Value ? a : b).Key; + float accPredictSign = signPredictor.learnableProbabilities[predictedSign]; + float thresholdPredictedSign = GetTresholdPercentage(predictedSign); + + if (feedbackText != null && feedbackProgressImage != null) + { + Color col; + if (accCurrentSign > thresholdCurrentSign) + { + feedbackText.text = "Goed"; + col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); + } + else if (accCurrentSign > 0.9 * thresholdCurrentSign) + { + feedbackText.text = "Bijna..."; + col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f); + } + else if (accPredictSign > thresholdPredictedSign) + { + feedbackText.text = $"Verkeerde gebaar: '{predictedSign}'"; + col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + accCurrentSign = 0.0f; + } + else + { + feedbackText.text = "Detecteren..."; + col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + } + + feedbackText.color = col; + feedbackProgressImage.color = col; + + float oldValue = feedbackProgress.value; + // use an exponential scale + float newValue = Mathf.Exp(4 * (Mathf.Clamp(accCurrentSign / thresholdCurrentSign, 0.0f, 1.0f) - 1.0f)); + feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) => + { + if (feedbackProgress != null) + { + feedbackProgress.value = t.CurrentValue; + } + }); + } + + + if (accPredictSign > thresholdPredictedSign) + { + // Correct sign + if (predictedSign == currentSign) + { + yield return new WaitForSeconds(0.5f); + PredictSign(predictedSign); + timer = DateTime.Now; + predictedSign = null; + previousIncorrectSign = null; + } + // Incorrect sign + else + { + if (previousIncorrectSign != predictedSign) + { + timer = DateTime.Now; + previousIncorrectSign = predictedSign; + } + else if (DateTime.Now - timer > TimeSpan.FromSeconds(2.0f)) + { + PredictSign(predictedSign); + timer = DateTime.Now; + predictedSign = null; + previousIncorrectSign = null; + } + } + + } + } + else if (feedbackProgress != null) + { + + feedbackProgress.value = 0.0f; + } + yield return null; + } + */ + /// + /// Function to get the current letter that needs to be signed + /// + /// the current letter that needs to be signed + public string GetSign() + { + if (letterIndex < currentWord.Length) + { + return currentWord[letterIndex].ToString().ToUpper(); + } + return null; + } + /// + /// Function to confirm your prediction and check if it is correct. + /// + /// + public void PredictSign(string sign) + { + bool successful = sign.ToUpper() == currentWord[letterIndex].ToString().ToUpper(); + if (successful) + { + AddSeconds(secondsPerLetter); + } + NextLetter(successful); + } + + /// + /// The logic to process the signs sent by the signPredictor + /// + /// The accuracy of the passed sign + /// The name of the passed sign + protected override void ProcessMostProbableSign(float accuracy, string predictedSign) + { + string currentSign = GetSign(); + float accPredictSign = accuracy; + float accCurrentSign = signPredictor.learnableProbabilities[currentSign]; + float thresholdCurrentSign = GetTresholdPercentage(currentSign); + float thresholdPredictedSign = GetTresholdPercentage(predictedSign); + + // If there is a feedback-object, we wil change its appearance + if (feedbackText != null && feedbackProgressImage != null) + { + Color col; + if (accPredictSign > thresholdCurrentSign) + { + feedbackText.text = "Goed"; + col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); + } + else if (accCurrentSign > 0.9 * thresholdCurrentSign) + { + feedbackText.text = "Bijna..."; + col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f); + } + else if (accPredictSign > thresholdPredictedSign) + { + feedbackText.text = $"Verkeerde gebaar: '{predictedSign}'"; + col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + accCurrentSign = 0.0f; + } + else + { + feedbackText.text = "Detecteren..."; + col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + } + + feedbackText.color = col; + feedbackProgressImage.color = col; + + float oldValue = feedbackProgress.value; + // use an exponential scale + float newValue = Mathf.Exp(4 * (Mathf.Clamp(accCurrentSign / thresholdCurrentSign, 0.0f, 1.0f) - 1.0f)); + feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) => + { + if (feedbackProgress != null) + { + feedbackProgress.value = t.CurrentValue; + } + }); + } + + // The logic for the internal workings of the game + if (accPredictSign > thresholdPredictedSign) + { + // Correct sign, instantly pass it along + if (predictedSign == currentSign) + { + PredictSign(predictedSign); + timer = DateTime.Now; + predictedSign = null; + previousIncorrectSign = null; + } + + // Incorrect sign, wait a bit before passing it along + else + { + if (previousIncorrectSign != predictedSign) + { + timer = DateTime.Now; + previousIncorrectSign = predictedSign; + } + else if (DateTime.Now - timer > TimeSpan.FromSeconds(2.0f)) + { + PredictSign(predictedSign); + timer = DateTime.Now; + predictedSign = null; + previousIncorrectSign = null; + } + } + + } + } + + /// + /// The logic to set the scoreboard of spellingbee + /// + /// SHows whether or not the player won + protected override void SetScoreBoard(bool victory) + { + string resultTxt; + if (victory) + { + resultTxt = "GEWONNEN"; + } + else + { + resultTxt = "VERLOREN"; + } + // Save the scores and show the scoreboard + gameEndedPanel.GetComponent().GenerateContent( + startTime: startTime, + totalWords: spelledWords, + correctLetters: correctLetters, + incorrectLetters: incorrectLetters, + result: resultTxt, + score: CalculateScore() + ); + } + + /// + /// The spellinbee-specific logic that needs to be called at the start of the game + /// + protected override void StartGameLogic() + { + correctLetters = 0; + incorrectLetters = 0; + + words.Clear(); + // We use -1 instead of 0 so SetNextWord can simply increment it each time + spelledWords = -1; + wordIndex = 0; + + gameIsActive = true; + timerValue = 30.0f; + bonusActiveRemaining = 0.0f; + startTime = DateTime.Now; + + gameEndedPanel.SetActive(false); + bonusTimeText.SetActive(false); + + currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex]; + //feedback.signPredictor.SetModel(currentTheme.modelIndex); + words.AddRange(currentTheme.learnables); + ShuffleWords(); + NextWord(); + + scoreDisplay.text = $"Score: {CalculateScore()}"; + scoreBonus.text = ""; + } + + /// + /// The spellingbee-specific logic that needs to be called at the end of a game + /// + /// + protected override void EndGameLogic(bool victory) + { + gameIsActive = false; + DeleteWord(); + } +} diff --git a/Assets/SpellingBee/Scripts/SpellingBeeController.cs.meta b/Assets/SpellingBee/Scripts/SpellingBeeController.cs.meta new file mode 100644 index 0000000..6fa40d2 --- /dev/null +++ b/Assets/SpellingBee/Scripts/SpellingBeeController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44fbed5ae228de39b9f727def7578d06 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs b/Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs new file mode 100644 index 0000000..de6c3d5 --- /dev/null +++ b/Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class SpellingBeeGameEndedPanel : AbstractGameEndedPanel +{ + /// + /// Tell the scoreboard that the scoreboard is for SpellingBee + /// + protected override MinigameIndex minigameIndex + { + get { return MinigameIndex.SPELLING_BEE; } + } + + /// + /// "VERLOREN" or "GEWONNEN" + /// + public TMP_Text endText; + + /// + /// LPM + /// + public TMP_Text lpmText; + + /// + /// Letters ( right | wrong ) + /// + public TMP_Text lettersRightText; + public TMP_Text lettersWrongText; + + /// + /// Letters + /// + public TMP_Text lettersTotalText; + + /// + /// Accuracy + /// + public TMP_Text accuracyText; + + /// + /// Words + /// + public TMP_Text wordsText; + + /// + /// Time + /// + public TMP_Text timeText; + + /// + /// Score + /// + public TMP_Text scoreText; + + /// + /// Generate the content of the GameEnded panel + /// + /// Time of starting the minigame + /// Total number of words + /// Total number of correctly spelled letters + /// Total number of incorrectly spelled letters + /// "VERLOREN" or "GEWONNEN" + /// Final score + public void GenerateContent(DateTime startTime, int totalWords, int correctLetters, int incorrectLetters, string result, int score) + { + // Final result + endText.text = result; + + // LPM + TimeSpan duration = DateTime.Now.Subtract(startTime); + lpmText.text = (60f * correctLetters / duration.TotalSeconds).ToString("#") + " LPM"; + + // Letters ( right | wrong ) total + lettersRightText.text = correctLetters.ToString(); + lettersWrongText.text = incorrectLetters.ToString(); + lettersTotalText.text = (correctLetters + incorrectLetters).ToString(); + + // Accuracy + if (correctLetters + incorrectLetters > 0) + { + accuracyText.text = ((correctLetters) * 100f / (correctLetters + incorrectLetters)).ToString("#.##") + "%"; + } + else + { + accuracyText.text = "-"; + } + + // Words + wordsText.text = $"{totalWords}"; + + // Time + timeText.text = duration.ToString(@"mm\:ss"); + + // Score + scoreText.text = $"Score: {score}"; + SetScoreBoard(); + } +} diff --git a/Assets/SpellingBee/Scripts/GameEndedPanel.cs.meta b/Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs.meta similarity index 100% rename from Assets/SpellingBee/Scripts/GameEndedPanel.cs.meta rename to Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs.meta diff --git a/Assets/SpellingBee/Scripts/SpellingBeeScripts.asmdef b/Assets/SpellingBee/Scripts/SpellingBeeScripts.asmdef index d8c8edb..bbf25b5 100644 --- a/Assets/SpellingBee/Scripts/SpellingBeeScripts.asmdef +++ b/Assets/SpellingBee/Scripts/SpellingBeeScripts.asmdef @@ -6,8 +6,10 @@ "GUID:1631ed2680c61245b8211d943c1639a8", "GUID:3444c67d5a3a93e5a95a48906078c372", "GUID:d0b6b39a21908f94fbbd9f2c196a9725", - "GUID:5c2b5ba89f9e74e418232e154bc5cc7a", - "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25" + "GUID:58e104b97fb3752438ada2902a36dcbf", + "GUID:e83ddf9a537a96b4a804a16bb7872ec1", + "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25", + "GUID:403dd94a93598934eb522dc36df43d7b" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/SpellingBee/Tests/BasicTests.cs b/Assets/SpellingBee/Tests/BasicTests.cs index 7da4cc0..7cffd7c 100644 --- a/Assets/SpellingBee/Tests/BasicTests.cs +++ b/Assets/SpellingBee/Tests/BasicTests.cs @@ -1,7 +1,5 @@ -using System.Collections; -using System.Collections.Generic; using NUnit.Framework; -using UnityEngine; +using System.Collections; using UnityEngine.TestTools; public class BasicTests diff --git a/Assets/SystemArchitecture.meta b/Assets/SystemArchitecture.meta new file mode 100644 index 0000000..35c4f20 --- /dev/null +++ b/Assets/SystemArchitecture.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 00903f60e81ce95419bc0c62a11ddfd1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SystemArchitecture/Scripts.meta b/Assets/SystemArchitecture/Scripts.meta new file mode 100644 index 0000000..5cf4d68 --- /dev/null +++ b/Assets/SystemArchitecture/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17374f544297b194aa5517c196ca2f07 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/Unity.Barracuda.ONNX.asmdef b/Assets/SystemArchitecture/Scripts/ArchitectureScripts.asmdef similarity index 51% rename from Packages/com.unity.barracuda/Runtime/ONNX/Unity.Barracuda.ONNX.asmdef rename to Assets/SystemArchitecture/Scripts/ArchitectureScripts.asmdef index 4205080..0503acd 100644 --- a/Packages/com.unity.barracuda/Runtime/ONNX/Unity.Barracuda.ONNX.asmdef +++ b/Assets/SystemArchitecture/Scripts/ArchitectureScripts.asmdef @@ -1,14 +1,14 @@ { - "name": "Unity.Barracuda.ONNX", - "references": [ - "Unity.Barracuda" - ], - "optionalUnityReferences": [], + "name": "ArchitectureScripts", + "rootNamespace": "", + "references": [], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, - "defineConstraints": [] + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false } \ No newline at end of file diff --git a/Assets/SystemArchitecture/Scripts/ArchitectureScripts.asmdef.meta b/Assets/SystemArchitecture/Scripts/ArchitectureScripts.asmdef.meta new file mode 100644 index 0000000..b28cb92 --- /dev/null +++ b/Assets/SystemArchitecture/Scripts/ArchitectureScripts.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e83ddf9a537a96b4a804a16bb7872ec1 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Interfaces/CourseIndex.cs b/Assets/SystemArchitecture/Scripts/CourseIndex.cs similarity index 92% rename from Assets/Common/Interfaces/CourseIndex.cs rename to Assets/SystemArchitecture/Scripts/CourseIndex.cs index 544cb24..328f6dd 100644 --- a/Assets/Common/Interfaces/CourseIndex.cs +++ b/Assets/SystemArchitecture/Scripts/CourseIndex.cs @@ -5,6 +5,7 @@ public enum CourseIndex { FINGERSPELLING, + BASIC_SIGNS, CLOTHING, ANIMALS, FOOD, diff --git a/Assets/Common/Interfaces/CourseIndex.cs.meta b/Assets/SystemArchitecture/Scripts/CourseIndex.cs.meta similarity index 100% rename from Assets/Common/Interfaces/CourseIndex.cs.meta rename to Assets/SystemArchitecture/Scripts/CourseIndex.cs.meta diff --git a/Assets/Common/Interfaces/MinigameIndex.cs b/Assets/SystemArchitecture/Scripts/MinigameIndex.cs similarity index 100% rename from Assets/Common/Interfaces/MinigameIndex.cs rename to Assets/SystemArchitecture/Scripts/MinigameIndex.cs diff --git a/Assets/Common/Interfaces/MinigameIndex.cs.meta b/Assets/SystemArchitecture/Scripts/MinigameIndex.cs.meta similarity index 100% rename from Assets/Common/Interfaces/MinigameIndex.cs.meta rename to Assets/SystemArchitecture/Scripts/MinigameIndex.cs.meta diff --git a/Assets/SystemArchitecture/Scripts/PersistentDataController.cs b/Assets/SystemArchitecture/Scripts/PersistentDataController.cs new file mode 100644 index 0000000..6e6d546 --- /dev/null +++ b/Assets/SystemArchitecture/Scripts/PersistentDataController.cs @@ -0,0 +1,558 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization.Formatters.Binary; +using UnityEngine; + +/// +/// PersistentDataController singleton +/// +public class PersistentDataController +{ + /// + /// The instance controlling the singleton + /// + private static PersistentDataController instance = null; + + /// + /// Current implementation version of the PersistentDataController + /// + /// MSB represent sprint version, LSB represent subversion + public static readonly int VERSION = 0x04_03; + + /// + /// Path of the .json-file to store all serialized data + /// + public static string PATH = null; + + /// + /// Class to hold a list of data records + /// + [Serializable] + public class PersistentDataContainer + { + /// + /// A helper class for handling the stored progress + /// + [Serializable] + public class PersistentDataEntry + { + /// + /// The key, used to reference the data object + /// + public string key; + + /// + /// The object, representated as a list of byte (which can be serialized) + /// + public List data = new List(); + + public PersistentDataEntry(string key, byte[] data) : this(key, data.ToList()) + { } + + public PersistentDataEntry(string key, List data) + { + this.key = key; + this.data = data; + } + } + + /// + /// List of data records + /// + public List entries = new List(); + + /// + /// Update the value of a certain key, + /// or add a new value if the key was not present. + /// + /// The type of the data to be added/updated + /// The key, used for referencing the data + /// The object of type + /// true if successful, false otherwise + public bool Set(string key, T data) + { + if (data == null) + return false; + + PersistentDataEntry entry = entries.Find(x => x.key == key); + + // Hacky serialization stuff + BinaryFormatter bf = new BinaryFormatter(); + using (MemoryStream ms = new MemoryStream()) + { + bf.Serialize(ms, data); + if (entry != null) + { + entry.data.Clear(); + entry.data.AddRange(ms.ToArray()); + } + else + { + entries.Add(new PersistentDataEntry(key, ms.ToArray())); + } + return true; + } + } + + /// + /// Get the data object of a certain key + /// + /// The type of the data object + /// The key referencing the data object + /// The data, cast to a type + /// + /// + public T Get(string key) + { + BinaryFormatter bf = new BinaryFormatter(); + using (MemoryStream ms = new MemoryStream()) + { + // Find the correct key + foreach (PersistentDataEntry entry in entries) + { + if (entry.key == key) + { + // Hacky serialization stuff + byte[] data = entry.data.ToArray(); + ms.Write(data, 0, data.Length); + ms.Seek(0, SeekOrigin.Begin); + return (T)bf.Deserialize(ms); + } + } + } + + // Raise an exception when key is not found + throw new KeyNotFoundException(); + } + + /// + /// Remove a key-value from the data. + /// + /// The key referencing the data object + /// + public void Remove(string key) + { + if (!Has(key)) + throw new KeyNotFoundException(); + + entries.Remove(entries.Find(x => x.key == key)); + } + + /// + /// Remove and return value from the data. + /// + /// The type of the data object + /// The key referencing the data object + /// Whether the removal of the data should also be saved to disk + /// + public T Pop(string key) + { + T data = Get(key); + Remove(key); + return data; + } + + /// + /// Check whether a key is present + /// + /// The key to check + /// true if a item can be found with the specified key + public bool Has(string key) + { + return entries.Find(x => x.key == key) != null; + } + } + + /// + /// Stored user data record + /// + [Serializable] + public class SavedUserData : PersistentDataContainer + { + public string username = null; + public int avatarIndex = -1; + public double playtime = 0.0; + public List minigames = new List(); + public List courses = new List(); + } + + /// + /// Stored course progress data record + /// + [Serializable] + public class SavedCourseProgress : PersistentDataContainer + { + + /// + /// Update the progress value of the SavedLearnableProgress with the given learnableName. + /// + /// + /// + public void UpdateLearnable(string learnableName, float addValue) + { + SavedLearnableProgress learnable = learnables.Find(l => l.name == learnableName); + if (learnable == null) + { + return; + } + + // Update the progress value of the SavedLearnableProgress + learnable.progress += addValue; + // crop the learnable progress around -5 and 5 + if (learnable.progress > 5.0f) + { + learnable.progress = 5.0f; + } + else if (learnable.progress < -5.0f) + { + learnable.progress = -5.0f; + } + + // if learnable progress is big enough it is "completed" + + if (learnable.progress > 3) + { + completedLearnables++; + } + } + + /// + /// + /// + /// bool which indicates if there are enough inUseLearnables + private bool EnoughLearnables() + { + // There need to be more then 5 non completed learnables + return inUseLearnables - completedLearnables > 5 || totalLearnables == inUseLearnables; + } + + /// + /// Find a SavedLearnableProgress with the given name + /// + /// + /// SavedLearnableProgress with the given name + public SavedLearnableProgress FindLearnable(string name) + { + return learnables.Find(l => l.name == name); + } + + /// + /// find learnable in learnables which is not yet in use, and set it active + /// + /// bool which indicates the success of the function + public SavedLearnableProgress AddNewLearnable() + { + SavedLearnableProgress learnable = learnables.Find(l => !l.inUse); + if (learnable == null) + { + return null; + } + learnable.inUse = true; + inUseLearnables++; + return learnable; + } + + /// + /// Gets a random inUse learnable + /// + /// a randomly selected inUse SavedLearnable which is not yet completed + public SavedLearnableProgress GetRandomLearnable() + { + if (!EnoughLearnables()) + { + return AddNewLearnable(); + } + else + { + // only select inUse learnables which are not yet completed (progress < 3.5f) + List inUseLearnables = learnables.FindAll(l => l.inUse && l.progress <= 3.5f); + + if (inUseLearnables.Count == 0) + { + return null; + } + + // Select a random index from the in-use learnables list + int randomIndex = UnityEngine.Random.Range(0, inUseLearnables.Count); + return inUseLearnables[randomIndex]; + } + } + + /// + /// Create new SavedLearnableProgress object and assigns the index and name values + /// + /// + /// + /// bool which indicates the success of the function + public bool AddLearnable(string name, int index) + { + if (learnables.Any(learnable => learnable.name == name || learnable.index == index)) + return false; + + SavedLearnableProgress savedLearnableProgress = new SavedLearnableProgress(); + savedLearnableProgress.index = index; + savedLearnableProgress.name = name; + learnables.Add(savedLearnableProgress); + totalLearnables++; + return true; + } + + public CourseIndex courseIndex; + public float progress = -1.0f; + public int completedLearnables = 0; + public int inUseLearnables = 0; + public int totalLearnables = 0; + public List learnables = new List(); + } + + /// + /// Stored individual learnable progress + /// + [Serializable] + public class SavedLearnableProgress : PersistentDataContainer + { + public int index; + public bool inUse = false; + public string name; + public float progress = 0.0f; + } + + /// + /// Stored minigame progress data record + /// + [Serializable] + public class SavedMinigameProgress : PersistentDataContainer + { + public MinigameIndex minigameIndex; + public List latestScores = new List(); + public List highestScores = new List(); + } + + /// + /// Stored WeSign data record + /// + [Serializable] + private class SavedDataStructure + { + public int version = VERSION; + public List users = new List(); + public int currentUser = -1; + public MinigameIndex currentMinigame; + public CourseIndex currentCourse; + public ThemeIndex currentTheme; + } + + /// + /// The object holding the data references + /// + private SavedDataStructure json = new SavedDataStructure(); + + /// + /// Get the instance loaded by the singleton + /// + /// PersistentDataController instance + public static PersistentDataController GetInstance() + { + // Create a new instance if non exists + if (instance == null) + { + if (PATH == null) + PersistentDataController.PATH = $"{Application.persistentDataPath}/wesign_saved_data.json"; + instance = new PersistentDataController(); + } + return instance; + } + + /// + /// PersistentDataController contructor + /// + private PersistentDataController() + { + Load(); + } + + /// + /// Clear everything stored in the PersistentDataController, won't save to disk + /// + public void Clear() + { + json.users.Clear(); + json.currentUser = -1; + } + + /// + /// Save all data to disk + /// + public void Save() + { + string text = JsonUtility.ToJson(json); + File.CreateText(PATH).Close(); + File.WriteAllText(PATH, text); + } + + /// + /// Override current data with the data from disk, will just clear if no data was found. + /// + /// true if you want to override the existing file if it exists and the loading failed. + /// If the data on disk is outdated (version number is lower than the current version), the loading will also fail + /// true if successful, false otherwise + public bool Load(bool overrideOnFail = true) + { + Clear(); + if (!File.Exists(PATH)) + goto failed; + + try + { + string text = File.ReadAllText(PATH); + SavedDataStructure newJson = JsonUtility.FromJson(text); + if (newJson == null || newJson.version != VERSION) + goto failed; + + json = newJson; + return true; + } + catch (Exception) { goto failed; } + + failed: + if (overrideOnFail) + Save(); + return false; + } + + /// + /// Add a user to the WeSign data record + /// + /// User data record + /// Whether to save the addition immediately to disk + public void AddUser(SavedUserData user, bool save = true) + { + if (json.users.Count == 0) + json.currentUser = 0; + json.users.Add(user); + + if (save) + Save(); + } + + /// + /// Get a list of all user data records + /// + /// + public List GetUsers() + { + return json.users; + } + + /// + /// Get the index of the current user + /// + /// + public int GetCurrentUser() + { + return json.currentUser; + } + + /// + /// Set the index of the current record + /// + /// New index + /// Whether to save the change immediately to disk + /// + public void SetCurrentUser(int index, bool save = true) + { + if (index < 0 || json.users.Count <= index) + throw new IndexOutOfRangeException(); + json.currentUser = index; + + if (save) + Save(); + } + + /// + /// Remove a user data record + /// + /// Index of the user + /// Whether to save the deletion immediately to disk + /// + public void DeleteUser(int index, bool save = true) + { + if (index < 0 || json.users.Count <= index) + throw new IndexOutOfRangeException(); + + if (0 < json.currentUser && index <= json.currentUser) + json.currentUser--; + json.users.RemoveAt(index); + + if (save) + Save(); + } + + /// + /// Get the current course + /// + /// + public CourseIndex GetCurrentCourse() + { + return json.currentCourse; + } + + /// + /// Set the current course + /// + /// New course index + /// Whether to save the change immediately to disk + public void SetCurrentCourse(CourseIndex course, bool save = true) + { + json.currentCourse = course; + + if (save) + Save(); + } + + /// + /// Get the current minigame + /// + /// + public MinigameIndex GetCurrentMinigame() + { + return json.currentMinigame; + } + + /// + /// Set the current minigame + /// + /// New minigame index + /// Whether to save the change immediately to disk + public void SetCurrentMinigame(MinigameIndex minigame, bool save = true) + { + json.currentMinigame = minigame; + + if (save) + Save(); + } + + /// + /// Get the current theme + /// + /// + public ThemeIndex GetCurrentTheme() + { + return json.currentTheme; + } + + /// + /// Set the current theme + /// + /// New theme index + /// Whether to save the change immediately to disk + public void SetCurrentTheme(ThemeIndex theme, bool save = true) + { + json.currentTheme = theme; + + if (save) + Save(); + } +} diff --git a/Assets/SystemArchitecture/Scripts/PersistentDataController.cs.meta b/Assets/SystemArchitecture/Scripts/PersistentDataController.cs.meta new file mode 100644 index 0000000..9eeea85 --- /dev/null +++ b/Assets/SystemArchitecture/Scripts/PersistentDataController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 164b1accbeff688429a4311f1e40bd59 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Interfaces/Score.cs b/Assets/SystemArchitecture/Scripts/Score.cs similarity index 100% rename from Assets/Common/Interfaces/Score.cs rename to Assets/SystemArchitecture/Scripts/Score.cs diff --git a/Assets/Common/Interfaces/Score.cs.meta b/Assets/SystemArchitecture/Scripts/Score.cs.meta similarity index 100% rename from Assets/Common/Interfaces/Score.cs.meta rename to Assets/SystemArchitecture/Scripts/Score.cs.meta diff --git a/Assets/SystemArchitecture/Scripts/SlicedSlider.cs b/Assets/SystemArchitecture/Scripts/SlicedSlider.cs new file mode 100644 index 0000000..56fb623 --- /dev/null +++ b/Assets/SystemArchitecture/Scripts/SlicedSlider.cs @@ -0,0 +1,647 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER +using UnityEngine.U2D; +#endif +using Sprites = UnityEngine.Sprites; + +#if UNITY_EDITOR +using UnityEditor; + +// Custom Editor to order the variables in the Inspector similar to Image component +[CustomEditor(typeof(SlicedSlider)), CanEditMultipleObjects] +public class SlicedSliderEditor : Editor +{ + private SerializedProperty spriteProp, colorProp; + private GUIContent spriteLabel; + + private void OnEnable() + { + spriteProp = serializedObject.FindProperty("m_Sprite"); + colorProp = serializedObject.FindProperty("m_Color"); + spriteLabel = new GUIContent("Source Image"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(spriteProp, spriteLabel); + EditorGUILayout.PropertyField(colorProp); + DrawPropertiesExcluding(serializedObject, "m_Script", "m_Sprite", "m_Color", "m_OnCullStateChanged"); + + serializedObject.ApplyModifiedProperties(); + } +} +#endif + +// Credit: https://bitbucket.org/Unity-Technologies/ui/src/2018.4/UnityEngine.UI/UI/Core/Image.cs +[RequireComponent(typeof(CanvasRenderer))] +[AddComponentMenu("UI/Sliced Slider", 11)] +public class SlicedSlider : MaskableGraphic, ISerializationCallbackReceiver, ILayoutElement, ICanvasRaycastFilter +{ + private static class SetPropertyUtility + { + public static bool SetStruct(ref T currentValue, T newValue) where T : struct + { + if (EqualityComparer.Default.Equals(currentValue, newValue)) + return false; + + currentValue = newValue; + return true; + } + + public static bool SetClass(ref T currentValue, T newValue) where T : class + { + if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue))) + return false; + + currentValue = newValue; + return true; + } + } + + public enum FillDirection { Right = 0, Left = 1, Up = 2, Down = 3 } + + private static readonly Vector3[] s_Vertices = new Vector3[4]; + private static readonly Vector2[] s_UVs = new Vector2[4]; + private static readonly Vector2[] s_SlicedVertices = new Vector2[4]; + private static readonly Vector2[] s_SlicedUVs = new Vector2[4]; + +#pragma warning disable 1692 +#pragma warning disable IDE1006 // Suppress 'Naming rule violation' warnings +#pragma warning disable 0649 + [SerializeField] + private Sprite m_Sprite; + public Sprite sprite + { + get { return m_Sprite; } + set + { + if (SetPropertyUtility.SetClass(ref m_Sprite, value)) + { + SetAllDirty(); + TrackImage(); + } + } + } + + [SerializeField] + private FillDirection m_FillDirection; + public FillDirection fillDirection + { + get { return m_FillDirection; } + set + { + if (SetPropertyUtility.SetStruct(ref m_FillDirection, value)) + SetVerticesDirty(); + } + } + + [Range(0, 1)] + [SerializeField] + private float m_FillAmount = 1f; + public float fillAmount + { + get { return m_FillAmount; } + set + { + if (SetPropertyUtility.SetStruct(ref m_FillAmount, Mathf.Clamp01(value))) + SetVerticesDirty(); + } + } + + [SerializeField] + private bool m_FillCenter = true; + public bool fillCenter + { + get { return m_FillCenter; } + set + { + if (SetPropertyUtility.SetStruct(ref m_FillCenter, value)) + SetVerticesDirty(); + } + } + + [SerializeField] + private float m_PixelsPerUnitMultiplier = 1f; + public float pixelsPerUnitMultiplier + { + get { return m_PixelsPerUnitMultiplier; } + set { m_PixelsPerUnitMultiplier = Mathf.Max(0.01f, value); } + } + + public float pixelsPerUnit + { + get + { + float spritePixelsPerUnit = 100; + if (activeSprite) + spritePixelsPerUnit = activeSprite.pixelsPerUnit; + + float referencePixelsPerUnit = 100; + if (canvas) + referencePixelsPerUnit = canvas.referencePixelsPerUnit; + + return m_PixelsPerUnitMultiplier * spritePixelsPerUnit / referencePixelsPerUnit; + } + } +#pragma warning restore 0649 + + [NonSerialized] + private Sprite m_OverrideSprite; + public Sprite overrideSprite + { + get { return activeSprite; } + set + { + if (SetPropertyUtility.SetClass(ref m_OverrideSprite, value)) + { + SetAllDirty(); + TrackImage(); + } + } + } + + private Sprite activeSprite { get { return m_OverrideSprite != null ? m_OverrideSprite : m_Sprite; } } + + public override Texture mainTexture + { + get + { + if (activeSprite != null) + return activeSprite.texture; + + return material != null && material.mainTexture != null ? material.mainTexture : s_WhiteTexture; + } + } + + public bool hasBorder + { + get + { + if (activeSprite != null) + { + Vector4 v = activeSprite.border; + return v.sqrMagnitude > 0f; + } + + return false; + } + } + + public override Material material + { + get + { + if (m_Material != null) + return m_Material; + + if (activeSprite && activeSprite.associatedAlphaSplitTexture != null) + { +#if UNITY_EDITOR + if (Application.isPlaying) +#endif + return Image.defaultETC1GraphicMaterial; + } + + return defaultMaterial; + } + set { base.material = value; } + } + + public float alphaHitTestMinimumThreshold { get; set; } +#pragma warning restore IDE1006 +#pragma warning restore 1692 + + protected SlicedSlider() + { + useLegacyMeshGeneration = false; + } + + protected override void OnEnable() + { + base.OnEnable(); + TrackImage(); + } + + protected override void OnDisable() + { + base.OnDisable(); + + if (m_Tracked) + UnTrackImage(); + } + +#if UNITY_EDITOR + protected override void OnValidate() + { + base.OnValidate(); + m_PixelsPerUnitMultiplier = Mathf.Max(0.01f, m_PixelsPerUnitMultiplier); + } +#endif + + protected override void OnPopulateMesh(VertexHelper vh) + { + if (activeSprite == null) + { + base.OnPopulateMesh(vh); + return; + } + + GenerateSlicedFilledSprite(vh); + } + + /// + /// Update the renderer's material. + /// + protected override void UpdateMaterial() + { + base.UpdateMaterial(); + + // Check if this sprite has an associated alpha texture (generated when splitting RGBA = RGB + A as two textures without alpha) + if (activeSprite == null) + { + canvasRenderer.SetAlphaTexture(null); + return; + } + + Texture2D alphaTex = activeSprite.associatedAlphaSplitTexture; + if (alphaTex != null) + canvasRenderer.SetAlphaTexture(alphaTex); + } + + private void GenerateSlicedFilledSprite(VertexHelper vh) + { + vh.Clear(); + + if (m_FillAmount < 0.001f) + return; + + Rect rect = GetPixelAdjustedRect(); + Vector4 outer = Sprites.DataUtility.GetOuterUV(activeSprite); + Vector4 padding = Sprites.DataUtility.GetPadding(activeSprite); + + if (!hasBorder) + { + Vector2 size = activeSprite.rect.size; + + int spriteW = Mathf.RoundToInt(size.x); + int spriteH = Mathf.RoundToInt(size.y); + + // Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top. + Vector4 vertices = new Vector4( + rect.x + rect.width * (padding.x / spriteW), + rect.y + rect.height * (padding.y / spriteH), + rect.x + rect.width * ((spriteW - padding.z) / spriteW), + rect.y + rect.height * ((spriteH - padding.w) / spriteH)); + + GenerateFilledSprite(vh, vertices, outer, m_FillAmount); + return; + } + + Vector4 inner = Sprites.DataUtility.GetInnerUV(activeSprite); + Vector4 border = GetAdjustedBorders(activeSprite.border / pixelsPerUnit, rect); + + padding = padding / pixelsPerUnit; + + s_SlicedVertices[0] = new Vector2(padding.x, padding.y); + s_SlicedVertices[3] = new Vector2(rect.width - padding.z, rect.height - padding.w); + + s_SlicedVertices[1].x = border.x; + s_SlicedVertices[1].y = border.y; + + s_SlicedVertices[2].x = rect.width - border.z; + s_SlicedVertices[2].y = rect.height - border.w; + + for (int i = 0; i < 4; ++i) + { + s_SlicedVertices[i].x += rect.x; + s_SlicedVertices[i].y += rect.y; + } + + s_SlicedUVs[0] = new Vector2(outer.x, outer.y); + s_SlicedUVs[1] = new Vector2(inner.x, inner.y); + s_SlicedUVs[2] = new Vector2(inner.z, inner.w); + s_SlicedUVs[3] = new Vector2(outer.z, outer.w); + + float rectStartPos; + float _1OverTotalSize; + if (m_FillDirection == FillDirection.Left || m_FillDirection == FillDirection.Right) + { + rectStartPos = s_SlicedVertices[0].x; + + float totalSize = (s_SlicedVertices[3].x - s_SlicedVertices[0].x); + _1OverTotalSize = totalSize > 0f ? 1f / totalSize : 1f; + } + else + { + rectStartPos = s_SlicedVertices[0].y; + + float totalSize = (s_SlicedVertices[3].y - s_SlicedVertices[0].y); + _1OverTotalSize = totalSize > 0f ? 1f / totalSize : 1f; + } + + for (int x = 0; x < 3; x++) + { + int x2 = x + 1; + + for (int y = 0; y < 3; y++) + { + if (!m_FillCenter && x == 1 && y == 1) + continue; + + int y2 = y + 1; + + float sliceStart, sliceEnd; + switch (m_FillDirection) + { + case FillDirection.Right: + sliceStart = (s_SlicedVertices[x].x - rectStartPos) * _1OverTotalSize; + sliceEnd = (s_SlicedVertices[x2].x - rectStartPos) * _1OverTotalSize; + break; + case FillDirection.Up: + sliceStart = (s_SlicedVertices[y].y - rectStartPos) * _1OverTotalSize; + sliceEnd = (s_SlicedVertices[y2].y - rectStartPos) * _1OverTotalSize; + break; + case FillDirection.Left: + sliceStart = 1f - (s_SlicedVertices[x2].x - rectStartPos) * _1OverTotalSize; + sliceEnd = 1f - (s_SlicedVertices[x].x - rectStartPos) * _1OverTotalSize; + break; + case FillDirection.Down: + sliceStart = 1f - (s_SlicedVertices[y2].y - rectStartPos) * _1OverTotalSize; + sliceEnd = 1f - (s_SlicedVertices[y].y - rectStartPos) * _1OverTotalSize; + break; + default: // Just there to get rid of the "Use of unassigned local variable" compiler error + sliceStart = sliceEnd = 0f; + break; + } + + if (sliceStart >= m_FillAmount) + continue; + + Vector4 vertices = new Vector4(s_SlicedVertices[x].x, s_SlicedVertices[y].y, s_SlicedVertices[x2].x, s_SlicedVertices[y2].y); + Vector4 uvs = new Vector4(s_SlicedUVs[x].x, s_SlicedUVs[y].y, s_SlicedUVs[x2].x, s_SlicedUVs[y2].y); + float fillAmount = (m_FillAmount - sliceStart) / (sliceEnd - sliceStart); + + GenerateFilledSprite(vh, vertices, uvs, fillAmount); + } + } + } + + private Vector4 GetAdjustedBorders(Vector4 border, Rect adjustedRect) + { + Rect originalRect = rectTransform.rect; + + for (int axis = 0; axis <= 1; axis++) + { + float borderScaleRatio; + + // The adjusted rect (adjusted for pixel correctness) may be slightly larger than the original rect. + // Adjust the border to match the adjustedRect to avoid small gaps between borders (case 833201). + if (originalRect.size[axis] != 0) + { + borderScaleRatio = adjustedRect.size[axis] / originalRect.size[axis]; + border[axis] *= borderScaleRatio; + border[axis + 2] *= borderScaleRatio; + } + + // If the rect is smaller than the combined borders, then there's not room for the borders at their normal size. + // In order to avoid artefacts with overlapping borders, we scale the borders down to fit. + float combinedBorders = border[axis] + border[axis + 2]; + if (adjustedRect.size[axis] < combinedBorders && combinedBorders != 0) + { + borderScaleRatio = adjustedRect.size[axis] / combinedBorders; + border[axis] *= borderScaleRatio; + border[axis + 2] *= borderScaleRatio; + } + } + + return border; + } + + private void GenerateFilledSprite(VertexHelper vh, Vector4 vertices, Vector4 uvs, float fillAmount) + { + if (m_FillAmount < 0.001f) + return; + + float uvLeft = uvs.x; + float uvBottom = uvs.y; + float uvRight = uvs.z; + float uvTop = uvs.w; + + if (fillAmount < 1f) + { + if (m_FillDirection == FillDirection.Left || m_FillDirection == FillDirection.Right) + { + if (m_FillDirection == FillDirection.Left) + { + vertices.x = vertices.z - (vertices.z - vertices.x) * fillAmount; + uvLeft = uvRight - (uvRight - uvLeft) * fillAmount; + } + else + { + vertices.z = vertices.x + (vertices.z - vertices.x) * fillAmount; + uvRight = uvLeft + (uvRight - uvLeft) * fillAmount; + } + } + else + { + if (m_FillDirection == FillDirection.Down) + { + vertices.y = vertices.w - (vertices.w - vertices.y) * fillAmount; + uvBottom = uvTop - (uvTop - uvBottom) * fillAmount; + } + else + { + vertices.w = vertices.y + (vertices.w - vertices.y) * fillAmount; + uvTop = uvBottom + (uvTop - uvBottom) * fillAmount; + } + } + } + + s_Vertices[0] = new Vector3(vertices.x, vertices.y); + s_Vertices[1] = new Vector3(vertices.x, vertices.w); + s_Vertices[2] = new Vector3(vertices.z, vertices.w); + s_Vertices[3] = new Vector3(vertices.z, vertices.y); + + s_UVs[0] = new Vector2(uvLeft, uvBottom); + s_UVs[1] = new Vector2(uvLeft, uvTop); + s_UVs[2] = new Vector2(uvRight, uvTop); + s_UVs[3] = new Vector2(uvRight, uvBottom); + + int startIndex = vh.currentVertCount; + + for (int i = 0; i < 4; i++) + vh.AddVert(s_Vertices[i], color, s_UVs[i]); + + vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2); + vh.AddTriangle(startIndex + 2, startIndex + 3, startIndex); + } + + int ILayoutElement.layoutPriority { get { return 0; } } + float ILayoutElement.minWidth { get { return 0; } } + float ILayoutElement.minHeight { get { return 0; } } + float ILayoutElement.flexibleWidth { get { return -1; } } + float ILayoutElement.flexibleHeight { get { return -1; } } + + float ILayoutElement.preferredWidth + { + get + { + if (activeSprite == null) + return 0; + + return Sprites.DataUtility.GetMinSize(activeSprite).x / pixelsPerUnit; + } + } + + float ILayoutElement.preferredHeight + { + get + { + if (activeSprite == null) + return 0; + + return Sprites.DataUtility.GetMinSize(activeSprite).y / pixelsPerUnit; + } + } + + void ILayoutElement.CalculateLayoutInputHorizontal() { } + void ILayoutElement.CalculateLayoutInputVertical() { } + + bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera) + { + if (alphaHitTestMinimumThreshold <= 0) + return true; + + if (alphaHitTestMinimumThreshold > 1) + return false; + + if (activeSprite == null) + return true; + + Vector2 local; + if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local)) + return false; + + Rect rect = GetPixelAdjustedRect(); + + // Convert to have lower left corner as reference point. + local.x += rectTransform.pivot.x * rect.width; + local.y += rectTransform.pivot.y * rect.height; + + Rect spriteRect = activeSprite.rect; + Vector4 border = activeSprite.border; + Vector4 adjustedBorder = GetAdjustedBorders(border / pixelsPerUnit, rect); + + for (int i = 0; i < 2; i++) + { + if (local[i] <= adjustedBorder[i]) + continue; + + if (rect.size[i] - local[i] <= adjustedBorder[i + 2]) + { + local[i] -= (rect.size[i] - spriteRect.size[i]); + continue; + } + + float lerp = Mathf.InverseLerp(adjustedBorder[i], rect.size[i] - adjustedBorder[i + 2], local[i]); + local[i] = Mathf.Lerp(border[i], spriteRect.size[i] - border[i + 2], lerp); + } + + // Normalize local coordinates. + Rect textureRect = activeSprite.textureRect; + Vector2 normalized = new Vector2(local.x / textureRect.width, local.y / textureRect.height); + + // Convert to texture space. + float x = Mathf.Lerp(textureRect.x, textureRect.xMax, normalized.x) / activeSprite.texture.width; + float y = Mathf.Lerp(textureRect.y, textureRect.yMax, normalized.y) / activeSprite.texture.height; + + switch (m_FillDirection) + { + case FillDirection.Right: + if (x > m_FillAmount) + return false; + break; + case FillDirection.Left: + if (1f - x > m_FillAmount) + return false; + break; + case FillDirection.Up: + if (y > m_FillAmount) + return false; + break; + case FillDirection.Down: + if (1f - y > m_FillAmount) + return false; + break; + } + + try + { + return activeSprite.texture.GetPixelBilinear(x, y).a >= alphaHitTestMinimumThreshold; + } + catch (UnityException e) + { + Debug.LogError("Using alphaHitTestMinimumThreshold greater than 0 on Image whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this); + return true; + } + } + + void ISerializationCallbackReceiver.OnBeforeSerialize() { } + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + m_FillAmount = Mathf.Clamp01(m_FillAmount); + } + + // Whether this is being tracked for Atlas Binding + private bool m_Tracked = false; + +#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER + private static List m_TrackedTexturelessImages = new List(); + private static bool s_Initialized; +#endif + + private void TrackImage() + { + if (activeSprite != null && activeSprite.texture == null) + { +#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER + if (!s_Initialized) + { + SpriteAtlasManager.atlasRegistered += RebuildImage; + s_Initialized = true; + } + + m_TrackedTexturelessImages.Add(this); +#endif + m_Tracked = true; + } + } + + private void UnTrackImage() + { +#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER + m_TrackedTexturelessImages.Remove(this); +#endif + m_Tracked = false; + } + +#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER + private static void RebuildImage(SpriteAtlas spriteAtlas) + { + for (int i = m_TrackedTexturelessImages.Count - 1; i >= 0; i--) + { + SlicedSlider image = m_TrackedTexturelessImages[i]; + if (spriteAtlas.CanBindTo(image.activeSprite)) + { + image.SetAllDirty(); + m_TrackedTexturelessImages.RemoveAt(i); + } + } + } +#endif +} \ No newline at end of file diff --git a/Assets/SystemArchitecture/Scripts/SlicedSlider.cs.meta b/Assets/SystemArchitecture/Scripts/SlicedSlider.cs.meta new file mode 100644 index 0000000..273acc0 --- /dev/null +++ b/Assets/SystemArchitecture/Scripts/SlicedSlider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b69b55aa2ac2e0e4592740cf1269d52c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Accounts/Scripts/SystemController.cs b/Assets/SystemArchitecture/Scripts/SystemController.cs similarity index 65% rename from Assets/Accounts/Scripts/SystemController.cs rename to Assets/SystemArchitecture/Scripts/SystemController.cs index 69774b3..41f601f 100644 --- a/Assets/Accounts/Scripts/SystemController.cs +++ b/Assets/SystemArchitecture/Scripts/SystemController.cs @@ -17,6 +17,16 @@ public class SystemController ///
private Stack sceneStack = new Stack(); + /// + /// Index of the previous loaded scene + /// + public int previousScene = -1; + + /// + /// Index of the current loaded scene + /// + public int currentScene = -1; + /// /// Get the instance loaded by the singleton /// @@ -27,7 +37,8 @@ public class SystemController if (instance == null) { instance = new SystemController(); - instance.sceneStack.Push(SceneManager.GetActiveScene().buildIndex); + instance.currentScene = SceneManager.GetActiveScene().buildIndex; + instance.sceneStack.Push(instance.currentScene); } return instance; } @@ -38,7 +49,17 @@ public class SystemController /// Path of the scene public void LoadNextScene(string scenePath) { - LoadNextScene(SceneUtility.GetBuildIndexByScenePath(scenePath)); + LoadNextScene(SystemController.GetSceneIndex(scenePath)); + } + + /// + /// Get the index of a given scene + /// + /// Path of the scene + /// + public static int GetSceneIndex(string scenePath) + { + return SceneUtility.GetBuildIndexByScenePath(scenePath); } /// @@ -47,8 +68,11 @@ public class SystemController /// Buildindex of the scene public void LoadNextScene(int sceneIndex) { - sceneStack.Push(sceneIndex); - SceneManager.LoadScene(sceneIndex); + previousScene = currentScene; + currentScene = sceneIndex; + + sceneStack.Push(currentScene); + SceneManager.LoadScene(currentScene); } /// @@ -57,7 +81,7 @@ public class SystemController /// Path of the scene public void SwapScene(string scenePath) { - SwapScene(SceneUtility.GetBuildIndexByScenePath(scenePath)); + SwapScene(SystemController.GetSceneIndex(scenePath)); } /// @@ -66,7 +90,7 @@ public class SystemController /// Buildindex of the scene public void SwapScene(int sceneIndex) { - sceneStack.Pop(); + currentScene = sceneStack.Pop(); LoadNextScene(sceneIndex); } @@ -75,9 +99,8 @@ public class SystemController /// public void BackToPreviousScene() { - sceneStack.Pop(); - - if (sceneStack.Count > 0) SceneManager.LoadScene(sceneStack.Peek()); + previousScene = sceneStack.Pop(); + if (sceneStack.Count > 0) SceneManager.LoadScene(currentScene = sceneStack.Peek()); else Application.Quit(); } @@ -87,7 +110,7 @@ public class SystemController /// Path of the scene public void BackToScene(string scenePath) { - BackToScene(SceneUtility.GetBuildIndexByScenePath(scenePath)); + BackToScene(SystemController.GetSceneIndex(scenePath)); } /// @@ -96,9 +119,10 @@ public class SystemController /// Buildindex of the scene public void BackToScene(int sceneIndex) { + previousScene = currentScene; while (0 < sceneStack.Count && sceneStack.Peek() != sceneIndex) sceneStack.Pop(); - if (sceneStack.Count > 0) SceneManager.LoadScene(sceneStack.Peek()); + if (sceneStack.Count > 0) SceneManager.LoadScene(currentScene = sceneStack.Peek()); else Application.Quit(); } } diff --git a/Assets/Accounts/Scripts/SystemController.cs.meta b/Assets/SystemArchitecture/Scripts/SystemController.cs.meta similarity index 100% rename from Assets/Accounts/Scripts/SystemController.cs.meta rename to Assets/SystemArchitecture/Scripts/SystemController.cs.meta diff --git a/Assets/Common/Interfaces/ThemeIndex.cs b/Assets/SystemArchitecture/Scripts/ThemeIndex.cs similarity index 96% rename from Assets/Common/Interfaces/ThemeIndex.cs rename to Assets/SystemArchitecture/Scripts/ThemeIndex.cs index da93c90..4be508b 100644 --- a/Assets/Common/Interfaces/ThemeIndex.cs +++ b/Assets/SystemArchitecture/Scripts/ThemeIndex.cs @@ -5,6 +5,7 @@ public enum ThemeIndex { SIGN_ALPHABET, + SIGN_BASICS, SIGN_CLOTHING, SIGN_ANIMALS, SIGN_FOOD, diff --git a/Assets/Common/Interfaces/ThemeIndex.cs.meta b/Assets/SystemArchitecture/Scripts/ThemeIndex.cs.meta similarity index 100% rename from Assets/Common/Interfaces/ThemeIndex.cs.meta rename to Assets/SystemArchitecture/Scripts/ThemeIndex.cs.meta diff --git a/Packages/com.unity.barracuda/Tests.meta b/Assets/SystemArchitecture/Tests.meta similarity index 77% rename from Packages/com.unity.barracuda/Tests.meta rename to Assets/SystemArchitecture/Tests.meta index 4983e8b..0a1cfbf 100644 --- a/Packages/com.unity.barracuda/Tests.meta +++ b/Assets/SystemArchitecture/Tests.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0a5719d52937742fda1670a84426cc42 +guid: 8559f509b8f924f44bc10e2d20ac3eed folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/SystemArchitecture/Tests/ArchitectureTests.asmdef b/Assets/SystemArchitecture/Tests/ArchitectureTests.asmdef new file mode 100644 index 0000000..0192c2f --- /dev/null +++ b/Assets/SystemArchitecture/Tests/ArchitectureTests.asmdef @@ -0,0 +1,22 @@ +{ + "name": "ArchitectureTests", + "rootNamespace": "", + "references": [ + "UnityEditor.TestRunner", + "UnityEngine.TestRunner", + "ArchitectureScripts" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/SystemArchitecture/Tests/ArchitectureTests.asmdef.meta b/Assets/SystemArchitecture/Tests/ArchitectureTests.asmdef.meta new file mode 100644 index 0000000..e228634 --- /dev/null +++ b/Assets/SystemArchitecture/Tests/ArchitectureTests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b1a4ef95cbacdca459433eb2ddc05755 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SystemArchitecture/Tests/PersistentDataControllerTest.cs b/Assets/SystemArchitecture/Tests/PersistentDataControllerTest.cs new file mode 100644 index 0000000..ceb885d --- /dev/null +++ b/Assets/SystemArchitecture/Tests/PersistentDataControllerTest.cs @@ -0,0 +1,769 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + + +[TestFixture] +public class PersistentDataTests +{ + /// + /// Create a new path so the existing .json file will not be overwritten + /// + private static string PATH = $"{Application.persistentDataPath}/wesign_unit_test.json"; + + /// + /// Reference to the pdc to perform tests on + /// + private PersistentDataController pdc = null; + + /// + /// A dummy serializable struct to perform test operations on + /// + [Serializable] + private struct Struct + { + public int r, g, b; + public float x, y, z; + } + + /// + /// A dummy serializable enum to perform test operations on + /// + private enum Enum + { + SQUARE, + TRIANBLE, + CIRCLE + } + + [SetUp] + public void Setup_PersistentDataController() + { + PersistentDataController.PATH = PersistentDataTests.PATH; + //PersistentDataController.PATH = null; + pdc = PersistentDataController.GetInstance(); + } + + [Test] + public void Test_PersistentDataController_GetInstance() + { + Assert.IsNotNull(pdc); + //Assert.AreEqual($"{Application.persistentDataPath}/wesign_saved_data.json", PersistentDataController.PATH); + } + + [Test] + public void Test_PersistentDataController_Clear() + { + pdc.Load(); + pdc.Clear(); + Assert.Zero(pdc.GetUsers().Count); + Assert.AreEqual(-1, pdc.GetCurrentUser()); + } + + [Test] + public void Test_PersistentDataController_Save_Empty() + { + pdc.Load(); + pdc.Clear(); + + pdc.Save(); + FileAssert.Exists(PATH); + + string content = File.ReadAllText(PATH); + string expected = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[],\"currentUser\":-1,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + Assert.AreEqual(expected, content); + } + + [Test] + public void Test_PersistentDataController_Save_New() + { + pdc.Load(); + pdc.Clear(); + + if (File.Exists(PATH)) + File.Delete(PATH); + pdc.Save(); + FileAssert.Exists(PATH); + + string content = File.ReadAllText(PATH); + string expected = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[],\"currentUser\":-1,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + Assert.AreEqual(expected, content); + } + + [Test] + public void Test_PersistentDataController_Load_Existing() + { + string content = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[],\"currentUser\":-1,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(PATH, content); + Assert.IsTrue(pdc.Load(false)); + } + + [Test] + public void Test_PersistentDataController_Load_OlderVersion() + { + string content = $"{{\"version\":{PersistentDataController.VERSION - 1},\"users\":[],\"currentUser\":-1,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(PATH, content); + Assert.IsFalse(pdc.Load(false)); + } + + [Test] + public void Test_PersistentDataController_Load_NewerVersion() + { + string content = $"{{\"version\":{PersistentDataController.VERSION + 1},\"users\":[],\"currentUser\":-1,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + File.WriteAllText(PATH, content); + Assert.IsFalse(pdc.Load(false)); + } + + [Test] + public void Test_PersistentDataController_Load_New() + { + if (File.Exists(PATH)) + File.Delete(PATH); + Assert.IsFalse(pdc.Load(false)); + FileAssert.DoesNotExist(PATH); + } + + [Test] + public void Test_PersistentDataController_Load_Exception() + { + File.WriteAllText(PATH, "https://www.youtube.com/watch?v=dQw4w9WgXcQ"); + Assert.IsFalse(pdc.Load(false)); + Assert.AreEqual("https://www.youtube.com/watch?v=dQw4w9WgXcQ", File.ReadAllText(PATH)); + } + + [Test] + public void Test_PersistentDataController_Load_Override() + { + File.WriteAllText(PATH, "https://www.youtube.com/watch?v=dQw4w9WgXcQ"); + Assert.IsFalse(pdc.Load(true)); + string content = File.ReadAllText(PATH); + string expected = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[],\"currentUser\":-1,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + Assert.AreEqual(expected, content); + } + + [Test] + public void Test_PersistentDataController_Version() + { + const int VERSION = 0x04_03; + Assert.AreEqual(VERSION, PersistentDataController.VERSION); + } + + [Test] + public void Test_PersistentDataController_AddUser() + { + pdc.Load(); + pdc.Clear(); + var d = new PersistentDataController.SavedUserData() + { + username = "username", + avatarIndex = 0 + }; + + pdc.AddUser(d); + string content = File.ReadAllText(PATH); + string expected = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"username\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + Assert.AreEqual(expected, content); + } + + [Test] + public void Test_PersistentDataController_GetUsers() + { + pdc.Load(); + pdc.Clear(); + var d = new PersistentDataController.SavedUserData() + { + username = "username", + avatarIndex = 0 + }; + + pdc.AddUser(d); + var users = pdc.GetUsers(); + Assert.AreEqual(1, users.Count); + Assert.AreEqual("username", users[0].username); + Assert.AreEqual(0, users[0].avatarIndex); + } + + [Test] + public void Test_PersistentDataController_GetCurrentUser() + { + pdc.Load(); + pdc.Clear(); + + Assert.AreEqual(-1, pdc.GetCurrentUser()); + pdc.AddUser(new PersistentDataController.SavedUserData() + { + username = "username", + avatarIndex = 0 + }); + Assert.AreEqual(0, pdc.GetCurrentUser()); + } + + [Test] + public void Test_PersistentDataController_SetCurrentUser() + { + pdc.Load(); + pdc.Clear(); + + for (int i = 0; i < 5; i++) + pdc.AddUser(new PersistentDataController.SavedUserData() + { + username = $"username_{i}", + avatarIndex = i + }); + pdc.SetCurrentUser(3); + Assert.AreEqual(3, pdc.GetCurrentUser()); + } + + [Test] + public void Test_PersistentDataController_SetCurrentUser_Invalid() + { + pdc.Load(); + pdc.Clear(); + + pdc.AddUser(new PersistentDataController.SavedUserData() + { + username = $"username", + avatarIndex = 0 + }); + Assert.Throws(delegate { pdc.SetCurrentUser(3); }); + } + + [Test] + public void Test_PersistentDataController_SetCurrentUser_Empty() + { + pdc.Load(); + pdc.Clear(); + Assert.Throws(delegate { pdc.SetCurrentUser(0); }); + } + + [Test] + public void Test_PersistentDataController_DeleteUser_BeforeCurrent() + { + pdc.Load(); + pdc.Clear(); + + var users = new List(); + for (int i = 0; i < 5; i++) + { + var d = new PersistentDataController.SavedUserData() + { + username = $"username_{i}", + avatarIndex = i + }; + pdc.AddUser(d); + users.Add(d); + } + pdc.SetCurrentUser(0); + users.RemoveAt(2); + pdc.DeleteUser(2); + + var vsers = pdc.GetUsers(); + Assert.AreEqual(0, pdc.GetCurrentUser()); + Assert.AreEqual(users.Count, vsers.Count); + for (int i = 0; i < 4; i++) + { + Assert.AreEqual(users[i].username, vsers[i].username); + Assert.AreEqual(users[i].avatarIndex, vsers[i].avatarIndex); + } + } + + [Test] + public void Test_PersistentDataController_DeleteUser_Current() + { + pdc.Load(); + pdc.Clear(); + + var users = new List(); + for (int i = 0; i < 5; i++) + { + var d = new PersistentDataController.SavedUserData() + { + username = $"username_{i}", + avatarIndex = i + }; + pdc.AddUser(d); + users.Add(d); + } + pdc.SetCurrentUser(2); + users.RemoveAt(2); + pdc.DeleteUser(2); + + var vsers = pdc.GetUsers(); + Assert.AreEqual(1, pdc.GetCurrentUser()); + Assert.AreEqual(users.Count, vsers.Count); + for (int i = 0; i < 4; i++) + { + Assert.AreEqual(users[i].username, vsers[i].username); + Assert.AreEqual(users[i].avatarIndex, vsers[i].avatarIndex); + } + } + + [Test] + public void Test_PersistentDataController_DeleteUser_AfterCurrent() + { + pdc.Load(); + pdc.Clear(); + + var users = new List(); + for (int i = 0; i < 5; i++) + { + var d = new PersistentDataController.SavedUserData() + { + username = $"username_{i}", + avatarIndex = i + }; + pdc.AddUser(d); + users.Add(d); + + } + pdc.SetCurrentUser(4); + users.RemoveAt(2); + pdc.DeleteUser(2); + + var vsers = pdc.GetUsers(); + Assert.AreEqual(3, pdc.GetCurrentUser()); + Assert.AreEqual(users.Count, vsers.Count); + for (int i = 0; i < 4; i++) + { + Assert.AreEqual(users[i].username, vsers[i].username); + Assert.AreEqual(users[i].avatarIndex, vsers[i].avatarIndex); + } + } + + [Test] + public void Test_PersistentDataController_DeleteUser_Invalid() + { + pdc.Load(); + pdc.Clear(); + + pdc.AddUser(new PersistentDataController.SavedUserData() + { + username = $"username", + avatarIndex = 0 + }); + Assert.Throws(delegate { pdc.SetCurrentUser(3); }); + } + + [Test] + public void Test_PersistentDataController_DeleteUser_Empty() + { + pdc.Load(); + pdc.Clear(); + Assert.Throws(delegate { pdc.DeleteUser(0); }); + } + + [Test] + public void Test_PersistentDataController_CurrentCourse() + { + pdc.Load(); + pdc.Clear(); + pdc.SetCurrentCourse(CourseIndex.FINGERSPELLING); + Assert.AreEqual(CourseIndex.FINGERSPELLING, pdc.GetCurrentCourse()); + } + + [Test] + public void Test_PersistentDataController_CurrentMinigame() + { + pdc.Load(); + pdc.Clear(); + pdc.SetCurrentMinigame(MinigameIndex.SPELLING_BEE); + Assert.AreEqual(MinigameIndex.SPELLING_BEE, pdc.GetCurrentMinigame()); + } + + [Test] + public void Test_PersistentDataController_CurrentTheme() + { + pdc.Load(); + pdc.Clear(); + pdc.SetCurrentTheme(ThemeIndex.SIGN_ALPHABET); + Assert.AreEqual(ThemeIndex.SIGN_ALPHABET, pdc.GetCurrentTheme()); + } + + [Test] + public void Test_New_PersistentDataContainer() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsNotNull(c); + Assert.Zero(c.entries.Count); + } + + [Test] + public void Test_PersistentDataContainer_Set_Invalid() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsFalse(c.Set("key", null)); + } + + [Test] + public void Test_PersistentDataContainer_Set_DuplicateKey() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsTrue(c.Set("key", 123)); + Assert.IsTrue(c.Set("key", 321)); + } + + [Test] + public void Test_PersistentDataContainer_Set_Int() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsTrue(c.Set("key", 123)); + } + + [Test] + public void Test_PersistentDataContainer_Set_String() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsTrue(c.Set("key", "abc")); + } + + [Test] + public void Test_PersistentDataContainer_Set_Struct() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsTrue(c.Set("key", new Struct())); + } + + [Test] + public void Test_PersistentDataContainer_Set_Enum() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsTrue(c.Set("key", new Enum())); + } + + [Test] + public void Test_PersistentDataContainer_Get_InvalidType() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", new Struct() { r = 255, g = 127, b = 63, x = 31, y = 15, z = 7 }); + Assert.Throws(delegate { c.Get("key"); }); + c.Set("key", 123); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Get_KeyNotFound() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", 123); + Assert.Throws(delegate { c.Get("KEY"); }); + } + + [Test] + public void Test_PersistentDataContainer_Get_Empty() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Get_Int() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", 123); + Assert.AreEqual(123, c.Get("key")); + } + + [Test] + public void Test_PersistentDataContainer_Get_String() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", "value"); + Assert.AreEqual("value", c.Get("key")); + } + + [Test] + public void Test_PersistentDataContainer_Get_Struct() + { + var c = new PersistentDataController.PersistentDataContainer(); + var s = new Struct() { r = 255, g = 127, b = 63, x = 31, y = 15, z = 7 }; + c.Set("key", s); + Assert.AreEqual(s, c.Get("key")); + } + + [Test] + public void Test_PersistentDataContainer_Get_Enum() + { + var c = new PersistentDataController.PersistentDataContainer(); + var e = Enum.CIRCLE; + c.Set("key", e); + Assert.AreEqual(e, c.Get("key")); + } + + [Test] + public void Test_PersistentDataContainer_Remove_Invalid() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", 123); + Assert.Throws(delegate { c.Remove("KEY"); }); + } + + [Test] + public void Test_PersistentDataContainer_Remove_Empty() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.Throws(delegate { c.Remove("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Remove_Int() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", 123); + c.Remove("key"); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Remove_String() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", "value"); + c.Remove("key"); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Remove_Struct() + { + var c = new PersistentDataController.PersistentDataContainer(); + var s = new Struct() { r = 255, g = 127, b = 63, x = 31, y = 15, z = 7 }; + c.Set("key", s); + c.Remove("key"); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Remove_Enum() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", Enum.CIRCLE); + c.Remove("key"); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Pop_Invalid() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", 123); + Assert.Throws(delegate { c.Remove("KEY"); }); + } + + [Test] + public void Test_PersistentDataContainer_Pop_Empty() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.Throws(delegate { c.Remove("KEY"); }); + } + + [Test] + public void Test_PersistentDataContainer_Pop_Int() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", 123); + Assert.AreEqual(123, c.Pop("key")); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Pop_String() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", "value"); + Assert.AreEqual("value", c.Pop("key")); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Pop_Struct() + { + var c = new PersistentDataController.PersistentDataContainer(); + var s = new Struct() { r = 255, g = 127, b = 63, x = 31, y = 15, z = 7 }; + c.Set("key", s); + Assert.AreEqual(s, c.Pop("key")); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Pop_Enum() + { + var c = new PersistentDataController.PersistentDataContainer(); + c.Set("key", Enum.CIRCLE); + Assert.AreEqual(Enum.CIRCLE, c.Pop("key")); + Assert.Throws(delegate { c.Get("key"); }); + } + + [Test] + public void Test_PersistentDataContainer_Has_ValidKey() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsFalse(c.Has("key")); + c.Set("key", 123); + Assert.IsTrue(c.Has("key")); + } + + [Test] + public void Test_PersistentDataContainer_Has_InvalidKey() + { + var c = new PersistentDataController.PersistentDataContainer(); + Assert.IsFalse(c.Has("KEY")); + c.Set("key", 123); + Assert.IsFalse(c.Has("KEY")); + } + + [Test] + public void Test_AddLearnable_AddsLearnable() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + + bool added = progress.AddLearnable("test learnable", 0); + + Assert.IsTrue(added); + Assert.AreEqual(progress.learnables.Count, 1); + Assert.AreEqual(progress.learnables[0].name, "test learnable"); + Assert.AreEqual(progress.learnables[0].index, 0); + } + + [Test] + public void Test_AddLearnable_FailsWithDuplicateName() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + + progress.AddLearnable("test learnable", 0); + + bool added = progress.AddLearnable("test learnable", 1); + + Assert.IsFalse(added); + Assert.AreEqual(progress.learnables.Count, 1); + } + + [Test] + public void Test_AddLearnable_FailsWithDuplicateIndex() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + + progress.AddLearnable("test learnable", 0); + + bool added = progress.AddLearnable("test learnable 2", 0); + + Assert.IsFalse(added); + Assert.AreEqual(progress.learnables.Count, 1); + } + + + [Test] + public void Test_UpdateLearnable_UpdatesProgress() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + + progress.AddLearnable("test learnable", 0); + + progress.UpdateLearnable("test learnable", 3.0f); + + Assert.AreEqual(progress.learnables[0].progress, 3.0f); + } + + [Test] + public void Test_UpdateLearnable_CropsProgressAtFive() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + + progress.AddLearnable("test learnable", 0); + + progress.UpdateLearnable("test learnable", 10.0f); + + Assert.AreEqual(progress.learnables[0].progress, 5.0f); + Assert.AreEqual(progress.completedLearnables, 1); + } + + [Test] + public void Test_UpdateLearnable_CropsProgressAtNegativeFive() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + + progress.AddLearnable("test learnable", 0); + + progress.UpdateLearnable("test learnable", -10.0f); + + Assert.AreEqual(progress.learnables[0].progress, -5.0f); + } + + [Test] + public void Test_FindLearnable_ReturnsNullWhenNotFound() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + progress.AddLearnable("test learnable 1", 0); + progress.AddLearnable("test learnable 2", 1); + + PersistentDataController.SavedLearnableProgress learnable = progress.FindLearnable("not found"); + + Assert.IsNull(learnable); + } + + [Test] + public void Test_FindLearnable_ReturnsLearnableByName() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + progress.AddLearnable("test learnable 1", 0); + progress.AddLearnable("test learnable 2", 1); + + PersistentDataController.SavedLearnableProgress learnable = progress.FindLearnable("test learnable 2"); + + Assert.AreEqual(learnable.index, 1); + } + + [Test] + public void Test_AddNewLearnable_ReturnsFalseWhenNoUnusedLearnables() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + progress.AddLearnable("test learnable 1", 0); + progress.learnables[0].inUse = true; + + PersistentDataController.SavedLearnableProgress learnable = progress.AddNewLearnable(); + + Assert.IsNull(learnable); + } + + [Test] + public void Test_AddNewLearnable_ReturnsTrueWhenUnusedLearnableFound() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + progress.AddLearnable("test learnable 1", 0); + progress.AddLearnable("test learnable 2", 1); + + PersistentDataController.SavedLearnableProgress learnable = progress.AddNewLearnable(); + + Assert.IsNotNull(learnable); + Assert.AreEqual(progress.inUseLearnables, 1); + } + + [Test] + public void Test_GetRandomLearnable_ReturnsNullWhenNoLearnables() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + + PersistentDataController.SavedLearnableProgress learnable = progress.GetRandomLearnable(); + + Assert.IsNull(learnable); + } + + [Test] + public void Test_GetRandomLearnable_ReturnsNullWhenOnlyCompletedLearnables() + { + PersistentDataController.SavedCourseProgress progress = new PersistentDataController.SavedCourseProgress(); + progress.AddLearnable("test learnable 1", 0); + progress.AddLearnable("test learnable 2", 1); + progress.learnables[0].progress = 4.0f; + progress.learnables[0].inUse = true; + progress.learnables[1].progress = 4.0f; + progress.learnables[1].inUse = true; + progress.completedLearnables = 2; + progress.inUseLearnables = 0; + + PersistentDataController.SavedLearnableProgress learnable = progress.GetRandomLearnable(); + + Assert.IsNull(learnable); + } +} diff --git a/Assets/SystemArchitecture/Tests/PersistentDataControllerTest.cs.meta b/Assets/SystemArchitecture/Tests/PersistentDataControllerTest.cs.meta new file mode 100644 index 0000000..a406576 --- /dev/null +++ b/Assets/SystemArchitecture/Tests/PersistentDataControllerTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56873c5649b881846a54e2a2aa5ce499 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Installer/Output/WeSignInstaller.exe b/Installer/Output/WeSignInstaller.exe index 04ee0ea..b02aea9 100644 Binary files a/Installer/Output/WeSignInstaller.exe and b/Installer/Output/WeSignInstaller.exe differ diff --git a/Packages/com.unity.barracuda/Editor/BarracudaAnalytics.cs b/Packages/com.unity.barracuda/Editor/BarracudaAnalytics.cs deleted file mode 100644 index ab1109a..0000000 --- a/Packages/com.unity.barracuda/Editor/BarracudaAnalytics.cs +++ /dev/null @@ -1,148 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.Linq; -using Onnx; -using UnityEditor; -using UnityEngine.Analytics; - -namespace Unity.Barracuda.Editor -{ - internal class BarracudaAnalytics - { - static bool s_EventRegistered = false; - const int k_MaxEventsPerHour = 1000; - const int k_MaxNumberOfElements = 1000; - const string k_VendorKey = "unity.barracuda"; - const string k_ImportEventName = "uBarracudaImport"; - - static bool EnableAnalytics() - { - AnalyticsResult result = EditorAnalytics.RegisterEventWithLimit(k_ImportEventName, k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey); - if (result == AnalyticsResult.Ok) - s_EventRegistered = true; - - return s_EventRegistered; - } - - struct BarracudaImportAnalyticsData - { - public string model_type; - public string original_layers; - public string imported_layers; - public string import_warnings; - } - - public static void SendBarracudaImportEvent(object originalModel, Model importedModel) - { - //The event shouldn't be able to report if this is disabled but if we know we're not going to report - //Lets early out and not waste time gathering all the data - if (!EditorAnalytics.enabled) - return; - - if (!EnableAnalytics()) - return; - - - var data = new BarracudaImportAnalyticsData(); - - try - { - data.original_layers = AnalyzeONNXModel(originalModel); - data.imported_layers = AnalyzeNNModel(importedModel); - data.model_type = string.IsNullOrEmpty(data.original_layers) ? "NN" : "ONNX"; - data.import_warnings = AnalyzeWarnings(importedModel); - } - catch (Exception e) - { - D.LogError($"Failed collecting Barracuda analytics: {e}"); - } - - EditorAnalytics.SendEventWithLimit(k_ImportEventName, data); - } - - static string AnalyzeONNXModel(object originalModel) - { - if (!(originalModel is ModelProto)) - return ""; - - var layers = new Dictionary(); - - var onnxModel = originalModel as ModelProto; - foreach (var node in onnxModel.Graph.Node) - { - var layerDescription = node.OpType; - - if (!layers.ContainsKey(layerDescription)) - layers[layerDescription] = 1; - else - layers[layerDescription] += 1; - } - - return DictionaryToJson(layers); - } - - static string AnalyzeNNModel(Model importedModel) - { - var layers = new Dictionary(); - - foreach (Layer layer in importedModel.layers) - { - var layerDescription = LayerToString(layer); - - if (!layers.ContainsKey(layerDescription)) - layers[layerDescription] = 1; - else - layers[layerDescription] += 1; - } - - return DictionaryToJson(layers); - } - - static string LayerToString(Layer layer) - { - var layerDescription = layer.type.ToString(); - - if (layer.type == Layer.Type.Conv2D || layer.type == Layer.Type.Conv2DTrans || - layer.type == Layer.Type.Conv3D || layer.type == Layer.Type.Conv3DTrans || - layer.type == Layer.Type.DepthwiseConv2D) - { - layerDescription += "_" + ConvShapeToString(layer); - } - - if (layer.activation != Layer.Activation.None) - layerDescription += "_" + layer.activation.ToString(); - - return layerDescription; - } - - static string ConvShapeToString(Layer layer) - { - if (layer.type == Layer.Type.Conv2D || - layer.type == Layer.Type.DepthwiseConv2D || - layer.type == Layer.Type.Conv2DTrans) - return string.Join("_", - layer.datasets.Where(d => d.name.EndsWith("/K")).Select(it => - $"{it.shape.kernelHeight}x{it.shape.kernelWidth}x{it.shape.kernelDepth}x{it.shape.kernelCount}")); - - if (layer.type == Layer.Type.Conv3D || - layer.type == Layer.Type.Conv3DTrans) - return string.Join("_", - layer.datasets.Where(d => d.name.EndsWith("/K")).Select(it => - $"{it.shape.kernelSpatialDepth}x{it.shape.kernelHeight}x{it.shape.kernelWidth}x{it.shape.kernelDepth}x{it.shape.kernelCount}")); - - return ""; - } - - static string AnalyzeWarnings(Model importedModel) - { - return "[" + string.Join(",",importedModel.Warnings.Select(item => $"'{item.LayerName}:{item.Message}'")) + "]"; - } - - static string DictionaryToJson(Dictionary dict) - { - var entries = dict.Select(d => $"\"{d.Key}\":{string.Join(",", d.Value)}"); - return "{" + string.Join(",", entries) + "}"; - } - } -} diff --git a/Packages/com.unity.barracuda/Editor/BarracudaAnalytics.cs.meta b/Packages/com.unity.barracuda/Editor/BarracudaAnalytics.cs.meta deleted file mode 100644 index 2586bd5..0000000 --- a/Packages/com.unity.barracuda/Editor/BarracudaAnalytics.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 92cb0e57f8c0c4255a2d2d93f844424d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Editor/NNModelIcon.png b/Packages/com.unity.barracuda/Editor/NNModelIcon.png deleted file mode 100644 index 10434c2..0000000 Binary files a/Packages/com.unity.barracuda/Editor/NNModelIcon.png and /dev/null differ diff --git a/Packages/com.unity.barracuda/Editor/NNModelImporter.cs b/Packages/com.unity.barracuda/Editor/NNModelImporter.cs deleted file mode 100644 index 9a04136..0000000 --- a/Packages/com.unity.barracuda/Editor/NNModelImporter.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.IO; -using Unity.Barracuda.Editor; -using UnityEditor; -using UnityEngine; -#if UNITY_2020_2_OR_NEWER -using UnityEditor.AssetImporters; -using UnityEditor.Experimental.AssetImporters; -#else -using UnityEditor.Experimental.AssetImporters; -#endif - -namespace Unity.Barracuda -{ - /// - /// Asset Importer of barracuda models. - /// - [ScriptedImporter(3, new[] {"nn"})] - public class NNModelImporter : ScriptedImporter { - private const string iconName = "NNModelIcon"; - - private Texture2D iconTexture; - - /// - /// Scripted importer callback - /// - /// Asset import context - public override void OnImportAsset(AssetImportContext ctx) - { - var model = File.ReadAllBytes(ctx.assetPath); - - // Analyze model and send analytics if enabled - var nnModel = ModelLoader.Load(ctx.assetPath, skipWeights:true); - BarracudaAnalytics.SendBarracudaImportEvent(null, nnModel); - - var assetData = ScriptableObject.CreateInstance(); - assetData.Value = model; - assetData.name = "Data"; - assetData.hideFlags = HideFlags.HideInHierarchy; - - var asset = ScriptableObject.CreateInstance(); - asset.modelData = assetData; - ctx.AddObjectToAsset("main obj", asset, LoadIconTexture()); - ctx.AddObjectToAsset("model data", assetData); - - ctx.SetMainObject(asset); - } - - private Texture2D LoadIconTexture() - { - if (iconTexture == null) - { - string[] allCandidates = AssetDatabase.FindAssets(iconName); - - if (allCandidates.Length > 0) - { - iconTexture = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(allCandidates[0]), typeof(Texture2D)) as Texture2D; - } - } - return iconTexture; - } - - } -} diff --git a/Packages/com.unity.barracuda/Editor/NNModelImporter.cs.meta b/Packages/com.unity.barracuda/Editor/NNModelImporter.cs.meta deleted file mode 100644 index 98a74a1..0000000 --- a/Packages/com.unity.barracuda/Editor/NNModelImporter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 19ed1486aa27d4903b34839f37b8f69f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Editor/ONNXModelIcon.png b/Packages/com.unity.barracuda/Editor/ONNXModelIcon.png deleted file mode 100644 index 9f811a6..0000000 Binary files a/Packages/com.unity.barracuda/Editor/ONNXModelIcon.png and /dev/null differ diff --git a/Packages/com.unity.barracuda/Editor/ONNXModelImporter.cs b/Packages/com.unity.barracuda/Editor/ONNXModelImporter.cs deleted file mode 100644 index e6f8c04..0000000 --- a/Packages/com.unity.barracuda/Editor/ONNXModelImporter.cs +++ /dev/null @@ -1,106 +0,0 @@ -using UnityEngine; -using UnityEditor; -#if UNITY_2020_2_OR_NEWER -using UnityEditor.AssetImporters; -using UnityEditor.Experimental.AssetImporters; -#else -using UnityEditor.Experimental.AssetImporters; -#endif -using System; -using System.IO; -using System.Runtime.CompilerServices; -using Unity.Barracuda.Editor; -using Unity.Barracuda.ONNX; - -[assembly: InternalsVisibleToAttribute("Barracuda.EditorTests")] -[assembly: InternalsVisibleToAttribute("Unity.Barracuda.Tests")] - -namespace Unity.Barracuda -{ - /// - /// Asset Importer for Open Neural Network Exchange (ONNX) files. - /// For more information about ONNX file format see: https://github.com/onnx/onnx - /// - [ScriptedImporter(34, new[] { "onnx" })] - public class ONNXModelImporter : ScriptedImporter - { - // Configuration - /// - /// Enable ONNX model optimization during import. Set via importer UI - /// - public bool optimizeModel = true; - - /// - /// Fix batch size for ONNX models. Set via importer UI - /// - public bool forceArbitraryBatchSize = true; - - /// - /// Treat errors as warnings. Set via importer UI - /// - public bool treatErrorsAsWarnings = false; - - [SerializeField, HideInInspector] - internal ONNXModelConverter.ImportMode importMode = ONNXModelConverter.ImportMode.Standard; - - [SerializeField, HideInInspector] - internal ONNXModelConverter.DataTypeMode weightsTypeMode = ONNXModelConverter.DataTypeMode.Default; - [SerializeField, HideInInspector] - internal ONNXModelConverter.DataTypeMode activationTypeMode = ONNXModelConverter.DataTypeMode.Default; - - internal const string iconName = "ONNXModelIcon"; - - - private Texture2D m_IconTexture; - - /// - /// Scripted importer callback - /// - /// Asset import context - public override void OnImportAsset(AssetImportContext ctx) - { - ONNXModelConverter.ModelImported += BarracudaAnalytics.SendBarracudaImportEvent; - var converter = new ONNXModelConverter(optimizeModel, treatErrorsAsWarnings, forceArbitraryBatchSize, importMode); - - var model = converter.Convert(ctx.assetPath); - - if (weightsTypeMode == ONNXModelConverter.DataTypeMode.ForceHalf) - model.ConvertWeights(DataType.Half); - else if (weightsTypeMode == ONNXModelConverter.DataTypeMode.ForceFloat) - model.ConvertWeights(DataType.Float); - - NNModelData assetData = ScriptableObject.CreateInstance(); - using (var memoryStream = new MemoryStream()) - using (var writer = new BinaryWriter(memoryStream)) - { - ModelWriter.Save(writer, model); - assetData.Value = memoryStream.ToArray(); - } - assetData.name = "Data"; - assetData.hideFlags = HideFlags.HideInHierarchy; - - NNModel asset = ScriptableObject.CreateInstance(); - asset.modelData = assetData; - - ctx.AddObjectToAsset("main obj", asset, LoadIconTexture()); - ctx.AddObjectToAsset("model data", assetData); - - ctx.SetMainObject(asset); - } - - // Icon helper - private Texture2D LoadIconTexture() - { - if (m_IconTexture == null) - { - string[] allCandidates = AssetDatabase.FindAssets(iconName); - - if (allCandidates.Length > 0) - { - m_IconTexture = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(allCandidates[0]), typeof(Texture2D)) as Texture2D; - } - } - return m_IconTexture; - } - } -} diff --git a/Packages/com.unity.barracuda/Editor/ONNXModelImporter.cs.meta b/Packages/com.unity.barracuda/Editor/ONNXModelImporter.cs.meta deleted file mode 100644 index 1d01a82..0000000 --- a/Packages/com.unity.barracuda/Editor/ONNXModelImporter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 683b6cb6d0a474744822c888b46772c9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Editor/ONNXModelImporterEditor.cs b/Packages/com.unity.barracuda/Editor/ONNXModelImporterEditor.cs deleted file mode 100644 index 89c104b..0000000 --- a/Packages/com.unity.barracuda/Editor/ONNXModelImporterEditor.cs +++ /dev/null @@ -1,461 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using UnityEditor; -#if UNITY_2020_2_OR_NEWER -using UnityEditor.AssetImporters; -using UnityEditor.Experimental.AssetImporters; -#else -using UnityEditor.Experimental.AssetImporters; -#endif -using UnityEngine; -using System; -using System.IO; -using System.Reflection; -using Unity.Barracuda.ONNX; -using ImportMode=Unity.Barracuda.ONNX.ONNXModelConverter.ImportMode; -using DataTypeMode=Unity.Barracuda.ONNX.ONNXModelConverter.DataTypeMode; - -namespace Unity.Barracuda.Editor -{ -/// -/// Asset Importer Editor of ONNX models -/// -[CustomEditor(typeof(ONNXModelImporter))] -[CanEditMultipleObjects] -public class ONNXModelImporterEditor : ScriptedImporterEditor -{ - static PropertyInfo s_InspectorModeInfo; - static ONNXModelImporterEditor() - { - s_InspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance); - } - - /// - /// Scripted importer editor UI callback - /// - public override void OnInspectorGUI() - { - var onnxModelImporter = target as ONNXModelImporter; - if (onnxModelImporter == null) - return; - - InspectorMode inspectorMode = InspectorMode.Normal; - if (s_InspectorModeInfo != null) - inspectorMode = (InspectorMode)s_InspectorModeInfo.GetValue(assetSerializedObject); - - serializedObject.Update(); - - bool debugView = inspectorMode != InspectorMode.Normal; - SerializedProperty iterator = serializedObject.GetIterator(); - for (bool enterChildren = true; iterator.NextVisible(enterChildren); enterChildren = false) - { - if (iterator.propertyPath != "m_Script") - EditorGUILayout.PropertyField(iterator, true); - } - - // Additional options exposed from ImportMode - SerializedProperty importModeProperty = serializedObject.FindProperty(nameof(onnxModelImporter.importMode)); - bool skipMetadataImport = ((ImportMode)importModeProperty.intValue).HasFlag(ImportMode.SkipMetadataImport); - if (EditorGUILayout.Toggle("Skip Metadata Import", skipMetadataImport) != skipMetadataImport) - { - importModeProperty.intValue ^= (int)ImportMode.SkipMetadataImport; - } - - if (debugView) - { - importModeProperty.intValue = (int)(ImportMode)EditorGUILayout.EnumFlagsField("Import Mode", (ImportMode)importModeProperty.intValue); - - SerializedProperty weightsTypeMode = serializedObject.FindProperty(nameof(onnxModelImporter.weightsTypeMode)); - SerializedProperty activationTypeMode = serializedObject.FindProperty(nameof(onnxModelImporter.activationTypeMode)); - weightsTypeMode.intValue = (int)(DataTypeMode)EditorGUILayout.EnumPopup("Weights type", (DataTypeMode)weightsTypeMode.intValue); - activationTypeMode.intValue = (int)(DataTypeMode)EditorGUILayout.EnumPopup("Activation type", (DataTypeMode)activationTypeMode.intValue); - } - else - { - if (onnxModelImporter.optimizeModel) - EditorGUILayout.HelpBox("Model optimizations are on\nRemove and re-import model if you observe incorrect behavior", MessageType.Info); - - if (onnxModelImporter.importMode == ImportMode.Legacy) - EditorGUILayout.HelpBox("Legacy importer is in use", MessageType.Warning); - } - - serializedObject.ApplyModifiedProperties(); - - ApplyRevertGUI(); - } -} - -/// -/// Asset Importer Editor of NNModel (the serialized file generated by ONNXModelImporter) -/// -[CustomEditor(typeof(NNModel))] -public class NNModelEditor : UnityEditor.Editor -{ - // Use a static store for the foldouts, so it applies to all inspectors - static Dictionary s_UIHelperFoldouts = new Dictionary(); - - private Model m_Model; - private List m_Inputs = new List(); - private List m_InputsDesc = new List(); - private List m_Outputs = new List(); - private List m_OutputsDesc = new List(); - private List m_Memories = new List(); - private List m_MemoriesDesc = new List(); - private List m_Layers = new List(); - private List m_LayersDesc = new List(); - private List m_Constants = new List(); - private List m_ConstantsDesc = new List(); - - Dictionary m_Metadata = new Dictionary(); - Vector2 m_MetadataScrollPosition = Vector2.zero; - // warnings - private Dictionary m_WarningsNeutral = new Dictionary(); - private Dictionary m_WarningsInfo = new Dictionary(); - private Dictionary m_WarningsWarning = new Dictionary(); - private Dictionary m_WarningsError = new Dictionary(); - private Vector2 m_WarningsNeutralScrollPosition = Vector2.zero; - private Vector2 m_WarningsInfoScrollPosition = Vector2.zero; - private Vector2 m_WarningsWarningScrollPosition = Vector2.zero; - private Vector2 m_WarningsErrorScrollPosition = Vector2.zero; - - - private long m_NumEmbeddedWeights; - private long m_NumConstantWeights; - private long m_TotalWeightsSizeInBytes; - - private Vector2 m_InputsScrollPosition = Vector2.zero; - private Vector2 m_OutputsScrollPosition = Vector2.zero; - private Vector2 m_MemoriesScrollPosition = Vector2.zero; - private Vector2 m_LayerScrollPosition = Vector2.zero; - private Vector2 m_ConstantScrollPosition = Vector2.zero; - private const float k_Space = 5f; - - private Texture2D m_IconTexture; - private Texture2D LoadIconTexture() - { - if (m_IconTexture != null) - return m_IconTexture; - - string[] allCandidates = AssetDatabase.FindAssets(ONNXModelImporter.iconName); - if (allCandidates.Length > 0) - m_IconTexture = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(allCandidates[0]), typeof(Texture2D)) as Texture2D; - - return m_IconTexture; - } - - /// - /// Editor static preview rendering callback - /// - /// Asset path - /// Child assets - /// width - /// height - /// - public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height) - { - Texture2D icon = LoadIconTexture(); - if (icon == null) - return null; - Texture2D tex = new Texture2D(width, height); - EditorUtility.CopySerialized(icon, tex); - return tex; - } - - private void AddDimension(StringBuilder stringBuilder, string name, int value, bool lastDim=false) - { - string strValue = (value >= 1) ? value.ToString() : "*"; - stringBuilder.AppendFormat("{0}:{1}", name, strValue); - if (!lastDim) - stringBuilder.Append(", "); - } - - private string GetUIStringFromShape(int[] shape) - { - StringBuilder stringBuilder = new StringBuilder("shape: (", 50); - if (shape.Length == 8) - { - bool is8D = (shape[0] > 1 || shape[1] > 1 || shape[3] > 1 || shape[4] > 1); - if (is8D) AddDimension(stringBuilder, "s", shape[0]); - if (is8D) AddDimension(stringBuilder, "r", shape[1]); - AddDimension(stringBuilder, "n", shape[2]); - if (is8D) AddDimension(stringBuilder, "t", shape[3]); - if (is8D) AddDimension(stringBuilder, "d", shape[4]); - AddDimension(stringBuilder, "h", shape[5]); - AddDimension(stringBuilder, "w", shape[6]); - AddDimension(stringBuilder, "c", shape[7], true); - } - else - { - UnityEngine.Debug.Assert(shape.Length == 4); - AddDimension(stringBuilder, "n", shape[0]); - AddDimension(stringBuilder, "h", shape[1]); - AddDimension(stringBuilder, "w", shape[2]); - AddDimension(stringBuilder, "c", shape[3], true); - } - stringBuilder.Append(")"); - return stringBuilder.ToString(); - } - - void OnEnable() - { - var nnModel = target as NNModel; - if (nnModel == null) - return; - if (nnModel.modelData == null) - return; - - m_Model = nnModel.GetDeserializedModel(); - if (m_Model == null) - return; - - m_Inputs = m_Model.inputs.Select(i => i.name).ToList(); - m_InputsDesc = m_Model.inputs.Select(i => GetUIStringFromShape(i.shape)).ToList(); - m_Outputs = m_Model.outputs.ToList(); - - bool allKnownInputShapes = true; - var inputShapes = new Dictionary(); - foreach (var i in m_Model.inputs) - { - allKnownInputShapes = allKnownInputShapes && ModelAnalyzer.IsInputShapeAcceptablyKnowForShapeInference(i); - if (!allKnownInputShapes) - break; - inputShapes.Add(i.name, new TensorShape(i.shape)); - } - if (allKnownInputShapes) - { - m_OutputsDesc = m_Model.outputs.Select(i => { - string output = "shape: (n:*, h:*, w:*, c:*)"; - try - { - TensorShape shape; - if (ModelAnalyzer.TryGetOutputTensorShape(m_Model, inputShapes, i, out shape)) - output = GetUIStringFromShape(shape.ToArray()); - } - catch (Exception e) - { - Debug.LogError($"Unexpected error while evaluating model output {i}. {e}"); - } - return output; }).ToList(); - } - else - { - m_OutputsDesc = m_Model.outputs.Select(i => "shape: (n:*, h:*, w:*, c:*)").ToList(); - } - - m_Memories = m_Model.memories.Select(i => i.input).ToList(); - m_MemoriesDesc = m_Model.memories.Select(i => $"shape:{i.shape.ToString()} output:{i.output}").ToList(); - - var layers = m_Model.layers.Where(i => i.type != Layer.Type.Load); - var constants = m_Model.layers.Where(i => i.type == Layer.Type.Load); - - m_Layers = layers.Select(i => i.type.ToString()).ToList(); - m_LayersDesc = layers.Select(i => i.ToString()).ToList(); - m_Constants = constants.Select(i => i.type.ToString()).ToList(); - m_ConstantsDesc = constants.Select(i => i.ToString()).ToList(); - - m_NumEmbeddedWeights = layers.Sum(l => (long)l.datasets.Sum(ds => (long)ds.length)); - m_NumConstantWeights = constants.Sum(l => (long)l.datasets.Sum(ds => (long)ds.length)); - - // weights are not loaded for UI, recompute size - m_TotalWeightsSizeInBytes = 0; - for (var l = 0; l < m_Model.layers.Count; ++l) - for (var d = 0; d < m_Model.layers[l].datasets.Length; ++d) - m_TotalWeightsSizeInBytes += m_Model.layers[l].datasets[d].length * m_Model.layers[l].datasets[d].itemSizeInBytes; - - m_Metadata = new Dictionary(m_Model.Metadata); - - for (int i = 0; i < m_Model.Warnings.Count; i++) - { - var warning = m_Model.Warnings[i].LayerName; - var warningDesc = m_Model.Warnings[i].Message; - MessageType messageType = MessageType.Warning; - if(warningDesc.StartsWith("MessageType")) - { - messageType = (MessageType)(warningDesc[12] - '0'); - warningDesc = warningDesc.Substring(13); - } - - switch (messageType) - { - case MessageType.None: - m_WarningsNeutral[warning] = warningDesc; - break; - case MessageType.Info: - m_WarningsInfo[warning] = warningDesc; - break; - case MessageType.Warning: - m_WarningsWarning[warning] = warningDesc; - break; - case MessageType.Error: - m_WarningsError[warning] = warningDesc; - break; - } - } - } - - private void OpenNNModelAsTempFileButton(NNModel nnModel) - { - if (nnModel == null) - return; - if (nnModel.modelData == null) - return; - - if (GUILayout.Button("Open imported NN model as temp file")) - { - string tempPath = Application.temporaryCachePath; - string filePath = Path.Combine(tempPath, nnModel.name); - string filePathWithExtension = Path.ChangeExtension(filePath, "nn"); - File.WriteAllBytes(filePathWithExtension, nnModel.modelData.Value); - System.Diagnostics.Process.Start(filePathWithExtension); - } - } - - /// - /// Editor UI rendering callback - /// - public override void OnInspectorGUI() - { - if (m_Model == null) - return; - - // HACK: When inspector settings are applied and the file is re-imported there doesn't seem to be a clean way to - // get a notification from Unity, so we detect this change - var nnModel = target as NNModel; - if (nnModel && m_Model != nnModel.GetDeserializedModel()) - OnEnable(); // Model data changed underneath while inspector was active, so reload - - GUI.enabled = true; - OpenNNModelAsTempFileButton(nnModel); - GUILayout.Label($"Source: {m_Model.IrSource}"); - GUILayout.Label($"Version: {m_Model.IrVersion}"); - GUILayout.Label($"Producer Name: {m_Model.ProducerName}"); - - if (m_Metadata.Any()) - { - ListUIHelper($"Metadata {m_Metadata.Count}", - m_Metadata.Keys.ToList(), m_Metadata.Values.ToList(), ref m_MetadataScrollPosition); - } - - if(m_WarningsError.Any()) - { - ListUIHelper($"Errors {m_WarningsError.Count.ToString()}", m_WarningsError.Keys.ToList(), m_WarningsError.Values.ToList(), ref m_WarningsErrorScrollPosition); - EditorGUILayout.HelpBox("Model contains errors. Behavior might be incorrect", MessageType.Error, true); - } - if(m_WarningsWarning.Any()) - { - ListUIHelper($"Warnings {m_WarningsWarning.Count.ToString()}", m_WarningsWarning.Keys.ToList(), m_WarningsWarning.Values.ToList(), ref m_WarningsWarningScrollPosition); - EditorGUILayout.HelpBox("Model contains warnings. Behavior might be incorrect", MessageType.Warning, true); - } - if(m_WarningsInfo.Any()) - { - ListUIHelper($"Information: ", m_WarningsInfo.Keys.ToList(), m_WarningsInfo.Values.ToList(), ref m_WarningsInfoScrollPosition); - EditorGUILayout.HelpBox("Model contains import information.", MessageType.Info, true); - } - if(m_WarningsNeutral.Any()) - { - ListUIHelper($"Comments: ", m_WarningsNeutral.Keys.ToList(), m_WarningsNeutral.Values.ToList(), ref m_WarningsNeutralScrollPosition); - } - var constantWeightInfo = m_Constants.Count > 0 ? $" using {m_NumConstantWeights:n0} weights" : ""; - ListUIHelper($"Inputs ({m_Inputs.Count})", m_Inputs, m_InputsDesc, ref m_InputsScrollPosition); - ListUIHelper($"Outputs ({m_Outputs.Count})", m_Outputs, m_OutputsDesc, ref m_OutputsScrollPosition); - ListUIHelper($"Memories ({m_Memories.Count})", m_Memories, m_MemoriesDesc, ref m_MemoriesScrollPosition); - ListUIHelper($"Layers ({m_Layers.Count} using {m_NumEmbeddedWeights:n0} embedded weights)", m_Layers, m_LayersDesc, ref m_LayerScrollPosition, m_Constants.Count == 0 ? 1.5f: 1f); - ListUIHelper($"Constants ({m_Constants.Count}{constantWeightInfo})", m_Constants, m_ConstantsDesc, ref m_ConstantScrollPosition); - - GUILayout.Label($"Total weight size: {m_TotalWeightsSizeInBytes:n0} bytes"); - } - - private static void ListUIHelper(string sectionTitle, IReadOnlyList names, IReadOnlyList descriptions, ref Vector2 scrollPosition, float maxHeightMultiplier = 1f) - { - int n = names.Count(); - UnityEngine.Debug.Assert(descriptions.Count == n); - if (descriptions.Count < n) - return; - - GUILayout.Space(k_Space); - if (!s_UIHelperFoldouts.TryGetValue(sectionTitle, out bool foldout)) - foldout = true; - - foldout = EditorGUILayout.Foldout(foldout, sectionTitle, true, EditorStyles.foldoutHeader); - s_UIHelperFoldouts[sectionTitle] = foldout; - if (foldout) - { - // GUILayout.Label(sectionTitle, EditorStyles.boldLabel); - float height = Mathf.Min(n * 20f + 2f, 150f * maxHeightMultiplier); - if (n == 0) - return; - - scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUI.skin.box, GUILayout.MinHeight(height)); - Event e = Event.current; - float lineHeight = 16.0f; - - StringBuilder fullText = new StringBuilder(); - fullText.Append(sectionTitle); - fullText.AppendLine(); - for (int i = 0; i < n; ++i) - { - string name = names[i]; - string description = descriptions[i]; - fullText.Append($"{name} {description}"); - fullText.AppendLine(); - } - - for (int i = 0; i < n; ++i) - { - Rect r = EditorGUILayout.GetControlRect(false, lineHeight); - - string name = names[i]; - string description = descriptions[i]; - - // Context menu, "Copy" - if (e.type == EventType.ContextClick && r.Contains(e.mousePosition)) - { - e.Use(); - var menu = new GenericMenu(); - - // need to copy current value to be used in delegate - // (C# closures close over variables, not their values) - menu.AddItem(new GUIContent($"Copy current line"), false, delegate - { - EditorGUIUtility.systemCopyBuffer = $"{name} {description}"; - }); - menu.AddItem(new GUIContent($"Copy section"), false, delegate - { - EditorGUIUtility.systemCopyBuffer = fullText.ToString(); - }); - menu.ShowAsContext(); - } - - // Color even line for readability - if (e.type == EventType.Repaint) - { - GUIStyle st = "CN EntryBackEven"; - if ((i & 1) == 0) - st.Draw(r, false, false, false, false); - } - - // layer name on the right side - Rect locRect = r; - locRect.xMax = locRect.xMin; - GUIContent gc = new GUIContent(name.ToString(CultureInfo.InvariantCulture)); - - // calculate size so we can left-align it - Vector2 size = EditorStyles.miniBoldLabel.CalcSize(gc); - locRect.xMax += size.x; - GUI.Label(locRect, gc, EditorStyles.miniBoldLabel); - locRect.xMax += 2; - - // message - Rect msgRect = r; - msgRect.xMin = locRect.xMax; - GUI.Label(msgRect, new GUIContent(description.ToString(CultureInfo.InvariantCulture)), EditorStyles.miniLabel); - } - - GUILayout.EndScrollView(); - } - } -} - -} diff --git a/Packages/com.unity.barracuda/Editor/ONNXModelImporterEditor.cs.meta b/Packages/com.unity.barracuda/Editor/ONNXModelImporterEditor.cs.meta deleted file mode 100644 index c538291..0000000 --- a/Packages/com.unity.barracuda/Editor/ONNXModelImporterEditor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 08ecb3218a86c6741aed5b2a299b203b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Editor/Unity.Barracuda.Editor.asmdef b/Packages/com.unity.barracuda/Editor/Unity.Barracuda.Editor.asmdef deleted file mode 100644 index 9b95609..0000000 --- a/Packages/com.unity.barracuda/Editor/Unity.Barracuda.Editor.asmdef +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "Unity.Barracuda.Editor", - "references": [ - "Unity.Barracuda", - "Unity.Barracuda.ONNX" - ], - "optionalUnityReferences": [], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/Core.meta b/Packages/com.unity.barracuda/Runtime/Core.meta deleted file mode 100644 index 65bcbca..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5bec48e8f6ff349488387cf35fbae752 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/AssemblyInfo.cs b/Packages/com.unity.barracuda/Runtime/Core/AssemblyInfo.cs deleted file mode 100644 index 18f9507..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Reflection; - -// DON'T EDIT -// Will be replaced by Tools/Build/build.py -[assembly: AssemblyVersion("3.0.0.0")] -[assembly: AssemblyFileVersion("3.0.0.0")] - diff --git a/Packages/com.unity.barracuda/Runtime/Core/AssemblyInfo.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/AssemblyInfo.cs.meta deleted file mode 100644 index d6d44d7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/AssemblyInfo.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: f7f9574517c146ada866c486dc392731 -timeCreated: 1533296387 \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends.meta deleted file mode 100644 index 35d3de3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 12a6bedd18899cd4189f66d8188f29ff -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackends.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackends.cs deleted file mode 100644 index f62ef77..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackends.cs +++ /dev/null @@ -1,1390 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Unity.Barracuda { - -/// -/// Interfaces for backend implementers -/// see ModelBuilder.cs for detail on layers. -/// -public interface IOps : IOpsStatistics -{ - /// - /// Matrix multiplication o = `x` ⨯ `y` - /// - /// left Tensor - /// transposed `x` flag - /// right Tensor - /// transposed `y` flag - /// output Tensor - Tensor MatMul(Tensor x, bool xTranspose, Tensor y, bool yTranspose);// @TODO: consider MatMulAdd instead - - /// - /// Multidimensional Matrix multiplication o = `x` ⨯ `y` - /// - /// left Tensor - /// rank of `x` - /// right Tensor - /// rank of `y` - /// output Tensor - Tensor MatMul(Tensor x, int rankX, Tensor y, int rankY); - - /// - /// Dense layer (matrix multiplication) o = `x` ⨯ `w` + `b` - /// - /// x argument - /// w argument - /// bias argument - /// fused activation type - /// output Tensor - Tensor Dense(Tensor x, Tensor w, Tensor b, Layer.FusedActivation fusedActivation); - - /// - /// rank3 Dense layer (matrix multiplication) o = `x` ⨯ `w` + `b` - /// O: N,_,W,C / X: N,_,W,C / W:N,_,_,C / B:N,_,_,_ - /// - /// x argument (rank3) - /// w argument (rank2) - /// bias argument (rank1) - /// fused activation type - /// output Tensor - Tensor Dense3(Tensor x, Tensor w, Tensor b); - - - /// - /// 2D convolution - /// - /// input - /// kernel - /// bias - /// stride - /// padding - /// fused activation type - /// output Tensor - Tensor Conv2D(Tensor x, Tensor k, Tensor b, int[] stride, int[] pad, Layer.FusedActivation fusedActivation); - - /// - /// 3D convolution - /// - /// input - /// kernel - /// bias - /// stride - /// padding - /// fused activation type - /// output Tensor - Tensor Conv3D(Tensor x, Tensor k, Tensor b, int[] stride, int[] pad, Layer.FusedActivation fusedActivation); - - /// - /// Depthwise 2D convolution - /// - /// input - /// kernel - /// bias - /// stride - /// padding - /// fused activation type - /// output Tensor - Tensor DepthwiseConv2D(Tensor x, Tensor k, Tensor b, int[] stride, int[] pad, Layer.FusedActivation fusedActivation); - - /// - /// Transpose 2D convolution - /// - /// input - /// kernel - /// bias - /// stride - /// padding - /// output adjustments - /// fused activation type - /// output Tensor - Tensor Conv2DTrans(Tensor x, Tensor k, Tensor b, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation); - - /// - /// Upsample 2D - /// - /// input - /// scale - /// bilinear flag - /// output Tensor - Tensor Upsample2D(Tensor x, int[] scale, bool bilinear); - - /// - /// Upsample 3D - /// - /// input - /// scale - /// trilinear flag - /// output Tensor - Tensor Upsample3D(Tensor x, int[] scale, bool trilinear); - - /// - /// Resample 2D - /// - /// input - /// size - /// bilinear flag - /// output Tensor - Tensor Resample2D(Tensor x, int[] size, bool bilinear); - - /// - /// Depth to space - /// - /// input - /// scale - /// mode - /// output Tensor - Tensor DepthToSpace(Tensor x, int[] scale, Layer.DepthToSpaceMode mode); - - /// - /// Space to depth - /// - /// input - /// scale - /// output Tensor - Tensor SpaceToDepth(Tensor x, int[] scale); - - /// - /// 2D max pooling - /// - /// input - /// pooling - /// stride - /// padding - /// output Tensor - Tensor MaxPool2D(Tensor x, int[] pool, int[] stride, int[] pad); - - /// - /// 2D average pooling - /// - /// input - /// pooling - /// stride - /// padding - /// output Tensor - Tensor AvgPool2D(Tensor x, int[] pool, int[] stride, int[] pad); - - /// - /// 2D global max pooling - /// - /// input - /// output Tensor - Tensor GlobalMaxPool2D(Tensor x); // @TODO: consider, if it should be just a special case of MaxPool2D with {pool=X.width/height, stride=1} - - /// - /// 2D global average pooling - /// - /// input - /// output Tensor - Tensor GlobalAvgPool2D(Tensor x); - - /// - /// 2D global average variance pooling - /// - /// input - /// output Tensor - Tensor GlobalAvgVariancePool2D(Tensor x); - - /// - /// 2D border padding - /// - /// input - /// padding - /// border value - /// output Tensor - Tensor Border2D(Tensor x, int[] pad, float borderValue); - - /// - /// 3D border padding - /// - /// input - /// padding - /// border value - /// output Tensor - Tensor Border3D(Tensor x, int[] pad, float borderValue); - - /// - /// Reflection padding - /// - /// input - /// padding - /// output Tensor - Tensor Pad2DReflect(Tensor x, int[] pad); - - /// - /// Symmetric padding - /// - /// input - /// padding - /// output Tensor - Tensor Pad2DSymmetric(Tensor x, int[] pad); - - /// - /// Edge padding - /// - /// input - /// padding - /// output Tensor - Tensor Pad2DEdge(Tensor x, int[] pad); - - /// - /// Scale bias o = s * x + b, element wise - /// - /// input - /// scale - /// bias - /// output Tensor - Tensor ScaleBias(Tensor x, Tensor s, Tensor b); - - /// - /// Normalization - /// - /// input - /// scale - /// bias - /// pooling - /// axis - /// threshold - /// fused activation type - /// output Tensor - Tensor Normalization(Tensor x, Tensor s, Tensor b, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation); - - /// - /// LRN (Local Response Normalization) - /// - /// input - /// alpha - /// beta - /// bias - /// size - /// output Tensor - Tensor LRN(Tensor x, float alpha, float beta, float bias, int size); - - /// - /// Dropout - /// - /// input - /// alpha - /// output Tensor - Tensor Dropout(Tensor x, float alpha); - - /// - /// Normal random distribution - /// - /// shape - /// mean - /// scale - /// seed - /// output Tensor - Tensor RandomNormal(TensorShape s, float mean, float scale, int seed); - - /// - /// Uniform random distribution - /// - /// shape - /// mean - /// scale - /// seed - /// output Tensor - Tensor RandomUniform(TensorShape s, float mean, float scale, int seed); - - /// - /// Multinomial random distribution - /// - /// input - /// count - /// seed - /// output Tensor - Tensor Multinomial(Tensor x, int count, int seed); - - /// - /// One hot - /// - /// input - /// output depth - /// on value - /// off value - /// input rank helper - /// output Tensor - Tensor OneHot(Tensor x, int depth, float onValue, float offValue, int inputRank=-1); - - /// - /// RoiAlign - /// - /// input - /// rois - /// batch indices - /// outputHeight - /// outputWidth - /// samplingRatio - /// spatialScale - /// output Tensor - Tensor RoiAlign(Tensor x, Tensor rois, Tensor indices, int outputHeight, int outputWidth, int samplingRatio, float spatialScale); - - /// - /// Top K indices - /// - /// input - /// k - /// axis - /// largest flag - /// sorted flag - /// output Tensor - Tensor TopKIndices(Tensor x, int k, int axis, bool largest, bool sorted); - - /// - /// Top K values - /// - /// input - /// indices - /// axis - /// output Tensor - Tensor TopKValues(Tensor X, Tensor I, int axis); - - /// - /// Indices for non zero values - /// - /// input - /// output Tensor - Tensor NonZero(Tensor X); - - /// - /// ReLU - /// - /// input - /// output Tensor - Tensor Relu(Tensor x); - - /// - /// Softmax - /// - /// input - /// axis - /// output Tensor - Tensor Softmax(Tensor x, int axis=1); - - /// - /// LogSoftmax - /// - /// input - /// output Tensor - Tensor LogSoftmax(Tensor x, int axis=1); - - /// - /// Tanh - /// - /// input - /// output Tensor - Tensor Tanh(Tensor x); - - /// - /// Softplus - /// - /// input - /// output Tensor - Tensor Softplus(Tensor x); - - /// - /// Sigmoid - /// - /// input - /// output Tensor - Tensor Sigmoid(Tensor x); - - /// - /// HardSigmoid - /// - /// input - /// alpha - /// alpha - /// output Tensor - Tensor HardSigmoid(Tensor x, float alpha, float beta); - - /// - /// ELU - /// - /// input - /// alpha - /// output Tensor - Tensor Elu(Tensor x, float alpha); - - /// - /// ReLU capped to 6 - /// - /// input - /// output Tensor - Tensor Relu6(Tensor x); - - /// - /// Leaky ReLU - /// - /// input - /// alpha - /// output Tensor - Tensor LeakyRelu(Tensor x, float alpha); - - /// - /// SELU - /// - /// input - /// alpha - /// gamma - /// output Tensor - Tensor Selu(Tensor x, float alpha, float gamma); - - /// - /// PReLU - /// - /// input - /// alpha - /// output Tensor - Tensor PRelu(Tensor x, Tensor alpha); - - /// - /// Swish - /// - /// input - /// output Tensor - Tensor Swish(Tensor x); - - /// - /// Abs - /// - /// input - /// output Tensor - Tensor Abs(Tensor x); - - /// - /// Neg - /// - /// input - /// output Tensor - Tensor Neg(Tensor x); - - /// - /// Ceil - /// - /// input - /// output Tensor - Tensor Ceil(Tensor x); - - /// - /// Clip - /// - /// input - /// min value - /// max value - /// output Tensor - Tensor Clip(Tensor x, float min, float max); - - /// - /// Floor - /// - /// input - /// output Tensor - Tensor Floor(Tensor x); - - /// - /// Round to nearest integer. In case of halfs, round to nearest even integer - /// - /// input - /// output Tensor - Tensor Round(Tensor x); - - /// - /// Reciprocal (1/x) - /// - /// input - /// output Tensor - Tensor Reciprocal(Tensor x); - - /// - /// Power - /// - /// input - /// alpha - /// output Tensor - Tensor Pow(Tensor x, float alpha); - - /// - /// Exponent e^x - /// - /// input - /// output Tensor - Tensor Exp(Tensor x); - - /// - /// Log - /// - /// input - /// output Tensor - Tensor Log(Tensor x); - - /// - /// Sqrt - /// - /// input - /// output Tensor - Tensor Sqrt(Tensor x); - - /// - /// Acos - /// - /// input - /// output Tensor - Tensor Acos(Tensor x); - - /// - /// Acosh - /// - /// input - /// output Tensor - Tensor Acosh(Tensor x); - - /// - /// Asin - /// - /// input - /// output Tensor - Tensor Asin(Tensor x); - - /// - /// Asinh - /// - /// input - /// output Tensor - Tensor Asinh(Tensor x); - - /// - /// Atan - /// - /// input - /// output Tensor - Tensor Atan(Tensor x); - - /// - /// Atanh - /// - /// input - /// output Tensor - Tensor Atanh(Tensor x); - - /// - /// Cos - /// - /// input - /// output Tensor - Tensor Cos(Tensor x); - - /// - /// Cosh - /// - /// input - /// output Tensor - Tensor Cosh(Tensor x); - - /// - /// Sin - /// - /// input - /// output Tensor - Tensor Sin(Tensor x); - - /// - /// Sinh - /// - /// input - /// output Tensor - Tensor Sinh(Tensor x); - - /// - /// Tan - /// - /// input - /// output Tensor - Tensor Tan(Tensor x); - - /// - /// Erf - /// - /// input - /// output Tensor - Tensor Erf(Tensor x); - - /// - /// Add `tensors` together - /// - /// input tensors - /// output Tensor - Tensor Add(Tensor[] tensors); - - - /// - /// Subtract tensors o = tensors[0] - tensors[1] - ... - tensors[N-1] - /// - /// input tensors - /// output Tensor - Tensor Sub(Tensor[] tensors); - - /// - /// Multiply tensors together - /// - /// input tensors - /// output Tensor - Tensor Mul(Tensor[] tensors); - - /// - /// Divide tensors o = tensors[0] / tensors[1] / ... / tensors[N-1] - /// - /// input tensors - /// output Tensor - Tensor Div(Tensor[] tensors); - - /// - /// Raise tensors to the power o =tensors[0] ^ tensors[1] ^ ... ^ tensors[N-1] - /// - /// input tensors - /// output Tensor - Tensor Pow(Tensor[] tensors); - - /// - /// Min - /// - /// input tensors - /// output Tensor - Tensor Min(Tensor[] tensors); - - /// - /// Max - /// - /// input tensors - /// output Tensor - Tensor Max(Tensor[] tensors); - - /// - /// Mean - /// - /// input tensors - /// output Tensor - Tensor Mean(Tensor[] tensors); - - /// - /// Reduce with max - /// - /// input - /// axis - /// output Tensor - Tensor ReduceMax(Tensor x, int axis); - - /// - /// Reduce with mean - /// - /// input - /// axis - /// output Tensor - Tensor ReduceMean(Tensor x, int axis); - - /// - /// Reduce with min - /// - /// input - /// axis - /// output Tensor - Tensor ReduceMin(Tensor x, int axis); - - /// - /// Reduce with product - /// - /// input - /// axis - /// output Tensor - Tensor ReduceProd(Tensor x, int axis); - - /// - /// Reduce with sum - /// - /// input - /// axis - /// output Tensor - Tensor ReduceSum(Tensor x, int axis); - - /// - /// ArgMax - /// - /// input - /// axis - /// output Tensor - Tensor ArgMax(Tensor x, int axis); - - /// - /// ArgMax - /// - /// input - /// axis - /// output Tensor - Tensor ArgMin(Tensor x, int axis); - - /// - /// Greater - /// - /// left Tensor - /// right Tensor - /// Tensor with `true` where a > b - Tensor Greater(Tensor a, Tensor b); - - /// - /// Greater or equal - /// - /// left Tensor - /// right Tensor - /// Tensor with `true` where a >= b - Tensor GreaterEqual(Tensor a, Tensor b); - - /// - /// Less - /// - /// left Tensor - /// right Tensor - /// Tensor with `true` where a < b - Tensor Less(Tensor a, Tensor b); - - /// - /// Less or equal - /// - /// left Tensor - /// right Tensor - /// Tensor with `true` where a < b - Tensor LessEqual(Tensor a, Tensor b); - - /// - /// Equal - /// - /// left Tensor - /// right Tensor - /// Tensor with `true` where a == b - Tensor Equal(Tensor a, Tensor b); - - /// - /// Or - /// - /// left Tensor - /// right Tensor - /// Tensor with `true` where a || b - Tensor LogicalOr(Tensor a, Tensor b); - - /// - /// And - /// - /// left Tensor - /// right Tensor - /// Tensor with `true` where a && b - Tensor LogicalAnd(Tensor a, Tensor b); - - /// - /// Xor - /// - /// left Tensor - /// right Tensor - /// Tensor with `true` where a xor b - Tensor LogicalXor(Tensor a, Tensor b); - - /// - /// Not - /// - /// input - /// Tensor with !x values - Tensor LogicalNot(Tensor x); - - /// - /// Where - /// - /// Tensor c - /// Tensor a - /// Tensor b - /// Tensor with values `c` ? `a` : `b` - Tensor Where(Tensor c, Tensor a, Tensor b); - - /// - /// Sign - /// - /// input - /// Tensor with 1 if x > 0 -1 if < 0 and 0 if == 0 values - Tensor Sign(Tensor x); - - /// - /// Flatten - /// - /// input - /// output Tensor - Tensor Flatten(Tensor x); - - /// - /// Reshape - /// - /// input - /// new shape - /// output Tensor - Tensor Reshape(Tensor x, TensorShape shape); - - /// - /// Expand - /// - /// input - /// new shape - /// output Tensor - Tensor Expand(Tensor x, TensorShape shape); - - /// - /// Transpose matrix - /// - /// input - /// output Tensor - Tensor Transpose(Tensor x); - - /// - /// Transpose according to permutations - /// - /// input - /// new axis order - /// output Tensor - Tensor Transpose(Tensor x, int[] permutations); - - /// - /// Concatenate `tensors` across `axis` - /// - /// input tensors - /// axis - /// output Tensor - Tensor Concat(Tensor[] tensors, int axis); - - /// - /// Strided slice - /// - /// input - /// - /// - /// stride - /// output Tensor - Tensor StridedSlice(Tensor x, int[] starts4Dor8D, int[] ends4Dor8D, int[] strides4Dor8D); - - /// - /// Tile - /// - /// input - /// repetition counts - /// output Tensor - Tensor Tile(Tensor x, int[] repeats); - - /// - /// Gather - /// - /// input tensors - /// axis - /// output Tensor - Tensor Gather(Tensor[] tensors, int axis); - - /// - /// ScatterND - /// - /// input tensor - /// indices - /// updates - /// reduction mode - /// output Tensor - Tensor ScatterND(Tensor x, Tensor indices, Tensor updates, Layer.ScatterNDReductionMode reduction); - - /// - /// Non max suppression tensors[0] - boxes, tensors[1] - scores - /// - /// - /// max output boxes per class - /// IOU (Intersection Over Union) threshold - /// score threshold - /// center point box - /// output Tensor - Tensor NonMaxSuppression(Tensor[] tensors, int maxOutputBoxesPerClass, float iouThreshold, float scoreThreshold, int centerPointBox); - - /// - /// LSTM - /// - /// The input sequences packed into one 3-D tensor. - /// W parameter weight matrix for input, output, forget, and cell gates - W[iofc] - /// R recurrence weight matrix for input, output, forget, and cell gates - R[iofc] - /// W bias vectors for input, output, forget, and cell gates - Wb[iofc] - /// R bias vectors for input, output, forget, and cell gates - Rb[iofc] - /// Initial value of the hidden - /// Initial value of the cell - /// [Y (concatenated intermediate values of the hidden), Y_h (final hidden), Y_c (final cell)] - Tensor[] LSTM(Tensor X, Tensor[] W, Tensor[] R, Tensor[] Wb, Tensor[] Rb, Tensor hidden, Tensor cell); - - /// - /// Shape of the `input` - /// - /// input - /// axis - /// output Tensor - Tensor Shape(Tensor X, int axis = -1); - - /// - /// Creates a constant of shape `input` - /// - /// input shape - /// value - /// Tensor DataType - /// output Tensor - Tensor ConstantOfShape(TensorShape X, DataType type, float value = 0.0f); - - /// - /// Copy - /// - /// input - /// output Tensor - Tensor Copy(Tensor x); - - /// - /// Prepares tensor for use - /// - /// input - /// Tensor - Tensor Prepare(Tensor x); - - /// - /// Prepares tensor for use without uploading internal data to device - /// - /// input - /// Tensor - Tensor PrepareNoAlloc(Tensor x); - - /// - /// Reset internal allocator - /// - /// keep cached memory flag - void ResetAllocator(bool keepCachedMemory = true); - - /// - /// Called after every layer execution. It allows IOps to run cleanup operations - /// such as clearing temporary buffers only used in the scope of the last layer - /// executed. - /// - void PostLayerCleanup(); - - /// - /// Set model executions reporter - /// model executions reporter - /// - void SetModelExecutionsReporter(IModelExecutionsReporter executionsReporter); - - /// - /// Get model executions reporter - /// - /// model executions reporter - IModelExecutionsReporter GetModelExecutionsReporter(); -} - -/// -/// Interfaces for model compiler -/// -internal interface IModelCompiler -{ - /// - /// Prepare model for execution, allocating required intermediate tensors - /// - /// model - /// input shapes - /// model variables - void PrepareModel(Model model, IDictionary inputShapes, IVars vars); - - /// - /// Prepare for layer execution - /// - /// layer - /// inputs - void PreExecuteLayer(Layer layer, Tensor[] inputs); -} - -/// -/// Interfaces for variables -/// -public interface IVars : IDisposable -{ - /// - /// Set input - /// - /// name - /// input - void SetInput(string name, Tensor x); - - /// - /// Prepare storage - /// - /// model - /// `IOps` to prepare tensors - /// input shapes dictionary - /// takeoverWeights flag - /// expect activation data type - void PrepareStorage(Model model, IOps optionalOpsToPrepareTensors = null, IDictionary optionalInputShapes = null, bool takeoverWeights = false, DataType dataType = DataType.Float); - - /// - /// Gather layer inputs - /// - /// layer - /// all input tensors - Tensor[] GatherInputs(Layer forLayer); - - /// - /// Prepare storage for layer - /// - /// layer - void PrepareStorage(Layer forLayer); - - /// - /// Dispose storage that can be deleted after layer - /// - /// layer - void DisposeAfterLayer(Layer forLayer); - - /// - /// Store `result` for layer - /// - /// layer - /// Tensor to store - void Store(Layer fromLayer, Tensor result); - - /// - /// Peek output - /// - /// name - /// Tensor - Tensor PeekOutput(string name); - - /// - /// Peek constants - /// - /// layer name - /// Tensor array - Tensor[] PeekConstants(string layerName); - - /// - /// Get allocator - /// - /// current `ITensorAllocator` - ITensorAllocator GetAllocator(); -} - -/// -/// High level model execution peak memory usage information -/// -public readonly struct MemoryPeakSummary -{ - private readonly long PeakMemoryUsageGPU; - private readonly long PeakMemoryUsageCPU; - private readonly long PeakMemoryUsageGPUAndCPU; - - public MemoryPeakSummary(long peakMemoryUsageGPU, long peakMemoryUsageCPU, long peakMemoryUsageGPUAndCPU) - { - PeakMemoryUsageGPU = peakMemoryUsageGPU; - PeakMemoryUsageCPU = peakMemoryUsageCPU; - PeakMemoryUsageGPUAndCPU = peakMemoryUsageGPUAndCPU; - } - - public override string ToString() - { - return $"GPU: {PeakMemoryUsageGPU:N0} / CPU: {PeakMemoryUsageCPU:N0} / GPU and CPU: {PeakMemoryUsageGPUAndCPU:N0}."; - } -} - -/// -/// Interfaces for model execution reporter -/// -public interface IModelExecutionsReporter -{ -#if ENABLE_BARRACUDA_STATS - /// - /// Mark the model execution as started - /// - void ModelExecutionStarted(); - - /// - /// Mark the model execution as completed - /// - void ModelExecutionCompleted(); - - /// - /// Mark a layer execution as started - /// layer - /// - void LayerExecutionStarted(Layer layer); - - /// - /// Mark a layer execution as completed - /// - void LayerExecutionCompleted(); - - /// - /// Set a layer operation summary - /// layer summary - /// - void SetLayerSummary(string message); - - /// - /// Set a layer theoretical numbers of ALU and memory bandwidth - /// number of theoretical ALU operations - /// number of theoretical bandwidth in bytes - /// - void SetLayerALUAndMemStats(long alu, long bytes); - - /// - /// Add a dispatch to current layer - /// dispatch information - /// - void AddLayerDispatch(DispatchInfo dispatchInfo); - - /// - /// Take a memory snapshot - /// IVars containing memory information - /// context of the snapshot - /// optional layer of the snapshot - /// - void TakeMemorySnapshot(IOps ops, IVars vars, string context, Layer layer=null); - - /// - /// Return a string representation of the executions tracked so far - /// as well as a quick summary of peak memory usage. - /// if true report will be formatted as a spreadSheet. - /// - string GenerateStringReport(out MemoryPeakSummary memoryPeakSummary, bool spreadSheetFormat); -#endif //ENABLE_BARRACUDA_STATS -} - - -public interface IUniqueResource -{ -#if ENABLE_BARRACUDA_STATS - /// - /// Returns a unique id for identification. - /// - int uniqueId { get; } -#endif //ENABLE_BARRACUDA_STATS -} - -public interface ITensorDataStatistics : IUniqueResource -{ - /// - /// Returns the maximum number of element this tensorData can contain. - /// - int maxCapacity { get; } - /// - /// Returns the type of the elements this tensorData can contain. - /// - DataType dataType { get; } -#if ENABLE_BARRACUDA_STATS - /// - /// Returns true if this tensor data is attached to any tensor. - /// - bool inUse { get; } - - /// - /// Returns true if this tensor data is reserved as GPU memory. - /// - bool isGPUMem { get; } -#endif //ENABLE_BARRACUDA_STATS -} - -#if ENABLE_BARRACUDA_STATS -public struct TempMemoryStatistics : IUniqueResource -{ - - public TempMemoryStatistics(int uniqueId, int size, bool isGPUMem, string name) - { - this.uniqueId = uniqueId; - this.size = size; - this.isGPUMem = isGPUMem; - this.name = name; - } - - /// - public int uniqueId { get; } - - /// - /// Returns the capacity in byte of this temp memory. - /// - public int size { get; } - - /// - /// Returns true if this temporary memory is reserved as GPU memory. - /// - public bool isGPUMem { get; } - - /// - /// Returns name associated with this temp memory. - /// - public string name { get; } -} -#endif //ENABLE_BARRACUDA_STATS - -public interface IOpsStatistics -{ -#if ENABLE_BARRACUDA_STATS - /// - /// Enumerator for temporary memory statistics. - /// - IEnumerable GetTempMemoryStatistics(); -#endif //ENABLE_BARRACUDA_STATS -} - -public interface ITensorStatistics: IUniqueResource -{ - /// - /// Return this tensor name. - /// - string name { get; } - - /// - /// Return the shape of this tensor. - /// - TensorShape shape { get; } - - /// - /// Return the data type of this tensor. - /// - DataType dataType { get; } - - /// - /// Return amount of internal tensor cache in bytes. - /// - int cacheBytes { get; } - - /// - /// Return this tensor tensor data statistics if any or null. - /// - ITensorDataStatistics GetTensorDataStatistics(); -} - -public interface IAllocatorStatistics: IUniqueResource -{ -#if ENABLE_BARRACUDA_STATS - /// - /// Return this allocator name. - /// - string name { get; } - - /// - /// Used bytes (sum of the parts of the tensorData used by tensors) - /// - long usedBytes { get; } - - /// - /// Busy bytes (sum of used tensorData capacities in bytes) - /// - long busyBytes { get; } - - /// - /// Free bytes (sum of un-used tensorData capacities in bytes) - /// - long freeBytes { get; } - - /// - /// Total bytes (busy + free) - /// - long totalBytes { get; } - - /// - /// Enumerator for tensors statistics. - /// - IEnumerable GetTensorsStatistics(); - - /// - /// Enumerator for tensors data statistics. - /// - IEnumerable GetTensorDatasStatistics(); -#endif //ENABLE_BARRACUDA_STATS -} - -public interface IVarsStatistics -{ -#if ENABLE_BARRACUDA_STATS - /// - /// Enumerator for allocators statistics. - /// - IEnumerable GetAllocatorsStatistics(); - - /// - /// Enumerator for tensors statistics. - /// - IEnumerable GetTensorsStatistics(); -#endif //ENABLE_BARRACUDA_STATS -} - -/// -/// Enum to describe life time of a given allocation -/// -public enum AllocScope -{ - LayerOutput, - InternalToLayer -} - -/// -/// Interfaces for tensor allocator -/// -public interface ITensorAllocator : IDisposable -{ - /// - /// Allocate - /// - /// shape - /// tensor lifetime scope - /// tensor data type - /// allocated Tensor - Tensor Alloc(TensorShape shape, AllocScope scope = AllocScope.LayerOutput, DataType dataType = DataType.Float); - - /// - /// Allocate with existing `ITensorData` buffer - /// - /// shape - /// buffer - /// tensor lifetime scope - /// allocated Tensor - Tensor Alloc(TensorShape shape, ITensorData buffer, AllocScope scope = AllocScope.LayerOutput, DataType dataType = DataType.Float); - - /// - /// Allows ITensorAllocator to run cleanup operations such as clearing - /// temporary buffers only used in the scope of the last layer executed. - /// - void PostLayerCleanup(); - - // MoveToDevice() callback is called from the following Tensor methods: - // UploadToDevice(), AttachToDevice() and DetachFromDevice() - /// - /// Move Tensor to device - /// - /// Tensor - /// new buffer - /// old buffer - /// dispose detached buffer hint - void MoveToDevice(Tensor x, ITensorData newBuffer, ITensorData oldBuffer, bool disposeDetachedBufferHint); - - // NOTE: Release() should be ready to handle edge-case situation when - // externally created new Tensor instance is passed with - // ITensorData (tensorOnDevice) that is already owned by the allocator - /// - /// Release Tensor - /// - /// Tensor - /// called from tensor dispose flag - void Release(Tensor x, bool calledFromTensorDispose); - - /// - /// Waive ownership - /// - /// Tensor - void WaiveOwnership(Tensor x); - - /// - /// Reset allocator - /// - /// keep cached memory flag - void Reset(bool keepCachedMemory); // end-of-frame -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackends.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackends.cs.meta deleted file mode 100644 index cb5b450..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackends.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 67f00a1befd4144eca5685250d893f09 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackendsFactory.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackendsFactory.cs deleted file mode 100644 index d9a3fb5..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackendsFactory.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; // ToList() -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda { - - -internal class BarracudaBackendsFactory -{ - public static WorkerFactory.Type ResolveAutoType(WorkerFactory.Type type) - { - if (type != WorkerFactory.Type.Auto) - return type; - return GetBestTypeForDevice(WorkerFactory.Device.Auto); - } - - internal static WorkerFactory.Type GetBestTypeForDevice(WorkerFactory.Device device) - { - switch (device) - { - case WorkerFactory.Device.Auto: - case WorkerFactory.Device.GPU: - return WorkerFactory.Type.ComputePrecompiled; - default: - return WorkerFactory.Type.CSharpBurst; - } - } - - internal static WorkerFactory.Type ValidateType(WorkerFactory.Type type) - { - type = ResolveAutoType(type); - Assert.AreNotEqual(type, WorkerFactory.Type.Auto); - - if (WorkerFactory.IsType(type, WorkerFactory.Device.GPU) && !ComputeShaderSingleton.Instance.supported) - { - type = WorkerFactory.Type.PixelShader; - } - - return type; - } - - private static IOps CreateOps(WorkerFactory.Type type, ITensorAllocator allocator, bool verbose) - { - switch(type) - { - case WorkerFactory.Type.ComputePrecompiled: - return new PrecompiledComputeOps(allocator, verbose); - - case WorkerFactory.Type.Compute: - return new ComputeOps(allocator, verbose); - - case WorkerFactory.Type.ComputeRef: - return new ReferenceComputeOps(allocator); - - case WorkerFactory.Type.PixelShader: - return new PixelShaderOps(allocator); - - case WorkerFactory.Type.CSharpBurst: - return new BurstCPUOps(allocator); - - case WorkerFactory.Type.CSharp: - return new UnsafeArrayCPUOps(allocator); - - default: - return new ReferenceCPUOps(allocator); - } - } - - internal static IWorker CreateWorker(WorkerFactory.Type type, Model model, string[] additionalOutputs, string[] trimOutputs, WorkerFactory.WorkerConfiguration workerConfiguration, IModelExecutionsReporter modelExecutionsReporter = null) - { - type = ResolveAutoType(type); - var compareAgainstType = ResolveAutoType(workerConfiguration.compareAgainstType); - Assert.AreNotEqual(type, WorkerFactory.Type.Auto); - Assert.AreNotEqual(compareAgainstType, WorkerFactory.Type.Auto); - - bool compare = type != compareAgainstType; - - if (WorkerFactory.IsType(type, WorkerFactory.Device.GPU) && !SystemInfo.supportsComputeShaders && !Application.isEditor) - { - type = WorkerFactory.Type.PixelShader; - } - - IVars vars; - // PixelShader worker uses Blit/Textures, cannot re-use vars unless the dispatch mechanism allows rendering to sub part of the texture - if ((type == WorkerFactory.Type.PixelShader) || (compareAgainstType == WorkerFactory.Type.PixelShader)) - vars = new GenericVarsWithReuse(); - else - { - if (WorkerFactory.IsType(type, WorkerFactory.Device.GPU) || WorkerFactory.IsType(compareAgainstType, WorkerFactory.Device.GPU)) - vars = new ComputeVarsWithSharedModel(); - else - vars = new DefaultVars(); - } - - ITensorAllocator allocator = vars.GetAllocator(); - if ((type == WorkerFactory.Type.PixelShader) || (compareAgainstType == WorkerFactory.Type.PixelShader)) - allocator = new TensorCachingByShapeAllocator(); - - if (workerConfiguration.verbose) - D.Log($"Storage type: {vars.GetType()}. Allocator type: {allocator.GetType()}."); - - IOps ops = CreateOps(type, allocator, workerConfiguration.verbose); - - if (compare) - ops = new CompareOps(ops, - CreateOps(compareAgainstType, allocator, workerConfiguration.verbose), workerConfiguration.compareLogLevel, workerConfiguration.compareEpsilon); - - if (workerConfiguration.verbose || modelExecutionsReporter != null) - ops = new VerboseOps(ops, workerConfiguration.verbose); - - if (Application.isEditor || modelExecutionsReporter != null) - ops = new StatsOps(ops); - - model = ValidateModel( - PatchModel(model, additionalOutputs, trimOutputs)); - - ops.SetModelExecutionsReporter(modelExecutionsReporter); - return new GenericWorker(model, ops, vars, workerConfiguration.verbose, workerConfiguration.takeoverWeights); - } - - internal static Model PatchModel(Model model, string[] additionalOutputs, string[] trimOutputs = null) - { - bool trimModel = trimOutputs != null; - - if (trimOutputs != null) - { - foreach (var o in trimOutputs.Except(model.outputs)) - if (additionalOutputs == null || !additionalOutputs.Contains(o)) - D.LogWarning($"Output specified in trimOutputs was not found in the model: {o}"); - - var newModel = model.ShallowCopy(); - newModel.outputs = trimOutputs.Intersect(model.outputs).ToList(); - model = newModel; - } - - if (additionalOutputs != null) - { - foreach (var o in additionalOutputs.Except(model.layers.Select(l => l.name))) - D.LogWarning($"Layer specified in additionalOutputs was not found in the model: {o}"); - - // 'new' means that output name does not yet exist in model.outputs - // 'valid' means that output name matches one of the existing model.layer names - var newAndValidAdditionalOutputs = - additionalOutputs.Except(model.outputs).Intersect(model.layers.Select(l => l.name)); - - var newModel = model.ShallowCopy(); - newModel.outputs.AddRange(newAndValidAdditionalOutputs); - model = newModel; - } - - if (trimModel) - { - var newModel = model.ShallowCopy(); - var upstream = ModelAnalyzer.FindUpstreamLayers(model, newModel.outputs.ToArray()); - foreach (var l in model.layers) - if (!upstream.Contains(l)) - newModel.layers.Remove(l); - - model = newModel; - } - - model = ModelOptimizer.RemoveNoop(model); - - return model; - } - - internal static Model ValidateModel(Model model) - { - // validate, model contains no broken links - var brokenLinks = ModelAnalyzer.FindBrokenLinks(model); - if (brokenLinks.Length > 0) - D.LogWarning($"Model contains {brokenLinks.Length} broken links: {string.Join(",", brokenLinks)}"); - - // validate, all model outputs are unique - // https://stackoverflow.com/questions/18547354/c-sharp-linq-find-duplicates-in-list - var duplicateOutputs = model.outputs.GroupBy(x => x) - .Where(g => g.Count() > 1) - .Select(y => y.Key); - foreach (var o in duplicateOutputs) - D.LogWarning($"Output is specified more than once in the model: {o}"); - - // validate, model contains no unconnected layers - var unconnectedOutputs = ModelAnalyzer.FindUnconnectedOutputs(model); - foreach (var o in unconnectedOutputs) - D.LogWarning($"Layer is specified as output, but is missing in the model: {o}"); - - return model; - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackendsFactory.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackendsFactory.cs.meta deleted file mode 100644 index 7a045f5..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBackendsFactory.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 355dc370391814b1c874848bb843b91c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Core.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Core.cs deleted file mode 100644 index eea6fac..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Core.cs +++ /dev/null @@ -1,245 +0,0 @@ -using System.Threading; -using UnityEngine; -using Unity.Jobs; - -namespace Unity.Barracuda { - -// BarracudaBurstCPU.Core.cs -- definition of class BurstCPUOps, Pin(), BurstTensorData -// BarracudaBurstCPU.Ops.cs -- impl. IOps, job schedulers -// BarracudaBurstCPU.Jobs.cs -- impl. jobs - -/// -/// Burst specific internal `Tensor` data storage -/// -public class BurstTensorData : UnsafeArrayTensorData, IDependableTensorData -{ - private JobHandle m_ReadFence; - private JobHandle m_WriteFence; - private bool m_SafeToDispose = true; - - /// - public JobHandle fence { get { return m_ReadFence; } set { m_ReadFence = value; m_WriteFence = value; m_SafeToDispose = false; } } - - /// - public JobHandle reuse { get { return m_WriteFence; } set { m_WriteFence = BurstCPUOps.Dependencies(value, m_WriteFence); m_SafeToDispose = false; } } - - /// - public unsafe void* rawPtr => array.RawAddressAt(offset); - - /// - /// Creates new array - /// - /// count - public BurstTensorData(int count, DataType dataType) : base(count, dataType) - { - } - - /// - /// Creates new array - /// - /// shape - public BurstTensorData(TensorShape shape, DataType dataType) : base(shape, dataType) - { - } - - /// - /// Uses shared array - /// - /// shared array - public BurstTensorData(ArrayTensorData sharedArray) : base(sharedArray) - { - } - - /// - /// Uses shared array - /// - /// shared array - public BurstTensorData(SharedArrayTensorData sharedArray) : base(sharedArray) - { - } - - /// - /// Uses unsafe array - /// - /// unsafe array - public BurstTensorData(UnsafeArrayTensorData unsafeArray) : base(unsafeArray.array, unsafeArray.offset, unsafeArray.count, unsafeArray.m_Readonly) - { - } - - /// - /// Finalizer - /// - ~BurstTensorData() - { - if (!m_SafeToDispose) - D.LogWarning($"Found unreferenced, but undisposed Tensor data that potentially participates in an unfinished job and might lead to hazardous memory overwrites: {ToString()}"); - } - - /// - /// Dispose contents - /// - public override void Dispose() - { - // It isn't safe to Complete jobs from a finalizer thread, so - if (Thread.CurrentThread == BurstCPUOps.MainThread) - CompleteAllPendingOperations(); - - base.Dispose(); - } - - internal void CompleteAllPendingOperations() - { - fence.Complete(); - reuse.Complete(); - m_SafeToDispose = true; - } - - /// - /// Reserve (allocate) storage for `count` elements - /// - /// count - public override void Reserve(int count) - { - if (count > maxCapacity) - { - // going to reallocate memory in base.Reserve() - // thus need to finish current work - CompleteAllPendingOperations(); - } - - base.Reserve(count); - } - - /// - /// Upload data to internal storage - /// - /// data - /// shape - /// `data` start index - public override void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0) - { - CompleteAllPendingOperations(); - base.Upload(data, shape, managedBufferStartIndex); - } - - /// - /// Return data from internal storage - /// - /// shape - /// managed array - public override float[] Download(TensorShape shape) - { - // Download() as optimization gives direct access to the internal buffer - // thus need to prepare internal buffer for potential writes - CompleteAllPendingOperations(); - return base.Download(shape); - } - - /// - /// Return shared array from internal storage - /// - /// shared array from internal storage - public override BarracudaArray SharedAccess(out int offset) - { - // SharedAccess() by design gives direct access to the interna - // thus need to prepare internal buffer for potential writes - CompleteAllPendingOperations(); - return base.SharedAccess(out offset); - } - - /// - /// Schedule async internal data download - /// - /// count to download - /// `true` if download is completed - public override bool ScheduleAsyncDownload(int count) - { - return fence.IsCompleted; - } - - /// - /// Object summary as string - /// - /// object summary - public override string ToString() - { - string readyToRead = m_SafeToDispose ? "true": "unknown"; - string readyForReuse = m_SafeToDispose ? "true": "unknown"; - try - { - readyToRead = fence.IsCompleted.ToString(); - readyForReuse = reuse.IsCompleted.ToString(); - } - catch (UnityException) {} - return string.Format("(CPU burst: {0} length: {1} offset: {2} uploaded: {3} ready-to-read: {4} ready-for-reuse: {5})", - GetHashCode(), m_Array?.Length, m_Offset, m_Count, readyToRead, readyForReuse); - } -} - -/// -/// Burst specific implementation of `IOps` -/// -public partial class BurstCPUOps : UnsafeArrayCPUOps -{ - /// - /// Create `BurstCPUOps` - /// - /// allocator - public BurstCPUOps(ITensorAllocator allocator = null) - : base(allocator) - { - if (PreferBLAS == BLAS.Native && !blas.IsNative()) - PreferBLAS = BLAS.Disabled; - } - - /// - /// Pin `Tensor` to Burst backend device, if `uploadCache` is false, data is not uploaded to device - /// - /// `Tensor` - /// `bool` - /// `BurstTensorData` - new public static BurstTensorData Pin(Tensor X, bool uploadCache = true) - { - X.FlushCache(uploadCache); - - var onDevice = X.tensorOnDevice as BurstTensorData; - if (onDevice == null) - { - // try to adopt CPU arrays - var asUnsafeArray = X.tensorOnDevice as UnsafeArrayTensorData; - var asSharedArray = X.tensorOnDevice as SharedArrayTensorData; - var asArray = X.tensorOnDevice as ArrayTensorData; - if (asUnsafeArray != null) X.AttachToDevice(new BurstTensorData(asUnsafeArray)); - else if (asSharedArray != null) X.AttachToDevice(new BurstTensorData(asSharedArray)); - else if (asArray != null) X.AttachToDevice(new BurstTensorData(asArray)); - else - { - if (uploadCache) - X.UploadToDevice(new BurstTensorData(X.shape, X.dataType)); // device is not compatible, create new array and upload - else - X.AllocateOnDevice(new BurstTensorData(X.shape, X.dataType)); // device is not compatible, create new array but do not upload - } - } - - return X.tensorOnDevice as BurstTensorData; - } - - /// - /// Prepare `Tensor` for use with Burst backend - /// - /// `Tensor` - /// `Tensor` - public override Tensor Prepare(Tensor X) - { - Pin(X); - return X; - } - - public override Tensor PrepareNoAlloc(Tensor X) - { - Pin(X, uploadCache: false); - return X; - } -} - -} // namespace Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Core.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Core.cs.meta deleted file mode 100644 index 6cb2eb1..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Core.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f44c1c453c1754aaeb1e8608df82452b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Helper.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Helper.cs deleted file mode 100644 index 0341a3b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Helper.cs +++ /dev/null @@ -1,471 +0,0 @@ -using UnityEngine; -using UnityEngine.Assertions; -using System; -using System.Collections.Generic; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs; -using Unity.Mathematics; - -namespace Unity.Barracuda { - -//#region Job output context helper - -internal static class BurstSchedulingHelper -{ - #region Private scheduling helpers with pointer aliasing verification - - private static unsafe JobHandle ScheduleXSBOInternal(T jobData, - JobHandle fenceBeforeJobStart, - void* ptrX, - void* ptrS, - void* ptrB, - void* ptrO, - int arrayLength, int innerloopBatchCount) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationXSBO - { - T jobDataInternalCopy = jobData; - jobDataInternalCopy.X = new BurstCPUOps.ReadOnlyMemResource() {ptr = ptrX}; - jobDataInternalCopy.S = new BurstCPUOps.ReadOnlyMemResource() {ptr = ptrS}; - jobDataInternalCopy.B = new BurstCPUOps.ReadOnlyMemResource() {ptr = ptrB}; - jobDataInternalCopy.O = new BurstCPUOps.ReadWriteMemResource() {ptr = ptrO}; - return jobDataInternalCopy.Schedule(arrayLength, innerloopBatchCount, fenceBeforeJobStart); - } - - private static unsafe JobHandle ScheduleXBOInternal(T jobData, - JobHandle fenceBeforeJobStart, - void* ptrX, - void* ptrB, - void* ptrO, - int arrayLength, int innerloopBatchCount) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationXBO - { - T jobDataInternalCopy = jobData; - jobDataInternalCopy.X = new BurstCPUOps.ReadOnlyMemResource() {ptr = ptrX}; - jobDataInternalCopy.B = new BurstCPUOps.ReadOnlyMemResource() {ptr = ptrB}; - jobDataInternalCopy.O = new BurstCPUOps.ReadWriteMemResource() {ptr = ptrO}; - return jobDataInternalCopy.Schedule(arrayLength, innerloopBatchCount, fenceBeforeJobStart); - } - - private static unsafe JobHandle ScheduleXOInternal(T jobData, - JobHandle fenceBeforeJobStart, - void* ptrX, - void* ptrO, - int arrayLength, int innerloopBatchCount) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationXO - { - T jobDataInternalCopy = jobData; - jobDataInternalCopy.X = new BurstCPUOps.ReadOnlyMemResource() {ptr = ptrX}; - jobDataInternalCopy.O = new BurstCPUOps.ReadWriteMemResource() {ptr = ptrO}; - return jobDataInternalCopy.Schedule(arrayLength, innerloopBatchCount, fenceBeforeJobStart); - } - - private static unsafe JobHandle ScheduleXOInternal(T jobData, - JobHandle fenceBeforeJobStart, - void* ptrX, - void* ptrO) - where T : struct, IJob, BurstCPUOps.IJobResourceDeclarationXO - { - Assert.IsTrue(ptrO != ptrX); - T jobDataInternalCopy = jobData; - jobDataInternalCopy.X = new BurstCPUOps.ReadOnlyMemResource() {ptr = ptrX}; - jobDataInternalCopy.O = new BurstCPUOps.ReadWriteMemResource() {ptr = ptrO}; - return jobDataInternalCopy.Schedule(fenceBeforeJobStart); - } - - private static unsafe JobHandle ScheduleOInternal(T jobData, - JobHandle fenceBeforeJobStart, - void* ptrO) - where T : struct, IJob, BurstCPUOps.IJobResourceDeclarationO - { - T jobDataInternalCopy = jobData; - jobDataInternalCopy.O = new BurstCPUOps.ReadWriteMemResource() {ptr = ptrO}; - return jobDataInternalCopy.Schedule(fenceBeforeJobStart); - } - - private static unsafe JobHandle ScheduleOInternal(T jobData, - JobHandle fenceBeforeJobStart, - void* ptrO, - int arrayLength, int innerloopBatchCount) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationO - { - T jobDataInternalCopy = jobData; - jobDataInternalCopy.O = new BurstCPUOps.ReadWriteMemResource() {ptr = ptrO}; - return jobDataInternalCopy.Schedule(arrayLength, innerloopBatchCount, fenceBeforeJobStart); - } - - #endregion - - #region Private fencing helper for readability - private static JobHandle GetFenceBeforeJobStartXSBO( - IDependableMemoryResource pinX, - IDependableMemoryResource pinS, - IDependableMemoryResource pinB, - IDependableMemoryResource pinO) - { - return BurstCPUOps.Dependencies(pinX.fence, pinS.fence, pinB.fence, pinO.reuse); - } - - private static JobHandle GetFenceBeforeJobStartXBO( - IDependableMemoryResource pinX, - IDependableMemoryResource pinB, - IDependableMemoryResource pinO) - { - return BurstCPUOps.Dependencies(pinX.fence, pinB.fence, pinO.reuse); - } - - private static JobHandle GetFenceBeforeJobStartXO( - IDependableMemoryResource pinX, - IDependableMemoryResource pinO) - { - return BurstCPUOps.Dependencies(pinX.fence, pinO.reuse); - } - - private static void SetXSBOFences(this JobHandle jobFence, - IDependableMemoryResource pinX, - IDependableMemoryResource pinS, - IDependableMemoryResource pinB, - IDependableMemoryResource pinO) - { - pinX.reuse = jobFence; - pinS.reuse = jobFence; - pinB.reuse = jobFence; - pinO.fence = jobFence; - } - - private static void SetXBOFences(this JobHandle jobFence, - IDependableMemoryResource pinX, - IDependableMemoryResource pinB, - IDependableMemoryResource pinO) - { - pinX.reuse = jobFence; - pinB.reuse = jobFence; - pinO.fence = jobFence; - } - - private static void SetXOFences(this JobHandle jobFence, - IDependableMemoryResource pinX, - IDependableMemoryResource pinO) - { - pinX.reuse = jobFence; - pinO.fence = jobFence; - } - #endregion - - #region Immediate scheduling helper - internal enum FencingHelperMode - { - UpdateResourcesFencesOnScheduling, - CustomResourcesFencesHandling, - } - - internal static unsafe JobHandle ScheduleXSBO(this T jobData, - IDependableMemoryResource rX, - IDependableMemoryResource rS, - IDependableMemoryResource rB, - IDependableMemoryResource rO, - int arrayLength, int innerloopBatchCount, - FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationXSBO - { - var fenceBeforeJobStart = GetFenceBeforeJobStartXSBO(rX, rS, rB, rO); - - JobHandle jobFence; - { - jobFence = ScheduleXSBOInternal(jobData, fenceBeforeJobStart, rX.rawPtr, rS.rawPtr, rB.rawPtr, rO.rawPtr, arrayLength, innerloopBatchCount); - } - - if (fencingMode==FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - jobFence.SetXSBOFences(rX, rS, rB, rO); - } - - return jobFence; - } - - internal static unsafe JobHandle ScheduleXBO(this T jobData, - IDependableMemoryResource X, - IDependableMemoryResource B, - IDependableMemoryResource O, - int arrayLength, int innerloopBatchCount, - FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationXBO - { - var fenceBeforeJobStart = GetFenceBeforeJobStartXBO(X, B, O); - - JobHandle jobFence; - { - jobFence = ScheduleXBOInternal(jobData, fenceBeforeJobStart, X.rawPtr, B.rawPtr, O.rawPtr, arrayLength, innerloopBatchCount); - } - - if (fencingMode==FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - jobFence.SetXBOFences(X, B, O); - } - - return jobFence; - } - - internal static unsafe JobHandle ScheduleO(this T jobData, - IDependableMemoryResource O, - FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - where T : struct, IJob, BurstCPUOps.IJobResourceDeclarationO - { - var fenceBeforeJobStart = O.reuse; - - JobHandle jobFence; - { - jobFence = ScheduleOInternal(jobData, fenceBeforeJobStart, O.rawPtr); - } - - if (fencingMode==FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - O.fence = jobFence; - } - - return jobFence; - } - - internal static unsafe JobHandle ScheduleXO(this T jobData, - IDependableMemoryResource X, - IDependableMemoryResource O, - int arrayLength, int innerloopBatchCount, - FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationXO - { - var fenceBeforeJobStart = GetFenceBeforeJobStartXO(X, O); - - JobHandle jobFence; - { - jobFence = ScheduleXOInternal(jobData, fenceBeforeJobStart, X.rawPtr, O.rawPtr, arrayLength, innerloopBatchCount); - } - - if (fencingMode==FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - jobFence.SetXOFences(X, O); - } - - return jobFence; - } - - internal static unsafe JobHandle ScheduleO(this T jobData, - BurstTensorData pinO, - int offsetO, - int arrayLength, int innerloopBatchCount, - FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationO - { - var fenceBeforeJobStart = pinO.reuse; - - JobHandle jobFence; - { - void* ptrO = pinO.array.RawAddressAt(pinO.offset+offsetO); - jobFence = ScheduleOInternal(jobData, fenceBeforeJobStart, ptrO, arrayLength, innerloopBatchCount); - } - - if (fencingMode==FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - pinO.fence = jobFence; - } - - return jobFence; - } - - internal static unsafe JobHandle ScheduleXO(this T jobData, - BurstTensorData pinX, - int offsetX, - BurstTensorData pinO, - int offsetO, - FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - where T : struct, IJob, BurstCPUOps.IJobResourceDeclarationXO - { - var fenceBeforeJobStart = GetFenceBeforeJobStartXO(pinX, pinO); - - JobHandle jobFence; - { - void* ptrX = pinX.array.RawAddressAt(pinX.offset+offsetX); - void* ptrO = pinO.array.RawAddressAt(pinO.offset+offsetO); - jobFence = ScheduleXOInternal(jobData, fenceBeforeJobStart, ptrX, ptrO); - } - - if (fencingMode==FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - jobFence.SetXOFences(pinX, pinO); - } - - return jobFence; - } - - internal static unsafe JobHandle ScheduleXO(this T jobData, - IDependableMemoryResource X, - IDependableMemoryResource O, - FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - where T : struct, IJob, BurstCPUOps.IJobResourceDeclarationXO - { - var fenceBeforeJobStart = GetFenceBeforeJobStartXO(X, O); - - JobHandle jobFence; - { - jobFence = ScheduleXOInternal(jobData, fenceBeforeJobStart, X.rawPtr, O.rawPtr); - } - - if (fencingMode==FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - jobFence.SetXOFences(X, O); - } - - return jobFence; - } - - #endregion -} - -#region Schedulling helper for parrallel jobs - -internal struct ParallelJobsContext : IDisposable -{ - internal static Dictionary s_ReadDependencyTracker = - new Dictionary(100); - - private readonly IDependableMemoryResource outputResource; - private JobHandle combinedJobFence; - - public ParallelJobsContext(IDependableMemoryResource output) - { - outputResource = output; - combinedJobFence = new JobHandle(); - Assert.AreEqual(0, s_ReadDependencyTracker.Count, - "s_ReadDependencyTracker should be empty meaning ParrallelJobs was not disposed properly."); - } - - //For now only CopyStrideJobHelper and tests need ParallelJobsContext. If this code need to be duplicated for more case in the future: - //- Maybe add generic version by having CopyStrideJobHelper and other helper struct implement an interface (but beware of GC). - //- Or make ParallelJobsContext partial and code generated by jobs template. - public JobHandle ScheduleXO( - BurstCPUOps.CopyStrideJobHelper jobData,//See comment above. - BurstTensorData pinX, int offsetX, - BurstTensorData pinO, int offsetO) - { - Assert.IsTrue(pinO == outputResource); - var jobFence = jobData.ScheduleXO(pinX, offsetX, pinO, offsetO, BurstSchedulingHelper.FencingHelperMode.CustomResourcesFencesHandling); - TrackJobReadDependencies(pinX, jobFence); - AddJobDependencyToOutputFence(jobFence); - return jobFence; - } - - public JobHandle ScheduleXO( - T jobData, - BurstTensorData pinX, - BurstTensorData pinO, - int arrayLength, int innerloopBatchCount) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationXO - { - Assert.IsTrue(pinO == outputResource); - var jobFence = jobData.ScheduleXO(pinX, pinO, arrayLength, innerloopBatchCount, BurstSchedulingHelper.FencingHelperMode.CustomResourcesFencesHandling); - TrackJobReadDependencies(pinX, jobFence); - AddJobDependencyToOutputFence(jobFence); - return jobFence; - } - - - public JobHandle ScheduleXBO( - T jobData, - BurstTensorData pinX, - BurstTensorData pinB, - BurstTensorData pinO, - int arrayLength, int innerloopBatchCount) - where T : struct, IJobParallelFor, BurstCPUOps.IJobResourceDeclarationXBO - { - Assert.IsTrue(pinO == outputResource); - var jobFence = jobData.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerloopBatchCount, BurstSchedulingHelper.FencingHelperMode.CustomResourcesFencesHandling); - TrackJobReadDependencies(pinX, jobFence); - TrackJobReadDependencies(pinB, jobFence); - AddJobDependencyToOutputFence(jobFence); - return jobFence; - } - - internal void AddJobDependencyToOutputFence(JobHandle jobFence) - { - //Once all jobs writing to O will be done, further jobs will be able to read from O. - //We combine job fences from all job writing to O here and assign to O.fence in Dispose(). - combinedJobFence = JobHandle.CombineDependencies(combinedJobFence, jobFence); - } - - internal void TrackJobReadDependencies(IDependableMemoryResource T, JobHandle jobFence) - { - //Once all jobs reading from T will be done, further jobs will be able to write to T. - //We combine job fences from all jobs reading from T here and assign to T.reuse in Dispose(). - if (T != null) - { - if (s_ReadDependencyTracker.ContainsKey(T)) - s_ReadDependencyTracker[T] = JobHandle.CombineDependencies(s_ReadDependencyTracker[T], jobFence); - else - s_ReadDependencyTracker[T] = jobFence; - } - } - - public void Dispose() - { - foreach (var key in s_ReadDependencyTracker.Keys) - { - key.reuse = s_ReadDependencyTracker[key]; - } - outputResource.fence = combinedJobFence; - s_ReadDependencyTracker.Clear(); - } -} - -#endregion - -#region Memory allocation wrapper usable by job fencing helpers - -internal unsafe class FencedMemoryAlloc : IDependableMemoryResource -{ - private JobHandle m_ReadFence; - private JobHandle m_WriteFence; - private void* data; - public void* rawPtr => data; - public half* halfdata { get { Assert.AreEqual(DataType.Half, type); return (half*) data; } } - public float* floatdata { get { Assert.AreEqual(DataType.Float, type);return (float*) data; } } - public DataType type; - public int elementCount; - public int elementSize; - - /// - public JobHandle fence { get { return m_ReadFence; } set { m_ReadFence = value; m_WriteFence = value; } } - - /// - public JobHandle reuse { get { return m_WriteFence; } set { m_WriteFence = value; } } - - public void Allocate(int numElement, DataType dataType, int alignment, Allocator allocator) - { - m_ReadFence = new JobHandle(); - m_WriteFence = new JobHandle(); - elementCount = numElement; - elementSize = BarracudaArray.DataItemSize(dataType); - type = dataType; - Assert.IsTrue(data == null, "Please call ClearState() when freeing underlying memory."); - Assert.IsTrue(alignment % elementSize == 0); - data = UnsafeUtility.Malloc(elementCount * elementSize, alignment, allocator); - Assert.IsTrue(data != null); - } - - public void ClearState() - { - m_ReadFence = new JobHandle(); - m_WriteFence = new JobHandle(); - elementCount = 0; - elementSize = 0; - type = DataType.Float; - data = null; - } - - public FencedMemoryAlloc() - { - ClearState(); - } -} - -#endregion - -} // namespace Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Helper.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Helper.cs.meta deleted file mode 100644 index 20e8714..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Helper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5071bbeadb81d034f827f20e95c52ee6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Activation.gen.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Activation.gen.cs deleted file mode 100644 index 009f45f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Activation.gen.cs +++ /dev/null @@ -1,2012 +0,0 @@ -// This is auto-generated -- do not modify directly -using UnityEngine; -using System; -using Unity.Burst; -using Unity.Burst.Intrinsics; -using Unity.Collections; -using Unity.Jobs; -using Unity.Mathematics; -using static Unity.Burst.Intrinsics.X86.Avx; -using static Unity.Burst.Intrinsics.X86.Fma; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs.LowLevel.Unsafe; -using FencingHelperMode = Unity.Barracuda.BurstSchedulingHelper.FencingHelperMode; - -namespace Unity.Barracuda { -public partial class BurstCPUOps -{ - #region Activation jobs declaration for mode: _Full_Float - - internal partial struct ReluJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ReluJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ReluJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ReluJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ReluJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i]; - // NOTE: burst-1.2.3 has troubles with Math.Min/Max generating poorly vectorized and branch code - // Instead Math.Abs based code is used instead. (Math.Abs just flips 1 bit) - Optr[i] = (float)(0.5f * (v + math.abs(v))); - } - } - - internal partial struct Relu6JobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new Relu6Job_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new Relu6Job_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Relu6Job_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public Relu6JobHelper data; - - public void Execute(int i) - { - // f(x) = min(max(x, 0), 6) - // "Convolutional Deep Belief Networks on CIFAR-10", A Krizhevsky, 2010 - // http://www.cs.utoronto.ca/~kriz/conv-cifar10-aug2010.pdf - float v = Xptr[i]; - - // NOTE: burst-1.2.3 has troubles with Math.Min/Max generating poorly vectorized and branch code - // Instead Math.Abs based code is used instead. (Math.Abs just flips 1 bit) - Optr[i] = (float)(0.5f * (-math.abs(v - 6f) + math.abs(v) + 6f)); - } - } - - internal partial struct LeakyReluJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new LeakyReluJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new LeakyReluJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct LeakyReluJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public LeakyReluJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i]; - // NOTE: burst-1.2.3 has troubles with Math.Min/Max generating poorly vectorized and branch code - // Instead Math.Abs based code is used instead. (Math.Abs just flips 1 bit) - Optr[i] = (float)(data.f1 * v + data.f2 * math.abs(v)); - } - } - - internal partial struct TanhJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new TanhJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new TanhJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct TanhJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public TanhJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.tanh(x); - Optr[i] = (float)v; - } - } - internal partial struct SoftplusJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new SoftplusJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new SoftplusJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SoftplusJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SoftplusJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.log(math.exp(x) + 1f); - Optr[i] = (float)v; - } - } - internal partial struct SigmoidJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new SigmoidJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new SigmoidJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SigmoidJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SigmoidJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 1f / (1f + math.exp(-x)); - Optr[i] = (float)v; - } - } - internal partial struct AbsJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new AbsJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new AbsJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AbsJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public AbsJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = Math.Abs(x); - Optr[i] = (float)v; - } - } - internal partial struct NegJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new NegJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new NegJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct NegJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public NegJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = -x; - Optr[i] = (float)v; - } - } - internal partial struct CeilJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new CeilJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new CeilJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CeilJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public CeilJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.ceil(x); - Optr[i] = (float)v; - } - } - internal partial struct FloorJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new FloorJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new FloorJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct FloorJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public FloorJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.floor(x); - Optr[i] = (float)v; - } - } - internal partial struct RoundJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new RoundJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new RoundJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct RoundJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public RoundJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.round(x); - Optr[i] = (float)v; - } - } - internal partial struct ReciprocalJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ReciprocalJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ReciprocalJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ReciprocalJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ReciprocalJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 1.0f / x; - Optr[i] = (float)v; - } - } - internal partial struct ExpJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ExpJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ExpJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ExpJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ExpJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.exp(x); - Optr[i] = (float)v; - } - } - internal partial struct LogJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new LogJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new LogJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct LogJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public LogJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.log(x); - Optr[i] = (float)v; - } - } - internal partial struct SqrtJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new SqrtJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new SqrtJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SqrtJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SqrtJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.sqrt(x); - Optr[i] = (float)v; - } - } - internal partial struct AcosJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new AcosJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new AcosJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AcosJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public AcosJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.acos(x); - Optr[i] = (float)v; - } - } - internal partial struct AcoshJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new AcoshJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new AcoshJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AcoshJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public AcoshJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.log( x + math.sqrt(x*x - 1.0f)); - Optr[i] = (float)v; - } - } - internal partial struct AsinJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new AsinJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new AsinJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AsinJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public AsinJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.asin(x); - Optr[i] = (float)v; - } - } - internal partial struct AsinhJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new AsinhJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new AsinhJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AsinhJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public AsinhJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.log( x + math.sqrt(x*x + 1.0f)); - Optr[i] = (float)v; - } - } - internal partial struct AtanJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new AtanJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new AtanJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AtanJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public AtanJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.atan(x); - Optr[i] = (float)v; - } - } - internal partial struct AtanhJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new AtanhJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new AtanhJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AtanhJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public AtanhJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 0.5f * math.log((1.0f + x)/(1.0f - x)); - Optr[i] = (float)v; - } - } - internal partial struct CosJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new CosJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new CosJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CosJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public CosJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.cos(x); - Optr[i] = (float)v; - } - } - internal partial struct CoshJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new CoshJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new CoshJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CoshJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public CoshJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 0.5f * (math.exp(x) + math.exp(-x)); - Optr[i] = (float)v; - } - } - internal partial struct SinJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new SinJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new SinJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SinJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SinJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.sin(x); - Optr[i] = (float)v; - } - } - internal partial struct SinhJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new SinhJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new SinhJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SinhJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SinhJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 0.5f * (math.exp(x) - math.exp(-x)); - Optr[i] = (float)v; - } - } - internal partial struct TanJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new TanJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new TanJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct TanJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public TanJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.tan(x); - Optr[i] = (float)v; - } - } - - internal partial struct HardSigmoidJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new HardSigmoidJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new HardSigmoidJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct HardSigmoidJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public HardSigmoidJobHelper data; - - public void Execute(int i) - { - Optr[i] = (float)(math.max(0.0f, math.min(1.0f, data.alpha * Xptr[i] + data.beta))); - } - } - - internal partial struct ClipJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ClipJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ClipJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ClipJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ClipJobHelper data; - - public void Execute(int i) - { - Optr[i] = (float)(math.clamp(Xptr[i], data.min, data.max)); - } - } - - internal partial struct PowJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new PowJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new PowJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct PowJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public PowJobHelper data; - - public void Execute(int i) - { - Optr[i] = (float)(math.pow(Xptr[i], data.alpha)); - } - } - - internal partial struct ErfJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ErfJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ErfJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ErfJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ErfJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i]; - - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x = math.abs(v); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t = 1.0f / (1.0f + p * x); - float t2 = t * t; - float t3 = t2 * t; - float t4 = t3 * t; - float t5 = t4 * t; - - Optr[i] = (float)(math.sign(v) * (1 - (a1 * t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5) * math.exp(-x * x))); - } - } - - internal partial struct EluJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new EluJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new EluJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct EluJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public EluJobHelper data; - - public void Execute(int i) - { - // f(x) = alpha * (exp(x) - 1.) for x < 0, f(x) = x for x >= 0 - // "Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs)", DA Clevert, 2015 - // https://arxiv.org/abs/1511.07289 - float v = Xptr[i]; - if (v <= 0) - v = data.alpha * (math.exp(v) - 1f); - Optr[i] = (float)(v); - } - } - - internal partial struct SeluJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new SeluJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new SeluJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SeluJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SeluJobHelper data; - - public void Execute(int i) - { - // f(x) = gamma * (alpha * e^x - alpha) for x <= 0, f(x) = gamma * x for x > 0 - float v = Xptr[i]; - if (v <= 0.0f) - v = data.gamma * (data.alpha * math.exp(v) - data.alpha); - else - v = data.gamma * v; - Optr[i] = (float)(v); - } - } - - internal partial struct PReluJobHelper - { - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new PReluJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new PReluJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct PReluJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public PReluJobHelper data; - - const int unrollSize = 32; - public void Execute(int i) - { - float* src = Xptr + i * data.inOutChannels; - float* dst = Optr + i * data.inOutChannels; - float* gamma = Bptr + i * data.inOutChannels * data.isGammaAVector; - - int j = 0; - for (; j < data.inOutChannels - unrollSize + 1; j += unrollSize) // unroll of inOutChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++, gamma+=data.isGammaAVector) - *dst = (float)(PRelu(*src, *gamma)); - for (; j < data.inOutChannels; j++, src++, dst++, gamma+=data.isGammaAVector) // remainder of inOutChannels loop - *dst = (float)(PRelu(*src, *gamma)); - } - - public static float PRelu(float v, float gamma) - { - // from Theano impl - // https://github.com/Theano/theano/blob/d395439aec5a6ddde8ef5c266fd976412a5c5695/theano/tensor/nnet/nnet.py#L2209-L2251 - // @TODO: precompute f1 and f2 for all S before this job - float f1 = 0.5f * (1f + gamma); - float f2 = 0.5f * (1f - gamma); - // NOTE: burst-1.2.3 has troubles with Math.Min/Max generating poorly vectorized and branch code - // Instead Math.Abs based code is used instead. (Math.Abs just flips 1 bit) - return f1 * v + f2 * math.abs(v); - } - } - - internal partial struct SwishJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new SwishJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new SwishJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SwishJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SwishJobHelper data; - - public void Execute(int i) - { - // f(x) = sigmoid(x) * x = x / (1 + exp(-x)) - // "Searching for Activation Functions". P Ramachandran, 2017 - // https://arxiv.org/abs/1710.05941 - float v = Xptr[i]; - v = v / (1f + math.exp(-v)); - Optr[i] = (float)(v); - } - } - - #endregion - #region Activation jobs declaration for mode: _Full_Half - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ReluJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ReluJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i]; - // NOTE: burst-1.2.3 has troubles with Math.Min/Max generating poorly vectorized and branch code - // Instead Math.Abs based code is used instead. (Math.Abs just flips 1 bit) - Optr[i] = (half)(0.5f * (v + math.abs(v))); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Relu6Job_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public Relu6JobHelper data; - - public void Execute(int i) - { - // f(x) = min(max(x, 0), 6) - // "Convolutional Deep Belief Networks on CIFAR-10", A Krizhevsky, 2010 - // http://www.cs.utoronto.ca/~kriz/conv-cifar10-aug2010.pdf - float v = Xptr[i]; - - // NOTE: burst-1.2.3 has troubles with Math.Min/Max generating poorly vectorized and branch code - // Instead Math.Abs based code is used instead. (Math.Abs just flips 1 bit) - Optr[i] = (half)(0.5f * (-math.abs(v - 6f) + math.abs(v) + 6f)); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct LeakyReluJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public LeakyReluJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i]; - // NOTE: burst-1.2.3 has troubles with Math.Min/Max generating poorly vectorized and branch code - // Instead Math.Abs based code is used instead. (Math.Abs just flips 1 bit) - Optr[i] = (half)(data.f1 * v + data.f2 * math.abs(v)); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct TanhJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public TanhJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.tanh(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SoftplusJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public SoftplusJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.log(math.exp(x) + 1f); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SigmoidJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public SigmoidJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 1f / (1f + math.exp(-x)); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AbsJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public AbsJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = Math.Abs(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct NegJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public NegJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = -x; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CeilJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public CeilJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.ceil(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct FloorJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public FloorJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.floor(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct RoundJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public RoundJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.round(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ReciprocalJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ReciprocalJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 1.0f / x; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ExpJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ExpJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.exp(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct LogJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public LogJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.log(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SqrtJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public SqrtJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.sqrt(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AcosJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public AcosJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.acos(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AcoshJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public AcoshJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.log( x + math.sqrt(x*x - 1.0f)); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AsinJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public AsinJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.asin(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AsinhJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public AsinhJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.log( x + math.sqrt(x*x + 1.0f)); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AtanJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public AtanJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.atan(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct AtanhJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public AtanhJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 0.5f * math.log((1.0f + x)/(1.0f - x)); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CosJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public CosJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.cos(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CoshJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public CoshJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 0.5f * (math.exp(x) + math.exp(-x)); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SinJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public SinJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.sin(x); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SinhJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public SinhJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = 0.5f * (math.exp(x) - math.exp(-x)); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct TanJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public TanJobHelper data; - - public void Execute(int i) - { - float x = Xptr[i]; - float v = math.tan(x); - Optr[i] = (half)v; - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct HardSigmoidJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public HardSigmoidJobHelper data; - - public void Execute(int i) - { - Optr[i] = (half)(math.max(0.0f, math.min(1.0f, data.alpha * Xptr[i] + data.beta))); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ClipJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ClipJobHelper data; - - public void Execute(int i) - { - Optr[i] = (half)(math.clamp(Xptr[i], data.min, data.max)); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct PowJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public PowJobHelper data; - - public void Execute(int i) - { - Optr[i] = (half)(math.pow(Xptr[i], data.alpha)); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ErfJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ErfJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i]; - - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x = math.abs(v); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t = 1.0f / (1.0f + p * x); - float t2 = t * t; - float t3 = t2 * t; - float t4 = t3 * t; - float t5 = t4 * t; - - Optr[i] = (half)(math.sign(v) * (1 - (a1 * t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5) * math.exp(-x * x))); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct EluJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public EluJobHelper data; - - public void Execute(int i) - { - // f(x) = alpha * (exp(x) - 1.) for x < 0, f(x) = x for x >= 0 - // "Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs)", DA Clevert, 2015 - // https://arxiv.org/abs/1511.07289 - float v = Xptr[i]; - if (v <= 0) - v = data.alpha * (math.exp(v) - 1f); - Optr[i] = (half)(v); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SeluJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public SeluJobHelper data; - - public void Execute(int i) - { - // f(x) = gamma * (alpha * e^x - alpha) for x <= 0, f(x) = gamma * x for x > 0 - float v = Xptr[i]; - if (v <= 0.0f) - v = data.gamma * (data.alpha * math.exp(v) - data.alpha); - else - v = data.gamma * v; - Optr[i] = (half)(v); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct PReluJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public PReluJobHelper data; - - const int unrollSize = 32; - public void Execute(int i) - { - half* src = Xptr + i * data.inOutChannels; - half* dst = Optr + i * data.inOutChannels; - half* gamma = Bptr + i * data.inOutChannels * data.isGammaAVector; - - int j = 0; - for (; j < data.inOutChannels - unrollSize + 1; j += unrollSize) // unroll of inOutChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++, gamma+=data.isGammaAVector) - *dst = (half)(PRelu(*src, *gamma)); - for (; j < data.inOutChannels; j++, src++, dst++, gamma+=data.isGammaAVector) // remainder of inOutChannels loop - *dst = (half)(PRelu(*src, *gamma)); - } - - public static float PRelu(float v, float gamma) - { - // from Theano impl - // https://github.com/Theano/theano/blob/d395439aec5a6ddde8ef5c266fd976412a5c5695/theano/tensor/nnet/nnet.py#L2209-L2251 - // @TODO: precompute f1 and f2 for all S before this job - float f1 = 0.5f * (1f + gamma); - float f2 = 0.5f * (1f - gamma); - // NOTE: burst-1.2.3 has troubles with Math.Min/Max generating poorly vectorized and branch code - // Instead Math.Abs based code is used instead. (Math.Abs just flips 1 bit) - return f1 * v + f2 * math.abs(v); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SwishJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public SwishJobHelper data; - - public void Execute(int i) - { - // f(x) = sigmoid(x) * x = x / (1 + exp(-x)) - // "Searching for Activation Functions". P Ramachandran, 2017 - // https://arxiv.org/abs/1710.05941 - float v = Xptr[i]; - v = v / (1f + math.exp(-v)); - Optr[i] = (half)(v); - } - } - - #endregion -} -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Activation.gen.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Activation.gen.cs.meta deleted file mode 100644 index 895db62..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Activation.gen.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5211ff135b3b87f42be25a8505a28df7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Broadcast.gen.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Broadcast.gen.cs deleted file mode 100644 index ecff60a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Broadcast.gen.cs +++ /dev/null @@ -1,1235 +0,0 @@ -// This is auto-generated -- do not modify directly -using UnityEngine; -using System; -using Unity.Burst; -using Unity.Burst.Intrinsics; -using Unity.Collections; -using Unity.Jobs; -using Unity.Mathematics; -using static Unity.Burst.Intrinsics.X86.Avx; -using static Unity.Burst.Intrinsics.X86.Fma; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs.LowLevel.Unsafe; -using FencingHelperMode = Unity.Barracuda.BurstSchedulingHelper.FencingHelperMode; - -namespace Unity.Barracuda { -public partial class BurstCPUOps -{ - #region Broadcast Jobs declaration for mode: _Full_Float - - internal partial struct VectorBroadcastScaleBiasJobHelper - { - public JobHandle ScheduleXSBO(Tensor X, Tensor S, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinS = Pin(S); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - return ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXSBO(BurstTensorData pinX, BurstTensorData pinS, BurstTensorData pinB, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinS.array.Type == DataType.Half; - bool BHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(WHalf, BHalf); - if (AHalf && WHalf) - { - var job = new VectorBroadcastScaleBiasJob_Full_Half(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && WHalf) - { - var job = new VectorBroadcastScaleBiasJob_ActAsFloat_WeightAsHalf(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && !WHalf) - { - var job = new VectorBroadcastScaleBiasJob_Full_Float(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (AHalf && !WHalf) - { - UnityEngine.Assertions.Assert.IsTrue(false, "VectorBroadcastScaleBiasJob does not support activation as half while weights are floats."); - return new JobHandle(); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct VectorBroadcastScaleBiasJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } float* Sptr => S.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public VectorBroadcastScaleBiasJobHelper data; - - const int unrollSize = 32; - public void Execute(int i) - { - float* src = Xptr + i * data.inOutChannels; - float* dst = Optr + i * data.inOutChannels; - float* gamma = Sptr; - float* beta = Bptr; - - int j = 0; - for (; j < data.inOutChannels - unrollSize + 1; j += unrollSize) // unroll of inOutChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++, gamma++, beta++) - *dst = (float)((*src) * (*gamma) + (*beta) * data.alpha); - for (; j < data.inOutChannels; j++, src++, dst++, gamma++, beta++) // remainder of inOutChannels loop - *dst = (float)((*src) * (*gamma) + (*beta) * data.alpha); - } - } - - internal partial struct ScalarBroadcastAddJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ScalarBroadcastAddJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ScalarBroadcastAddJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastAddJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ScalarBroadcastAddJobHelper data; - - public void Execute(int i) - { - float v = Bptr[0] * data.alpha + Xptr[i]; - Optr[i] = (float)v; - } - } - internal partial struct BroadcastAddJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new BroadcastAddJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new BroadcastAddJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastAddJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public BroadcastAddJobHelper data; - - public void Execute(int i) - { - float v = Bptr[i] * data.alpha + Xptr[i]; - Optr[i] = (float)v; - } - } - internal partial struct ScalarBroadcastMulJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ScalarBroadcastMulJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ScalarBroadcastMulJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastMulJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ScalarBroadcastMulJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i] * Bptr[0]; - Optr[i] = (float)v; - } - } - internal partial struct BroadcastMulJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new BroadcastMulJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new BroadcastMulJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastMulJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public BroadcastMulJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i] * Bptr[i]; - Optr[i] = (float)v; - } - } - internal partial struct ScalarBroadcastDivJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ScalarBroadcastDivJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ScalarBroadcastDivJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastDivJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ScalarBroadcastDivJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i] / Bptr[0]; - Optr[i] = (float)v; - } - } - internal partial struct BroadcastDivJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new BroadcastDivJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new BroadcastDivJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastDivJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public BroadcastDivJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i] / Bptr[i]; - Optr[i] = (float)v; - } - } - internal partial struct ScalarBroadcastMinJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ScalarBroadcastMinJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ScalarBroadcastMinJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastMinJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ScalarBroadcastMinJobHelper data; - - public void Execute(int i) - { - float v = math.min(Xptr[i], Bptr[0]); - Optr[i] = (float)v; - } - } - internal partial struct BroadcastMinJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new BroadcastMinJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new BroadcastMinJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastMinJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public BroadcastMinJobHelper data; - - public void Execute(int i) - { - float v = math.min(Xptr[i], Bptr[i]); - Optr[i] = (float)v; - } - } - internal partial struct ScalarBroadcastMaxJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ScalarBroadcastMaxJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ScalarBroadcastMaxJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastMaxJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ScalarBroadcastMaxJobHelper data; - - public void Execute(int i) - { - float v = math.max(Xptr[i], Bptr[0]); - Optr[i] = (float)v; - } - } - internal partial struct BroadcastMaxJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new BroadcastMaxJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new BroadcastMaxJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastMaxJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public BroadcastMaxJobHelper data; - - public void Execute(int i) - { - float v = math.max(Xptr[i], Bptr[i]); - Optr[i] = (float)v; - } - } - internal partial struct ScalarBroadcastPowJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ScalarBroadcastPowJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ScalarBroadcastPowJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastPowJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ScalarBroadcastPowJobHelper data; - - public void Execute(int i) - { - float v = math.pow(Xptr[i], Bptr[0]); - Optr[i] = (float)v; - } - } - internal partial struct BroadcastPowJobHelper - { - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new BroadcastPowJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new BroadcastPowJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastPowJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public BroadcastPowJobHelper data; - - public void Execute(int i) - { - float v = math.pow(Xptr[i], Bptr[i]); - Optr[i] = (float)v; - } - } - - internal unsafe struct ElementwiseAddJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public fixed int stridesX[8]; - [ReadOnly] public fixed int stridesY[8]; - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ElementwiseAddJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ElementwiseAddJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseAddJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ElementwiseAddJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = data.alpha * y + x; - Optr[i] = (float)v; - } - } - internal unsafe struct ElementwiseMulJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public fixed int stridesX[8]; - [ReadOnly] public fixed int stridesY[8]; - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ElementwiseMulJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ElementwiseMulJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseMulJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ElementwiseMulJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = x * y; - Optr[i] = (float)v; - } - } - internal unsafe struct ElementwiseDivJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public fixed int stridesX[8]; - [ReadOnly] public fixed int stridesY[8]; - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ElementwiseDivJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ElementwiseDivJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseDivJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ElementwiseDivJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = x / y; - Optr[i] = (float)v; - } - } - internal unsafe struct ElementwiseMinJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public fixed int stridesX[8]; - [ReadOnly] public fixed int stridesY[8]; - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ElementwiseMinJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ElementwiseMinJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseMinJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ElementwiseMinJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = math.min(x , y); - Optr[i] = (float)v; - } - } - internal unsafe struct ElementwiseMaxJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public fixed int stridesX[8]; - [ReadOnly] public fixed int stridesY[8]; - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ElementwiseMaxJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ElementwiseMaxJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseMaxJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ElementwiseMaxJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = math.max(x , y); - Optr[i] = (float)v; - } - } - internal unsafe struct ElementwisePowJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public fixed int stridesX[8]; - [ReadOnly] public fixed int stridesY[8]; - [ReadOnly] public float alpha; - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new ElementwisePowJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new ElementwisePowJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwisePowJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ElementwisePowJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = math.pow(x, y); - Optr[i] = (float)v; - } - } - - #endregion - #region Broadcast Jobs declaration for mode: _ActAsFloat_WeightAsHalf - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct VectorBroadcastScaleBiasJob_ActAsFloat_WeightAsHalf : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public VectorBroadcastScaleBiasJobHelper data; - - const int unrollSize = 32; - public void Execute(int i) - { - float* src = Xptr + i * data.inOutChannels; - float* dst = Optr + i * data.inOutChannels; - half* gamma = Sptr; - half* beta = Bptr; - - int j = 0; - for (; j < data.inOutChannels - unrollSize + 1; j += unrollSize) // unroll of inOutChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++, gamma++, beta++) - *dst = (float)((*src) * (*gamma) + (*beta) * data.alpha); - for (; j < data.inOutChannels; j++, src++, dst++, gamma++, beta++) // remainder of inOutChannels loop - *dst = (float)((*src) * (*gamma) + (*beta) * data.alpha); - } - } - - - - #endregion - #region Broadcast Jobs declaration for mode: _Full_Half - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct VectorBroadcastScaleBiasJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public VectorBroadcastScaleBiasJobHelper data; - - const int unrollSize = 32; - public void Execute(int i) - { - half* src = Xptr + i * data.inOutChannels; - half* dst = Optr + i * data.inOutChannels; - half* gamma = Sptr; - half* beta = Bptr; - - int j = 0; - for (; j < data.inOutChannels - unrollSize + 1; j += unrollSize) // unroll of inOutChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++, gamma++, beta++) - *dst = (half)((*src) * (*gamma) + (*beta) * data.alpha); - for (; j < data.inOutChannels; j++, src++, dst++, gamma++, beta++) // remainder of inOutChannels loop - *dst = (half)((*src) * (*gamma) + (*beta) * data.alpha); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastAddJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ScalarBroadcastAddJobHelper data; - - public void Execute(int i) - { - float v = Bptr[0] * data.alpha + Xptr[i]; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastAddJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public BroadcastAddJobHelper data; - - public void Execute(int i) - { - float v = Bptr[i] * data.alpha + Xptr[i]; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastMulJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ScalarBroadcastMulJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i] * Bptr[0]; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastMulJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public BroadcastMulJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i] * Bptr[i]; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastDivJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ScalarBroadcastDivJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i] / Bptr[0]; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastDivJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public BroadcastDivJobHelper data; - - public void Execute(int i) - { - float v = Xptr[i] / Bptr[i]; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastMinJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ScalarBroadcastMinJobHelper data; - - public void Execute(int i) - { - float v = math.min(Xptr[i], Bptr[0]); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastMinJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public BroadcastMinJobHelper data; - - public void Execute(int i) - { - float v = math.min(Xptr[i], Bptr[i]); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastMaxJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ScalarBroadcastMaxJobHelper data; - - public void Execute(int i) - { - float v = math.max(Xptr[i], Bptr[0]); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastMaxJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public BroadcastMaxJobHelper data; - - public void Execute(int i) - { - float v = math.max(Xptr[i], Bptr[i]); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ScalarBroadcastPowJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ScalarBroadcastPowJobHelper data; - - public void Execute(int i) - { - float v = math.pow(Xptr[i], Bptr[0]); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct BroadcastPowJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public BroadcastPowJobHelper data; - - public void Execute(int i) - { - float v = math.pow(Xptr[i], Bptr[i]); - Optr[i] = (half)v; - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseAddJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ElementwiseAddJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = data.alpha * y + x; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseMulJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ElementwiseMulJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = x * y; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseDivJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ElementwiseDivJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = x / y; - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseMinJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ElementwiseMinJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = math.min(x , y); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwiseMaxJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ElementwiseMaxJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = math.max(x , y); - Optr[i] = (half)v; - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct ElementwisePowJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ElementwisePowJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - float x = Xptr[data.stridesX[0] * s + data.stridesX[1] * r + data.stridesX[2] * n + data.stridesX[3] * t + data.stridesX[4] * d + data.stridesX[5] * h + data.stridesX[6] * w + data.stridesX[7] * c]; - float y = Bptr[data.stridesY[0] * s + data.stridesY[1] * r + data.stridesY[2] * n + data.stridesY[3] * t + data.stridesY[4] * d + data.stridesY[5] * h + data.stridesY[6] * w + data.stridesY[7] * c]; - - float v = math.pow(x, y); - Optr[i] = (half)v; - } - } - - #endregion -} -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Broadcast.gen.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Broadcast.gen.cs.meta deleted file mode 100644 index 18a61bf..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Broadcast.gen.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d05274a6ecc82404abe715a573ea8e74 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.DenseConv.gen.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.DenseConv.gen.cs deleted file mode 100644 index 2096039..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.DenseConv.gen.cs +++ /dev/null @@ -1,864 +0,0 @@ -// This is auto-generated -- do not modify directly -using UnityEngine; -using System; -using Unity.Burst; -using Unity.Burst.Intrinsics; -using Unity.Collections; -using Unity.Jobs; -using Unity.Mathematics; -using static Unity.Burst.Intrinsics.X86.Avx; -using static Unity.Burst.Intrinsics.X86.Fma; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs.LowLevel.Unsafe; -using FencingHelperMode = Unity.Barracuda.BurstSchedulingHelper.FencingHelperMode; - -namespace Unity.Barracuda { -public partial class BurstCPUOps -{ - #region Dense/Conv jobs declaration for mode: _Full_Float - - internal partial struct DepthwiseConv2DJobHelper - { - public JobHandle ScheduleXSBO(Tensor X, Tensor S, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinS = Pin(S); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - return ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXSBO(BurstTensorData pinX, BurstTensorData pinS, BurstTensorData pinB, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinS.array.Type == DataType.Half; - bool BHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(WHalf, BHalf); - if (AHalf && WHalf) - { - var job = new DepthwiseConv2DJob_Full_Half(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && WHalf) - { - var job = new DepthwiseConv2DJob_ActAsFloat_WeightAsHalf(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && !WHalf) - { - var job = new DepthwiseConv2DJob_Full_Float(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (AHalf && !WHalf) - { - UnityEngine.Assertions.Assert.IsTrue(false, "DepthwiseConv2DJob does not support activation as half while weights are floats."); - return new JobHandle(); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct DepthwiseConv2DJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } float* Sptr => S.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public DepthwiseConv2DJobHelper data; - - const int unrollSize = 16; - public void Execute(int y) - { - int accumulatorMemSize = data.kernelCount * sizeof(float); - float* outputAccumulators = (float*)UnsafeUtility.Malloc(accumulatorMemSize, JobsUtility.CacheLineSize, Allocator.TempJob); - for (int n = 0; n < data.outBatch; ++n) - for (int x = 0; x < data.outWidth; ++x) - { - // reset accumulators to 0 - UnsafeUtility.MemClear(outputAccumulators, accumulatorMemSize); - - // gather X * K results in accumulators - for (int dy = 0; dy < data.kernelHeight; ++dy) - { - int readY = y * data.strideY + dy - data.padY; - if (readY < 0) continue; - if (readY >= data.inHeight) continue; - - for (int dx = 0; dx < data.kernelWidth; ++dx) - { - int readX = x * data.strideX + dx - data.padY; - if (readX < 0) continue; - if (readX >= data.inWidth) continue; - - float* dst = outputAccumulators; - float* src = Xptr + n * data.inStrideN + readY * data.inStrideH + readX * data.inStrideW; - float* kernel = Sptr + dy * data.kernelStrideH + dx * data.kernelStrideW; - - int k = 0; - for (; k < data.kernelCount - unrollSize + 1; k += unrollSize) // unroll of kernelCount loop - for (int q = 0; q < unrollSize; q++, src++, dst++, kernel++) - *dst += (float)((*src) * (*kernel)); - for (; k < data.kernelCount; k++, src++, dst++, kernel++) // remainder of kernelCount loop - *dst += (float)((*src) * (*kernel)); - } - } - - { // write accumulators to memory and add bias - int k = 0; - float* src = outputAccumulators; - float* dst = Optr + n * data.outStrideN + y * data.outStrideH + x * data.outStrideW; - float* bias = Bptr; - for (; k < data.kernelCount - unrollSize + 1; k += unrollSize) // unroll of kernelCount loop - for (int q = 0; q < unrollSize; q++, src++, dst++, bias++) - *dst = (float)((*src) + (*bias)); - for (; k < data.kernelCount; k++, src++, dst++, bias++) // remainder of kernelCount loop - *dst = (float)((*src) + (*bias)); - } - } - - UnsafeUtility.Free(outputAccumulators, Allocator.TempJob); - } - } - - internal partial struct Dense3JobHelper - { - public JobHandle ScheduleXSBO(Tensor X, Tensor S, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinS = Pin(S); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - return ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXSBO(BurstTensorData pinX, BurstTensorData pinS, BurstTensorData pinB, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinS.array.Type == DataType.Half; - bool BHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(WHalf, BHalf); - if (AHalf && WHalf) - { - var job = new Dense3Job_Full_Half(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && WHalf) - { - var job = new Dense3Job_ActAsFloat_WeightAsHalf(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && !WHalf) - { - var job = new Dense3Job_Full_Float(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (AHalf && !WHalf) - { - UnityEngine.Assertions.Assert.IsTrue(false, "Dense3Job does not support activation as half while weights are floats."); - return new JobHandle(); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct Dense3Job_Full_Float : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } float* Sptr => S.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public Dense3JobHelper data; - - public const int blockSize = 16; - public void Execute(int threadID) - { - float* A = this.Xptr; - float* B = this.Sptr; - float* C = this.Bptr; - float* S = this.Optr; - int AM = data.AM; - int BM = data.BM; - int SM = data.SM; - int AN = data.AN; - int BN = data.BN; - int SN = data.SN; - - int dispatchThreadXY = data.dispatchThreadX * data.dispatchThreadY; - - int batch = (threadID / dispatchThreadXY); - int i = (threadID % dispatchThreadXY) % data.dispatchThreadX; - int j = (threadID % dispatchThreadXY) / data.dispatchThreadX; - - int batchOffSetA = (batch * AM * AN); - int batchOffSetS = (batch * SM * SN); - - int rowA = i * blockSize; - int colB = j * blockSize; - - unsafe - { - float* blockTempA = null; - float* blockTempB = null; - float* blockTempS = null; - - float* blockS = S + rowA + SM * colB + batchOffSetS; - int strideS = SM; - - if (rowA + blockSize > SM || colB + blockSize > SN) // copy remainder of C into zero-padded block - { - blockTempS = AllocBlock(blockSize, blockSize); - strideS = blockSize; - blockS = blockTempS; - } - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockS[x + strideS * y] = (float)((colB + y) < BN ? C[colB + y] : 0.0f); - - for (int l = 0; l < AN; l += blockSize) // inner-loop - { - float* blockA = A + rowA + AM * l + batchOffSetA; - float* blockB = B + l * BN + colB; - int strideA = AM; - int strideB = BN; - - if (rowA + blockSize > AM || l + blockSize > AN) // copy remainder of A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlock(blockSize, blockSize); - strideA = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempA[x + blockSize * y] = (float)(((rowA + x) < AM && (l + y < AN)) ? blockA[x + AM * y] : 0.0f); - - blockA = blockTempA; - } - - if (colB + blockSize > BN || l + blockSize > BM) // copy remainder of B into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlock(blockSize, blockSize); - strideB = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempB[x + blockSize * y] = (float)(((colB + x) < BN && (l + y < BM)) ? blockB[x + BN * y] : 0.0f); - - blockB = blockTempB; - } - - MultiplyBlockUnrollHx16(blockA, strideA, blockB, strideB, blockS, strideS); - } - - if (blockS == blockTempS) // copy back - { - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - { - if (((rowA + x) < SM) && ((colB + y) < SN)) - S[(rowA + x) + SM * (colB + y) + batchOffSetS] = blockTempS[x + blockSize * y]; - } - } - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempS); - } - } - - static void MultiplyBlockUnrollHx16(float* Ap, int Astride, float* Bp, int Bstride, float* Sp, int Sstride) - { - for (int i = 0; i < blockSize; i++) - { - float sum0 = *(Sp + i + Sstride * 0); - float sum1 = *(Sp + i + Sstride * 1); - float sum2 = *(Sp + i + Sstride * 2); - float sum3 = *(Sp + i + Sstride * 3); - float sum4 = *(Sp + i + Sstride * 4); - float sum5 = *(Sp + i + Sstride * 5); - float sum6 = *(Sp + i + Sstride * 6); - float sum7 = *(Sp + i + Sstride * 7); - float sum8 = *(Sp + i + Sstride * 8); - float sum9 = *(Sp + i + Sstride * 9); - float sumA = *(Sp + i + Sstride * 10); - float sumB = *(Sp + i + Sstride * 11); - float sumC = *(Sp + i + Sstride * 12); - float sumD = *(Sp + i + Sstride * 13); - float sumE = *(Sp + i + Sstride * 14); - float sumF = *(Sp + i + Sstride * 15); - - for (int l = 0; l < blockSize; l++) - { - float A = *(Ap + i + Astride * l); - - float B0 = *(Bp + l * Bstride + 0); - float B1 = *(Bp + l * Bstride + 1); - float B2 = *(Bp + l * Bstride + 2); - float B3 = *(Bp + l * Bstride + 3); - float B4 = *(Bp + l * Bstride + 4); - float B5 = *(Bp + l * Bstride + 5); - float B6 = *(Bp + l * Bstride + 6); - float B7 = *(Bp + l * Bstride + 7); - float B8 = *(Bp + l * Bstride + 8); - float B9 = *(Bp + l * Bstride + 9); - float BA = *(Bp + l * Bstride + 10); - float BB = *(Bp + l * Bstride + 11); - float BC = *(Bp + l * Bstride + 12); - float BD = *(Bp + l * Bstride + 13); - float BE = *(Bp + l * Bstride + 14); - float BF = *(Bp + l * Bstride + 15); - - - sum0 += A * B0; - sum1 += A * B1; - sum2 += A * B2; - sum3 += A * B3; - sum4 += A * B4; - sum5 += A * B5; - sum6 += A * B6; - sum7 += A * B7; - sum8 += A * B8; - sum9 += A * B9; - sumA += A * BA; - sumB += A * BB; - sumC += A * BC; - sumD += A * BD; - sumE += A * BE; - sumF += A * BF; - } - - *(Sp + i + Sstride * 0 ) = (float)(sum0); - *(Sp + i + Sstride * 1 ) = (float)(sum1); - *(Sp + i + Sstride * 2 ) = (float)(sum2); - *(Sp + i + Sstride * 3 ) = (float)(sum3); - *(Sp + i + Sstride * 4 ) = (float)(sum4); - *(Sp + i + Sstride * 5 ) = (float)(sum5); - *(Sp + i + Sstride * 6 ) = (float)(sum6); - *(Sp + i + Sstride * 7 ) = (float)(sum7); - *(Sp + i + Sstride * 8 ) = (float)(sum8); - *(Sp + i + Sstride * 9 ) = (float)(sum9); - *(Sp + i + Sstride * 10) = (float)(sumA); - *(Sp + i + Sstride * 11) = (float)(sumB); - *(Sp + i + Sstride * 12) = (float)(sumC); - *(Sp + i + Sstride * 13) = (float)(sumD); - *(Sp + i + Sstride * 14) = (float)(sumE); - *(Sp + i + Sstride * 15) = (float)(sumF); - } - } - } - - #endregion - #region Dense/Conv jobs declaration for mode: _ActAsFloat_WeightAsHalf - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct DepthwiseConv2DJob_ActAsFloat_WeightAsHalf : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public DepthwiseConv2DJobHelper data; - - const int unrollSize = 16; - public void Execute(int y) - { - int accumulatorMemSize = data.kernelCount * sizeof(float); - float* outputAccumulators = (float*)UnsafeUtility.Malloc(accumulatorMemSize, JobsUtility.CacheLineSize, Allocator.TempJob); - for (int n = 0; n < data.outBatch; ++n) - for (int x = 0; x < data.outWidth; ++x) - { - // reset accumulators to 0 - UnsafeUtility.MemClear(outputAccumulators, accumulatorMemSize); - - // gather X * K results in accumulators - for (int dy = 0; dy < data.kernelHeight; ++dy) - { - int readY = y * data.strideY + dy - data.padY; - if (readY < 0) continue; - if (readY >= data.inHeight) continue; - - for (int dx = 0; dx < data.kernelWidth; ++dx) - { - int readX = x * data.strideX + dx - data.padY; - if (readX < 0) continue; - if (readX >= data.inWidth) continue; - - float* dst = outputAccumulators; - float* src = Xptr + n * data.inStrideN + readY * data.inStrideH + readX * data.inStrideW; - half* kernel = Sptr + dy * data.kernelStrideH + dx * data.kernelStrideW; - - int k = 0; - for (; k < data.kernelCount - unrollSize + 1; k += unrollSize) // unroll of kernelCount loop - for (int q = 0; q < unrollSize; q++, src++, dst++, kernel++) - *dst += (float)((*src) * (*kernel)); - for (; k < data.kernelCount; k++, src++, dst++, kernel++) // remainder of kernelCount loop - *dst += (float)((*src) * (*kernel)); - } - } - - { // write accumulators to memory and add bias - int k = 0; - float* src = outputAccumulators; - float* dst = Optr + n * data.outStrideN + y * data.outStrideH + x * data.outStrideW; - half* bias = Bptr; - for (; k < data.kernelCount - unrollSize + 1; k += unrollSize) // unroll of kernelCount loop - for (int q = 0; q < unrollSize; q++, src++, dst++, bias++) - *dst = (float)((*src) + (*bias)); - for (; k < data.kernelCount; k++, src++, dst++, bias++) // remainder of kernelCount loop - *dst = (float)((*src) + (*bias)); - } - } - - UnsafeUtility.Free(outputAccumulators, Allocator.TempJob); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct Dense3Job_ActAsFloat_WeightAsHalf : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public Dense3JobHelper data; - - public const int blockSize = 16; - public void Execute(int threadID) - { - float* A = this.Xptr; - half* B = this.Sptr; - half* C = this.Bptr; - float* S = this.Optr; - int AM = data.AM; - int BM = data.BM; - int SM = data.SM; - int AN = data.AN; - int BN = data.BN; - int SN = data.SN; - - int dispatchThreadXY = data.dispatchThreadX * data.dispatchThreadY; - - int batch = (threadID / dispatchThreadXY); - int i = (threadID % dispatchThreadXY) % data.dispatchThreadX; - int j = (threadID % dispatchThreadXY) / data.dispatchThreadX; - - int batchOffSetA = (batch * AM * AN); - int batchOffSetS = (batch * SM * SN); - - int rowA = i * blockSize; - int colB = j * blockSize; - - unsafe - { - float* blockTempA = null; - half* blockTempB = null; - float* blockTempS = null; - - float* blockS = S + rowA + SM * colB + batchOffSetS; - int strideS = SM; - - if (rowA + blockSize > SM || colB + blockSize > SN) // copy remainder of C into zero-padded block - { - blockTempS = AllocBlock(blockSize, blockSize); - strideS = blockSize; - blockS = blockTempS; - } - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockS[x + strideS * y] = (float)((colB + y) < BN ? C[colB + y] : 0.0f); - - for (int l = 0; l < AN; l += blockSize) // inner-loop - { - float* blockA = A + rowA + AM * l + batchOffSetA; - half* blockB = B + l * BN + colB; - int strideA = AM; - int strideB = BN; - - if (rowA + blockSize > AM || l + blockSize > AN) // copy remainder of A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlock(blockSize, blockSize); - strideA = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempA[x + blockSize * y] = (float)(((rowA + x) < AM && (l + y < AN)) ? blockA[x + AM * y] : 0.0f); - - blockA = blockTempA; - } - - if (colB + blockSize > BN || l + blockSize > BM) // copy remainder of B into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlockHalf(blockSize, blockSize); - strideB = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempB[x + blockSize * y] = (half)(((colB + x) < BN && (l + y < BM)) ? blockB[x + BN * y] : 0.0f); - - blockB = blockTempB; - } - - MultiplyBlockUnrollHx16(blockA, strideA, blockB, strideB, blockS, strideS); - } - - if (blockS == blockTempS) // copy back - { - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - { - if (((rowA + x) < SM) && ((colB + y) < SN)) - S[(rowA + x) + SM * (colB + y) + batchOffSetS] = blockTempS[x + blockSize * y]; - } - } - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempS); - } - } - - static void MultiplyBlockUnrollHx16(float* Ap, int Astride, half* Bp, int Bstride, float* Sp, int Sstride) - { - for (int i = 0; i < blockSize; i++) - { - float sum0 = *(Sp + i + Sstride * 0); - float sum1 = *(Sp + i + Sstride * 1); - float sum2 = *(Sp + i + Sstride * 2); - float sum3 = *(Sp + i + Sstride * 3); - float sum4 = *(Sp + i + Sstride * 4); - float sum5 = *(Sp + i + Sstride * 5); - float sum6 = *(Sp + i + Sstride * 6); - float sum7 = *(Sp + i + Sstride * 7); - float sum8 = *(Sp + i + Sstride * 8); - float sum9 = *(Sp + i + Sstride * 9); - float sumA = *(Sp + i + Sstride * 10); - float sumB = *(Sp + i + Sstride * 11); - float sumC = *(Sp + i + Sstride * 12); - float sumD = *(Sp + i + Sstride * 13); - float sumE = *(Sp + i + Sstride * 14); - float sumF = *(Sp + i + Sstride * 15); - - for (int l = 0; l < blockSize; l++) - { - float A = *(Ap + i + Astride * l); - - float B0 = *(Bp + l * Bstride + 0); - float B1 = *(Bp + l * Bstride + 1); - float B2 = *(Bp + l * Bstride + 2); - float B3 = *(Bp + l * Bstride + 3); - float B4 = *(Bp + l * Bstride + 4); - float B5 = *(Bp + l * Bstride + 5); - float B6 = *(Bp + l * Bstride + 6); - float B7 = *(Bp + l * Bstride + 7); - float B8 = *(Bp + l * Bstride + 8); - float B9 = *(Bp + l * Bstride + 9); - float BA = *(Bp + l * Bstride + 10); - float BB = *(Bp + l * Bstride + 11); - float BC = *(Bp + l * Bstride + 12); - float BD = *(Bp + l * Bstride + 13); - float BE = *(Bp + l * Bstride + 14); - float BF = *(Bp + l * Bstride + 15); - - - sum0 += A * B0; - sum1 += A * B1; - sum2 += A * B2; - sum3 += A * B3; - sum4 += A * B4; - sum5 += A * B5; - sum6 += A * B6; - sum7 += A * B7; - sum8 += A * B8; - sum9 += A * B9; - sumA += A * BA; - sumB += A * BB; - sumC += A * BC; - sumD += A * BD; - sumE += A * BE; - sumF += A * BF; - } - - *(Sp + i + Sstride * 0 ) = (float)(sum0); - *(Sp + i + Sstride * 1 ) = (float)(sum1); - *(Sp + i + Sstride * 2 ) = (float)(sum2); - *(Sp + i + Sstride * 3 ) = (float)(sum3); - *(Sp + i + Sstride * 4 ) = (float)(sum4); - *(Sp + i + Sstride * 5 ) = (float)(sum5); - *(Sp + i + Sstride * 6 ) = (float)(sum6); - *(Sp + i + Sstride * 7 ) = (float)(sum7); - *(Sp + i + Sstride * 8 ) = (float)(sum8); - *(Sp + i + Sstride * 9 ) = (float)(sum9); - *(Sp + i + Sstride * 10) = (float)(sumA); - *(Sp + i + Sstride * 11) = (float)(sumB); - *(Sp + i + Sstride * 12) = (float)(sumC); - *(Sp + i + Sstride * 13) = (float)(sumD); - *(Sp + i + Sstride * 14) = (float)(sumE); - *(Sp + i + Sstride * 15) = (float)(sumF); - } - } - } - - #endregion - #region Dense/Conv jobs declaration for mode: _Full_Half - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct DepthwiseConv2DJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public DepthwiseConv2DJobHelper data; - - const int unrollSize = 16; - public void Execute(int y) - { - int accumulatorMemSize = data.kernelCount * sizeof(half); - half* outputAccumulators = (half*)UnsafeUtility.Malloc(accumulatorMemSize, JobsUtility.CacheLineSize, Allocator.TempJob); - for (int n = 0; n < data.outBatch; ++n) - for (int x = 0; x < data.outWidth; ++x) - { - // reset accumulators to 0 - UnsafeUtility.MemClear(outputAccumulators, accumulatorMemSize); - - // gather X * K results in accumulators - for (int dy = 0; dy < data.kernelHeight; ++dy) - { - int readY = y * data.strideY + dy - data.padY; - if (readY < 0) continue; - if (readY >= data.inHeight) continue; - - for (int dx = 0; dx < data.kernelWidth; ++dx) - { - int readX = x * data.strideX + dx - data.padY; - if (readX < 0) continue; - if (readX >= data.inWidth) continue; - - half* dst = outputAccumulators; - half* src = Xptr + n * data.inStrideN + readY * data.inStrideH + readX * data.inStrideW; - half* kernel = Sptr + dy * data.kernelStrideH + dx * data.kernelStrideW; - - int k = 0; - for (; k < data.kernelCount - unrollSize + 1; k += unrollSize) // unroll of kernelCount loop - for (int q = 0; q < unrollSize; q++, src++, dst++, kernel++) - *dst += (half)((*src) * (*kernel)); - for (; k < data.kernelCount; k++, src++, dst++, kernel++) // remainder of kernelCount loop - *dst += (half)((*src) * (*kernel)); - } - } - - { // write accumulators to memory and add bias - int k = 0; - half* src = outputAccumulators; - half* dst = Optr + n * data.outStrideN + y * data.outStrideH + x * data.outStrideW; - half* bias = Bptr; - for (; k < data.kernelCount - unrollSize + 1; k += unrollSize) // unroll of kernelCount loop - for (int q = 0; q < unrollSize; q++, src++, dst++, bias++) - *dst = (half)((*src) + (*bias)); - for (; k < data.kernelCount; k++, src++, dst++, bias++) // remainder of kernelCount loop - *dst = (half)((*src) + (*bias)); - } - } - - UnsafeUtility.Free(outputAccumulators, Allocator.TempJob); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct Dense3Job_Full_Half : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public Dense3JobHelper data; - - public const int blockSize = 16; - public void Execute(int threadID) - { - half* A = this.Xptr; - half* B = this.Sptr; - half* C = this.Bptr; - half* S = this.Optr; - int AM = data.AM; - int BM = data.BM; - int SM = data.SM; - int AN = data.AN; - int BN = data.BN; - int SN = data.SN; - - int dispatchThreadXY = data.dispatchThreadX * data.dispatchThreadY; - - int batch = (threadID / dispatchThreadXY); - int i = (threadID % dispatchThreadXY) % data.dispatchThreadX; - int j = (threadID % dispatchThreadXY) / data.dispatchThreadX; - - int batchOffSetA = (batch * AM * AN); - int batchOffSetS = (batch * SM * SN); - - int rowA = i * blockSize; - int colB = j * blockSize; - - unsafe - { - half* blockTempA = null; - half* blockTempB = null; - half* blockTempS = null; - - half* blockS = S + rowA + SM * colB + batchOffSetS; - int strideS = SM; - - if (rowA + blockSize > SM || colB + blockSize > SN) // copy remainder of C into zero-padded block - { - blockTempS = AllocBlockHalf(blockSize, blockSize); - strideS = blockSize; - blockS = blockTempS; - } - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockS[x + strideS * y] = (half)((colB + y) < BN ? C[colB + y] : 0.0f); - - for (int l = 0; l < AN; l += blockSize) // inner-loop - { - half* blockA = A + rowA + AM * l + batchOffSetA; - half* blockB = B + l * BN + colB; - int strideA = AM; - int strideB = BN; - - if (rowA + blockSize > AM || l + blockSize > AN) // copy remainder of A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlockHalf(blockSize, blockSize); - strideA = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempA[x + blockSize * y] = (half)(((rowA + x) < AM && (l + y < AN)) ? blockA[x + AM * y] : 0.0f); - - blockA = blockTempA; - } - - if (colB + blockSize > BN || l + blockSize > BM) // copy remainder of B into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlockHalf(blockSize, blockSize); - strideB = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempB[x + blockSize * y] = (half)(((colB + x) < BN && (l + y < BM)) ? blockB[x + BN * y] : 0.0f); - - blockB = blockTempB; - } - - MultiplyBlockUnrollHx16(blockA, strideA, blockB, strideB, blockS, strideS); - } - - if (blockS == blockTempS) // copy back - { - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - { - if (((rowA + x) < SM) && ((colB + y) < SN)) - S[(rowA + x) + SM * (colB + y) + batchOffSetS] = blockTempS[x + blockSize * y]; - } - } - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempS); - } - } - - static void MultiplyBlockUnrollHx16(half* Ap, int Astride, half* Bp, int Bstride, half* Sp, int Sstride) - { - for (int i = 0; i < blockSize; i++) - { - float sum0 = *(Sp + i + Sstride * 0); - float sum1 = *(Sp + i + Sstride * 1); - float sum2 = *(Sp + i + Sstride * 2); - float sum3 = *(Sp + i + Sstride * 3); - float sum4 = *(Sp + i + Sstride * 4); - float sum5 = *(Sp + i + Sstride * 5); - float sum6 = *(Sp + i + Sstride * 6); - float sum7 = *(Sp + i + Sstride * 7); - float sum8 = *(Sp + i + Sstride * 8); - float sum9 = *(Sp + i + Sstride * 9); - float sumA = *(Sp + i + Sstride * 10); - float sumB = *(Sp + i + Sstride * 11); - float sumC = *(Sp + i + Sstride * 12); - float sumD = *(Sp + i + Sstride * 13); - float sumE = *(Sp + i + Sstride * 14); - float sumF = *(Sp + i + Sstride * 15); - - for (int l = 0; l < blockSize; l++) - { - float A = *(Ap + i + Astride * l); - - float B0 = *(Bp + l * Bstride + 0); - float B1 = *(Bp + l * Bstride + 1); - float B2 = *(Bp + l * Bstride + 2); - float B3 = *(Bp + l * Bstride + 3); - float B4 = *(Bp + l * Bstride + 4); - float B5 = *(Bp + l * Bstride + 5); - float B6 = *(Bp + l * Bstride + 6); - float B7 = *(Bp + l * Bstride + 7); - float B8 = *(Bp + l * Bstride + 8); - float B9 = *(Bp + l * Bstride + 9); - float BA = *(Bp + l * Bstride + 10); - float BB = *(Bp + l * Bstride + 11); - float BC = *(Bp + l * Bstride + 12); - float BD = *(Bp + l * Bstride + 13); - float BE = *(Bp + l * Bstride + 14); - float BF = *(Bp + l * Bstride + 15); - - - sum0 += A * B0; - sum1 += A * B1; - sum2 += A * B2; - sum3 += A * B3; - sum4 += A * B4; - sum5 += A * B5; - sum6 += A * B6; - sum7 += A * B7; - sum8 += A * B8; - sum9 += A * B9; - sumA += A * BA; - sumB += A * BB; - sumC += A * BC; - sumD += A * BD; - sumE += A * BE; - sumF += A * BF; - } - - *(Sp + i + Sstride * 0 ) = (half)(sum0); - *(Sp + i + Sstride * 1 ) = (half)(sum1); - *(Sp + i + Sstride * 2 ) = (half)(sum2); - *(Sp + i + Sstride * 3 ) = (half)(sum3); - *(Sp + i + Sstride * 4 ) = (half)(sum4); - *(Sp + i + Sstride * 5 ) = (half)(sum5); - *(Sp + i + Sstride * 6 ) = (half)(sum6); - *(Sp + i + Sstride * 7 ) = (half)(sum7); - *(Sp + i + Sstride * 8 ) = (half)(sum8); - *(Sp + i + Sstride * 9 ) = (half)(sum9); - *(Sp + i + Sstride * 10) = (half)(sumA); - *(Sp + i + Sstride * 11) = (half)(sumB); - *(Sp + i + Sstride * 12) = (half)(sumC); - *(Sp + i + Sstride * 13) = (half)(sumD); - *(Sp + i + Sstride * 14) = (half)(sumE); - *(Sp + i + Sstride * 15) = (half)(sumF); - } - } - } - - #endregion -} -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.DenseConv.gen.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.DenseConv.gen.cs.meta deleted file mode 100644 index faf72c8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.DenseConv.gen.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 417ca864422a2384ab3013114bf9f845 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Other.gen.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Other.gen.cs deleted file mode 100644 index 8f064b0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Other.gen.cs +++ /dev/null @@ -1,1187 +0,0 @@ -// This is auto-generated -- do not modify directly -using UnityEngine; -using System; -using Unity.Burst; -using Unity.Burst.Intrinsics; -using Unity.Collections; -using Unity.Jobs; -using Unity.Mathematics; -using static Unity.Burst.Intrinsics.X86.Avx; -using static Unity.Burst.Intrinsics.X86.Fma; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs.LowLevel.Unsafe; -using FencingHelperMode = Unity.Barracuda.BurstSchedulingHelper.FencingHelperMode; - -namespace Unity.Barracuda { -public partial class BurstCPUOps -{ - #region Other jobs declaration for mode: _Full_Float - - internal partial struct CopyJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new CopyJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, fencingMode); - } - else - { - var job = new CopyJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CopyJob_Full_Float : IJob, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public CopyJobHelper data; - - public void Execute() - { - UnsafeUtility.MemCpy(destination: Optr, source: Xptr, size: data.length * sizeof(float)); - } - } - - internal partial struct CopyStrideJobHelper - { - public JobHandle ScheduleXO(BurstTensorData pinX, int offsetX, BurstTensorData pinO, int offsetY, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new CopyStrideJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, offsetX, pinO, offsetY, fencingMode); - } - else - { - var job = new CopyStrideJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, offsetX, pinO, offsetY, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CopyStrideJob_Full_Float : IJob, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public CopyStrideJobHelper data; - - public void Execute() - { - UnsafeUtility.MemCpyStride(destination: Optr, destinationStride: data.OStride * sizeof(float), - source: Xptr, sourceStride: data.XStride * sizeof(float), - elementSize: data.length * sizeof(float), count: data.count); - } - } - - internal partial struct GenericSliceJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new GenericSliceJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new GenericSliceJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct GenericSliceJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public GenericSliceJobHelper data; - - public void Execute(int threadIndex) - { - int indexO = threadIndex * data.shapeO.channels; - int s = 0, r = 0, n = 0, t = 0; - int d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(indexO, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - s = data.startS + s * data.strideS; - r = data.startR + r * data.strideR; - n = data.startN + n * data.strideN; - t = data.startT + t * data.strideT; - d = data.startD + d * data.strideD; - h = data.startH + h * data.strideH; - w = data.startW + w * data.strideW; - c = data.startC + c * data.strideC; - int indexX = data.shapeX.Index(s, r, n, t, d, h, w, c); - UnsafeUtility.MemCpy(destination: Optr+indexO, source: Xptr+indexX, size: data.shapeO.channels * sizeof(float)); - } - } - - internal partial struct GenericStridedSliceJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new GenericStridedSliceJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new GenericStridedSliceJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct GenericStridedSliceJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public GenericStridedSliceJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0; - int d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - s = data.startS + s * data.strideS; - r = data.startR + r * data.strideR; - n = data.startN + n * data.strideN; - t = data.startT + t * data.strideT; - d = data.startD + d * data.strideD; - h = data.startH + h * data.strideH; - w = data.startW + w * data.strideW; - c = data.startC + c * data.strideC; - Optr[i] = (float)(Xptr[data.shapeX.Index(s, r, n, t, d, h, w, c)]); - } - } - - internal partial struct Border2DJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new Border2DJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new Border2DJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Border2DJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public Border2DJobHelper data; - - public void Execute(int i) - { - int n = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref n, ref h, ref w, ref c); - - int readX = w - data.PadWidth; - int readY = h - data.PadHeight; - int readC = c - data.PadChannels; - - float v; - if (readX < 0 || readX >= data.CroppedWidth || - readY < 0 || readY >= data.CroppedHeight || - readC < 0 || readC >= data.CroppedChannels) - { - v = data.Beta; - } - else - { - v = Xptr[data.shapeX.Index(n, readY, readX, readC)]; - } - - Optr[i] = (float)(v); - } - } - - internal partial struct TransposeJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new TransposeJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new TransposeJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct TransposeJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public TransposeJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeX.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - int* index = stackalloc int[8]; - index[0] = s; index[1] = r; index[2] = n; index[3] = t; index[4] = d; index[5] = h; index[6] = w; index[7] = c; - - int indexO = data.shapeO.Index(index[data.permutations[0]], - index[data.permutations[1]], - index[data.permutations[2]], - index[data.permutations[3]], - index[data.permutations[4]], - index[data.permutations[5]], - index[data.permutations[6]], - index[data.permutations[7]]); - Optr[indexO] = (float)(Xptr[i]); - } - } - - internal partial struct Pad2DEdgeJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new Pad2DEdgeJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new Pad2DEdgeJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Pad2DEdgeJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public Pad2DEdgeJobHelper data; - - public void Execute(int i) - { - int n = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref n, ref h, ref w, ref c); - - int readX = w - data.PadWidth; - int readY = h - data.PadHeight; - int readC = c - data.PadChannels; - - readX = math.max(readX, 0); - readY = math.max(readY, 0); - readC = math.max(readC, 0); - readX = math.min(readX, data.shapeX.width - 1); - readY = math.min(readY, data.shapeX.height - 1); - readC = math.min(readC, data.shapeX.channels- 1); - - Optr[i] = (float)(Xptr[data.shapeX.Index(n, readY, readX, readC)]); - } - } - - internal partial struct Pad2DReflectJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new Pad2DReflectJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new Pad2DReflectJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Pad2DReflectJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public Pad2DReflectJobHelper data; - - public void Execute(int i) - { - int n = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref n, ref h, ref w, ref c); - - int readX = w - data.PadWidth; - int readY = h - data.PadHeight; - int readC = c - data.PadChannels; - - int lastXIndex = data.shapeX.width - 1; - int lastYIndex = data.shapeX.height - 1; - int lastCIndex = data.shapeX.channels - 1; - - //x reflect indexing - if (readX < 0) - readX = -readX; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex); - - //y reflect indexing - if (readY < 0) - readY = -readY; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex); - - //c reflect indexing - if (readC < 0) - readC = -readC; - else if (readC > lastCIndex) - readC = lastCIndex - (readC - lastCIndex); - - readX = math.max(readX, 0); - readY = math.max(readY, 0); - readC = math.max(readC, 0); - readX = math.min(readX, data.shapeX.width - 1); - readY = math.min(readY, data.shapeX.height - 1); - readC = math.min(readC, data.shapeX.channels- 1); - - Optr[i] = Xptr[data.shapeX.Index(n, readY, readX, readC)]; - } - } - - internal partial struct Pad2DSymmetricJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new Pad2DSymmetricJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new Pad2DSymmetricJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Pad2DSymmetricJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public Pad2DSymmetricJobHelper data; - - public void Execute(int i) - { - int n = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref n, ref h, ref w, ref c); - - int readX = w - data.PadWidth; - int readY = h - data.PadHeight; - int readC = c - data.PadChannels; - - int lastXIndex = data.shapeX.width - 1; - int lastYIndex = data.shapeX.height - 1; - int lastCIndex = data.shapeX.channels - 1; - - //x symmetric indexing - if (readX < 0) - readX = -readX - 1; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex) + 1; - - //y symmetric indexing - if (readY < 0) - readY = -readY - 1; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex) + 1; - - //c symmetric indexing - if (readC < 0) - readC = -readC - 1; - else if (readC > lastCIndex) - readC = lastCIndex - (readC - lastCIndex) + 1; - - readX = math.max(readX, 0); - readY = math.max(readY, 0); - readC = math.max(readC, 0); - readX = math.min(readX, data.shapeX.width - 1); - readY = math.min(readY, data.shapeX.height - 1); - readC = math.min(readC, data.shapeX.channels- 1); - - Optr[i] = (float)(Xptr[data.shapeX.Index(n, readY, readX, readC)]); - } - } - - internal partial struct TileJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new TileJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new TileJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct TileJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public TileJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - s = s % data.shapeX[0]; - r = r % data.shapeX[1]; - n = n % data.shapeX[2]; - t = t % data.shapeX[3]; - d = d % data.shapeX[4]; - h = h % data.shapeX[5]; - w = w % data.shapeX[6]; - c = c % data.shapeX[7]; - - float x = Xptr[data.shapeX.Index(s, r, n, t, d, h, w, c)]; - Optr[i] = (float)(x); - } - } - - internal partial struct GatherJobHelper - { - public JobHandle ScheduleXBO(Tensor X, Tensor B, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache: false); - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(AHalf, WHalf); - if (AHalf) - { - var job = new GatherJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (!AHalf) - { - var job = new GatherJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct GatherJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat;//Always use activation type - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public GatherJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - int d0 = (data.axis == 0) ? (int) Bptr[s] : s; - int d1 = (data.axis == 1) ? (int) Bptr[r] : r; - int d2 = (data.axis == 2) ? (int) Bptr[n] : n; - int d3 = (data.axis == 3) ? (int) Bptr[t] : t; - int d4 = (data.axis == 4) ? (int) Bptr[d] : d; - int d5 = (data.axis == 5) ? (int) Bptr[h] : h; - int d6 = (data.axis == 6) ? (int) Bptr[w] : w; - int d7 = (data.axis == 7) ? (int) Bptr[c] : c; - - Optr[i] = (float)(Xptr[data.shapeX.Index(d0, d1, d2, d3, d4, d5, d6, d7)]); - } - } - - internal partial struct OneHotJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new OneHotJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new OneHotJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct OneHotJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public OneHotJobHelper data; - - public void Execute(int idx) - { - // rank1: X = n,_,_,_ - // rank2: X = n,_,_,c - // rank3: X = n,_,w,c - - if (data.inputRank == 1) // TensorShape(X.flatHeight, depth) - { - int j = idx % data.depth; - int n = (idx / data.depth) % data.shapeX.flatHeight; - - int index = (int)Xptr[n]; - float v = (j == index) ? data.onValue: data.offValue; - Optr[idx] = (float)(v); - } - else if (data.inputRank == 2) // TensorShape(X.flatHeight, 1, depth, X.channels)); - { - int i = idx % data.shapeX.channels; - int j = (idx / data.shapeX.channels) % data.depth; - int n = ((idx / data.shapeX.channels) / data.depth) % data.shapeX.flatHeight; - - int index = (int)Xptr[data.shapeX.Index(n, i)]; - float v = (j == index) ? data.onValue: data.offValue; - Optr[idx] = (float)(v); - } - else // TensorShape(X.batch, X.width, depth, X.channels)) - { - int i = idx % data.shapeX.channels; - int j = (idx / data.shapeX.channels) % data.depth; - int k = ((idx / data.shapeX.channels) / data.depth) % data.shapeX.width; - int n = (((idx / data.shapeX.channels) / data.depth) / data.shapeX.width) % data.shapeX.batch; - - int index = (int)Xptr[data.shapeX.Index(n, 0, k, i)]; - float v = (j == index) ? data.onValue: data.offValue; - Optr[idx] = (float)(v); - } - } - } - - internal partial struct RandomNormalJobHelper - { - public JobHandle ScheduleO(BurstTensorData pinO, int offset, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool OHalf = pinO.array.Type == DataType.Half; - if (OHalf) - { - var job = new RandomNormalJob_Full_Half(); - job.data = this; - return job.ScheduleO(pinO, offset, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new RandomNormalJob_Full_Float(); - job.data = this; - return job.ScheduleO(pinO, offset, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct RandomNormalJob_Full_Float : IJobParallelFor, IJobResourceDeclarationO - { - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public RandomNormalJobHelper data; - - float Gaussian(float mean, float stdDev) - { - float u, v, s; - do { - u = data.rng.NextFloat() * 2 - 1; - v = data.rng.NextFloat() * 2 - 1; - s = u * u + v * v; - } while (s >= 1 || s == 0); - float mul = Mathf.Sqrt(-2.0f * Mathf.Log(s) / s); - return mean + stdDev * u * mul; - } - - public void Execute(int i) - { - Optr[i] = (float)(Gaussian(data.mean, data.scale)); - } - } - - internal partial struct RandomUniformJobHelper - { - public JobHandle ScheduleO(BurstTensorData pinO, int offset, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool OHalf = pinO.array.Type == DataType.Half; - if (OHalf) - { - var job = new RandomUniformJob_Full_Half(); - job.data = this; - return job.ScheduleO(pinO, offset, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new RandomUniformJob_Full_Float(); - job.data = this; - return job.ScheduleO(pinO, offset, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct RandomUniformJob_Full_Float : IJobParallelFor, IJobResourceDeclarationO - { - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public RandomUniformJobHelper data; - - public void Execute(int i) - { - float v = data.mean + data.scale * data.rng.NextFloat(); - Optr[i] = (float)(v); - } - } - - #endregion - #region Other jobs declaration for mode: _ActAsFloat_WeightAsHalf - - - - - - - - - - - - - - - - #endregion - #region Other jobs declaration for mode: _Full_Half - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CopyJob_Full_Half : IJob, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public CopyJobHelper data; - - public void Execute() - { - UnsafeUtility.MemCpy(destination: Optr, source: Xptr, size: data.length * sizeof(half)); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct CopyStrideJob_Full_Half : IJob, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public CopyStrideJobHelper data; - - public void Execute() - { - UnsafeUtility.MemCpyStride(destination: Optr, destinationStride: data.OStride * sizeof(half), - source: Xptr, sourceStride: data.XStride * sizeof(half), - elementSize: data.length * sizeof(half), count: data.count); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct GenericSliceJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public GenericSliceJobHelper data; - - public void Execute(int threadIndex) - { - int indexO = threadIndex * data.shapeO.channels; - int s = 0, r = 0, n = 0, t = 0; - int d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(indexO, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - s = data.startS + s * data.strideS; - r = data.startR + r * data.strideR; - n = data.startN + n * data.strideN; - t = data.startT + t * data.strideT; - d = data.startD + d * data.strideD; - h = data.startH + h * data.strideH; - w = data.startW + w * data.strideW; - c = data.startC + c * data.strideC; - int indexX = data.shapeX.Index(s, r, n, t, d, h, w, c); - UnsafeUtility.MemCpy(destination: Optr+indexO, source: Xptr+indexX, size: data.shapeO.channels * sizeof(half)); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct GenericStridedSliceJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public GenericStridedSliceJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0; - int d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - s = data.startS + s * data.strideS; - r = data.startR + r * data.strideR; - n = data.startN + n * data.strideN; - t = data.startT + t * data.strideT; - d = data.startD + d * data.strideD; - h = data.startH + h * data.strideH; - w = data.startW + w * data.strideW; - c = data.startC + c * data.strideC; - Optr[i] = (half)(Xptr[data.shapeX.Index(s, r, n, t, d, h, w, c)]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Border2DJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public Border2DJobHelper data; - - public void Execute(int i) - { - int n = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref n, ref h, ref w, ref c); - - int readX = w - data.PadWidth; - int readY = h - data.PadHeight; - int readC = c - data.PadChannels; - - float v; - if (readX < 0 || readX >= data.CroppedWidth || - readY < 0 || readY >= data.CroppedHeight || - readC < 0 || readC >= data.CroppedChannels) - { - v = data.Beta; - } - else - { - v = Xptr[data.shapeX.Index(n, readY, readX, readC)]; - } - - Optr[i] = (half)(v); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct TransposeJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public TransposeJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeX.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - int* index = stackalloc int[8]; - index[0] = s; index[1] = r; index[2] = n; index[3] = t; index[4] = d; index[5] = h; index[6] = w; index[7] = c; - - int indexO = data.shapeO.Index(index[data.permutations[0]], - index[data.permutations[1]], - index[data.permutations[2]], - index[data.permutations[3]], - index[data.permutations[4]], - index[data.permutations[5]], - index[data.permutations[6]], - index[data.permutations[7]]); - Optr[indexO] = (half)(Xptr[i]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Pad2DEdgeJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public Pad2DEdgeJobHelper data; - - public void Execute(int i) - { - int n = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref n, ref h, ref w, ref c); - - int readX = w - data.PadWidth; - int readY = h - data.PadHeight; - int readC = c - data.PadChannels; - - readX = math.max(readX, 0); - readY = math.max(readY, 0); - readC = math.max(readC, 0); - readX = math.min(readX, data.shapeX.width - 1); - readY = math.min(readY, data.shapeX.height - 1); - readC = math.min(readC, data.shapeX.channels- 1); - - Optr[i] = (half)(Xptr[data.shapeX.Index(n, readY, readX, readC)]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Pad2DReflectJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public Pad2DReflectJobHelper data; - - public void Execute(int i) - { - int n = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref n, ref h, ref w, ref c); - - int readX = w - data.PadWidth; - int readY = h - data.PadHeight; - int readC = c - data.PadChannels; - - int lastXIndex = data.shapeX.width - 1; - int lastYIndex = data.shapeX.height - 1; - int lastCIndex = data.shapeX.channels - 1; - - //x reflect indexing - if (readX < 0) - readX = -readX; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex); - - //y reflect indexing - if (readY < 0) - readY = -readY; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex); - - //c reflect indexing - if (readC < 0) - readC = -readC; - else if (readC > lastCIndex) - readC = lastCIndex - (readC - lastCIndex); - - readX = math.max(readX, 0); - readY = math.max(readY, 0); - readC = math.max(readC, 0); - readX = math.min(readX, data.shapeX.width - 1); - readY = math.min(readY, data.shapeX.height - 1); - readC = math.min(readC, data.shapeX.channels- 1); - - Optr[i] = Xptr[data.shapeX.Index(n, readY, readX, readC)]; - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct Pad2DSymmetricJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public Pad2DSymmetricJobHelper data; - - public void Execute(int i) - { - int n = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref n, ref h, ref w, ref c); - - int readX = w - data.PadWidth; - int readY = h - data.PadHeight; - int readC = c - data.PadChannels; - - int lastXIndex = data.shapeX.width - 1; - int lastYIndex = data.shapeX.height - 1; - int lastCIndex = data.shapeX.channels - 1; - - //x symmetric indexing - if (readX < 0) - readX = -readX - 1; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex) + 1; - - //y symmetric indexing - if (readY < 0) - readY = -readY - 1; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex) + 1; - - //c symmetric indexing - if (readC < 0) - readC = -readC - 1; - else if (readC > lastCIndex) - readC = lastCIndex - (readC - lastCIndex) + 1; - - readX = math.max(readX, 0); - readY = math.max(readY, 0); - readC = math.max(readC, 0); - readX = math.min(readX, data.shapeX.width - 1); - readY = math.min(readY, data.shapeX.height - 1); - readC = math.min(readC, data.shapeX.channels- 1); - - Optr[i] = (half)(Xptr[data.shapeX.Index(n, readY, readX, readC)]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct TileJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public TileJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - s = s % data.shapeX[0]; - r = r % data.shapeX[1]; - n = n % data.shapeX[2]; - t = t % data.shapeX[3]; - d = d % data.shapeX[4]; - h = h % data.shapeX[5]; - w = w % data.shapeX[6]; - c = c % data.shapeX[7]; - - float x = Xptr[data.shapeX.Index(s, r, n, t, d, h, w, c)]; - Optr[i] = (half)(x); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct GatherJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf;//Always use activation type - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public GatherJobHelper data; - - public void Execute(int i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - data.shapeO.GetPositionsFromIndex(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - - int d0 = (data.axis == 0) ? (int) Bptr[s] : s; - int d1 = (data.axis == 1) ? (int) Bptr[r] : r; - int d2 = (data.axis == 2) ? (int) Bptr[n] : n; - int d3 = (data.axis == 3) ? (int) Bptr[t] : t; - int d4 = (data.axis == 4) ? (int) Bptr[d] : d; - int d5 = (data.axis == 5) ? (int) Bptr[h] : h; - int d6 = (data.axis == 6) ? (int) Bptr[w] : w; - int d7 = (data.axis == 7) ? (int) Bptr[c] : c; - - Optr[i] = (half)(Xptr[data.shapeX.Index(d0, d1, d2, d3, d4, d5, d6, d7)]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct OneHotJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public OneHotJobHelper data; - - public void Execute(int idx) - { - // rank1: X = n,_,_,_ - // rank2: X = n,_,_,c - // rank3: X = n,_,w,c - - if (data.inputRank == 1) // TensorShape(X.flatHeight, depth) - { - int j = idx % data.depth; - int n = (idx / data.depth) % data.shapeX.flatHeight; - - int index = (int)Xptr[n]; - float v = (j == index) ? data.onValue: data.offValue; - Optr[idx] = (half)(v); - } - else if (data.inputRank == 2) // TensorShape(X.flatHeight, 1, depth, X.channels)); - { - int i = idx % data.shapeX.channels; - int j = (idx / data.shapeX.channels) % data.depth; - int n = ((idx / data.shapeX.channels) / data.depth) % data.shapeX.flatHeight; - - int index = (int)Xptr[data.shapeX.Index(n, i)]; - float v = (j == index) ? data.onValue: data.offValue; - Optr[idx] = (half)(v); - } - else // TensorShape(X.batch, X.width, depth, X.channels)) - { - int i = idx % data.shapeX.channels; - int j = (idx / data.shapeX.channels) % data.depth; - int k = ((idx / data.shapeX.channels) / data.depth) % data.shapeX.width; - int n = (((idx / data.shapeX.channels) / data.depth) / data.shapeX.width) % data.shapeX.batch; - - int index = (int)Xptr[data.shapeX.Index(n, 0, k, i)]; - float v = (j == index) ? data.onValue: data.offValue; - Optr[idx] = (half)(v); - } - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct RandomNormalJob_Full_Half : IJobParallelFor, IJobResourceDeclarationO - { - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public RandomNormalJobHelper data; - - float Gaussian(float mean, float stdDev) - { - float u, v, s; - do { - u = data.rng.NextFloat() * 2 - 1; - v = data.rng.NextFloat() * 2 - 1; - s = u * u + v * v; - } while (s >= 1 || s == 0); - float mul = Mathf.Sqrt(-2.0f * Mathf.Log(s) / s); - return mean + stdDev * u * mul; - } - - public void Execute(int i) - { - Optr[i] = (half)(Gaussian(data.mean, data.scale)); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct RandomUniformJob_Full_Half : IJobParallelFor, IJobResourceDeclarationO - { - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public RandomUniformJobHelper data; - - public void Execute(int i) - { - float v = data.mean + data.scale * data.rng.NextFloat(); - Optr[i] = (half)(v); - } - } - - #endregion -} -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Other.gen.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Other.gen.cs.meta deleted file mode 100644 index ef98658..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Other.gen.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 30d1de61c64693a4895a66fecf45a004 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Reduce.gen.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Reduce.gen.cs deleted file mode 100644 index 3e71a11..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Reduce.gen.cs +++ /dev/null @@ -1,890 +0,0 @@ -// This is auto-generated -- do not modify directly -using UnityEngine; -using System; -using Unity.Burst; -using Unity.Burst.Intrinsics; -using Unity.Collections; -using Unity.Jobs; -using Unity.Mathematics; -using static Unity.Burst.Intrinsics.X86.Avx; -using static Unity.Burst.Intrinsics.X86.Fma; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs.LowLevel.Unsafe; -using FencingHelperMode = Unity.Barracuda.BurstSchedulingHelper.FencingHelperMode; - -namespace Unity.Barracuda { -public partial class BurstCPUOps -{ - #region Reduce jobs declaration for mode: _Full_Float - - internal partial struct ReduceMaxJobHelper - { - public JobHandle ScheduleXO(BurstTensorData pinX, FencedMemoryAlloc pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ReduceMaxJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ReduceMaxJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - internal partial struct ReduceMaxJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ReduceMaxJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ReduceMaxJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ReduceMaxJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ReduceMaxJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float maxV = float.MinValue; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - maxV = math.max(maxV, v); - } - Optr[y * data.offsetReduce + x] = (float)maxV; - } - } - - internal partial struct ReduceSumJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ReduceSumJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ReduceSumJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ReduceSumJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ReduceSumJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float sumV = 0; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - sumV += v; - } - Optr[y * data.offsetReduce + x] = (float)(sumV); - } - } - - internal partial struct ReduceMeanJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new ReduceMeanJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new ReduceMeanJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ReduceMeanJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ReduceMeanJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float sumV = 0; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - sumV += v; - } - Optr[y * data.offsetReduce + x] = (float)(sumV / (float)data.reduceDim); - } - } - - internal partial struct ExpBiasReduceJobHelper - { - public JobHandle ScheduleXBO(BurstTensorData pinX, FencedMemoryAlloc pinB, FencedMemoryAlloc pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinB.type == DataType.Half; - bool OHalf = pinO.type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf && WHalf) - { - var job = new ExpBiasReduceJob_Full_Half(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && WHalf) - { - var job = new ExpBiasReduceJob_ActAsFloat_WeightAsHalf(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && !WHalf) - { - var job = new ExpBiasReduceJob_Full_Float(); - job.data = this; - return job.ScheduleXBO(pinX, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (AHalf && !WHalf) - { - UnityEngine.Assertions.Assert.IsTrue(false, "ExpBiasReduceJob does not support activation as half while weights are floats."); - return new JobHandle(); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ExpBiasReduceJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ExpBiasReduceJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float accum = 0.0f; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - float b = Bptr[y * data.offsetReduce + x]; - accum += math.exp(v - b); - } - Optr[y * data.offsetReduce + x] = (float)accum; - } - } - - internal partial struct SoftmaxEndJobHelper - { - public JobHandle ScheduleXSBO(BurstTensorData pinX, FencedMemoryAlloc pinS, FencedMemoryAlloc pinB, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinS.type == DataType.Half; - bool BHalf = pinB.type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(WHalf, BHalf); - if (AHalf && WHalf) - { - var job = new SoftmaxEndJob_Full_Half(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && WHalf) - { - var job = new SoftmaxEndJob_ActAsFloat_WeightAsHalf(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && !WHalf) - { - var job = new SoftmaxEndJob_Full_Float(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (AHalf && !WHalf) - { - UnityEngine.Assertions.Assert.IsTrue(false, "SoftmaxEndJob does not support activation as half while weights are floats."); - return new JobHandle(); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SoftmaxEndJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } float* Sptr => S.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SoftmaxEndJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = ((i / data.offsetReduce) % data.reduceDim); - int z = ((i / data.offsetReduce) / data.reduceDim); - - Optr[i] = (float)(math.exp(Xptr[i] - Bptr[z * data.offsetReduce + x]) / Sptr[z * data.offsetReduce + x]); - } - } - - internal partial struct LogSoftmaxEndJobHelper - { - public JobHandle ScheduleXSBO(BurstTensorData pinX, FencedMemoryAlloc pinS, FencedMemoryAlloc pinB, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool WHalf = pinS.type == DataType.Half; - bool BHalf = pinB.type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - UnityEngine.Assertions.Assert.AreEqual(WHalf, BHalf); - if (AHalf && WHalf) - { - var job = new LogSoftmaxEndJob_Full_Half(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && WHalf) - { - var job = new LogSoftmaxEndJob_ActAsFloat_WeightAsHalf(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else if (!AHalf && !WHalf) - { - var job = new LogSoftmaxEndJob_Full_Float(); - job.data = this; - return job.ScheduleXSBO(pinX, pinS, pinB, pinO, arrayLength, innerBatchCount, fencingMode); - } - else //if (AHalf && !WHalf) - { - UnityEngine.Assertions.Assert.IsTrue(false, "LogSoftmaxEndJob does not support activation as half while weights are floats."); - return new JobHandle(); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct LogSoftmaxEndJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } float* Sptr => S.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public LogSoftmaxEndJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = ((i / data.offsetReduce) % data.reduceDim); - int z = ((i / data.offsetReduce) / data.reduceDim); - - Optr[i] = (float)((Xptr[i] - Bptr[z * data.offsetReduce + x]) - math.log(Sptr[z * data.offsetReduce + x])); - } - } - - internal partial struct MaxPool2DJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new MaxPool2DJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new MaxPool2DJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct MaxPool2DJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public MaxPool2DJobHelper data; - - const int unrollSize = 16; - public void Execute(int y) - { - int accumulatorMemSize = data.inChannels * sizeof(float); - float* outputAccumulators = (float*)UnsafeUtility.Malloc(accumulatorMemSize, JobsUtility.CacheLineSize, Allocator.TempJob); - for (int n = 0; n < data.outBatch; ++n) - for (int x = 0; x < data.outWidth; ++x) - { - bool firstNotRejectedPixelInKernel = true; - // gather max results in accumulators - for (int dy = 0; dy < data.kernelHeight; ++dy) - { - int readY = y * data.strideY + dy - data.padY; - if (readY < 0) continue; - if (readY >= data.inHeight) continue; - - for (int dx = 0; dx < data.kernelWidth; ++dx) - { - int readX = x * data.strideX + dx - data.padY; - if (readX < 0) continue; - if (readX >= data.inWidth) continue; - - float* dst = outputAccumulators; - float* src = Xptr + n * data.inStrideN + readY * data.inStrideH + readX * data.inStrideW; - - int k = 0; - if (firstNotRejectedPixelInKernel) // first pass, write-through - { - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst = *src; - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst = *src; - } - else - { - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst = (*dst) > (*src) ? (*dst) : (*src); - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst = (*dst) > (*src) ? (*dst) : (*src); - } - firstNotRejectedPixelInKernel = false; - } - } - - // safety net, if kernel was completely outside of X - // fill with padding_value (0) to avoid uninitialized memory - if (firstNotRejectedPixelInKernel) - UnsafeUtility.MemClear(outputAccumulators, accumulatorMemSize); - - { // write accumulators to memory - int k = 0; - float* src = outputAccumulators; - float* dst = Optr + n * data.outStrideN + y * data.outStrideH + x * data.outStrideW; - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst = *src; - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst = *src; - } - } - - UnsafeUtility.Free(outputAccumulators, Allocator.TempJob); - } - } - - internal partial struct AvgPool2DJobHelper - { - public JobHandle ScheduleXO(Tensor X, Tensor O, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - return ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - public JobHandle ScheduleXO(BurstTensorData pinX, BurstTensorData pinO, int arrayLength, int innerBatchCount, FencingHelperMode fencingMode=FencingHelperMode.UpdateResourcesFencesOnScheduling) - { - bool AHalf = pinX.array.Type == DataType.Half; - bool OHalf = pinO.array.Type == DataType.Half; - UnityEngine.Assertions.Assert.AreEqual(AHalf, OHalf); - if (AHalf) - { - var job = new AvgPool2DJob_Full_Half(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - else - { - var job = new AvgPool2DJob_Full_Float(); - job.data = this; - return job.ScheduleXO(pinX, pinO, arrayLength, innerBatchCount, fencingMode); - } - } - } - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct AvgPool2DJob_Full_Float : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public AvgPool2DJobHelper data; - - const int unrollSize = 16; - public void Execute(int y) - { - int accumulatorMemSize = data.inChannels * sizeof(float); - float* outputAccumulators = (float*)UnsafeUtility.Malloc(accumulatorMemSize, JobsUtility.CacheLineSize, Allocator.TempJob); - - for (int n = 0; n < data.outBatch; ++n) - for (int x = 0; x < data.outWidth; ++x) - { - // reset accumulators & counter - int counter = 0; - UnsafeUtility.MemClear(outputAccumulators, accumulatorMemSize); - - // gather sums in accumulators - for (int dy = 0; dy < data.kernelHeight; ++dy) - { - int readY = y * data.strideY + dy - data.padY; - if (readY < 0) continue; - if (readY >= data.inHeight) continue; - - for (int dx = 0; dx < data.kernelWidth; ++dx) - { - int readX = x * data.strideX + dx - data.padY; - if (readX < 0) continue; - if (readX >= data.inWidth) continue; - - float* dst = outputAccumulators; - float* src = Xptr + n * data.inStrideN + readY * data.inStrideH + readX * data.inStrideW; - - int k = 0; - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst += *src; - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst += *src; - counter++; - } - } - - // safety net, if kernel was completely outside of X - counter = math.max(1, counter); - - { // write accumulators to memory - int k = 0; - float invCounter = 1f / counter; - float* src = outputAccumulators; - float* dst = Optr + n * data.outStrideN + y * data.outStrideH + x * data.outStrideW; - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst = (float)(*src * invCounter); - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst = (float)(*src * invCounter); - } - } - - UnsafeUtility.Free(outputAccumulators, Allocator.TempJob); - } - } - - #endregion - #region Reduce jobs declaration for mode: _ActAsFloat_WeightAsHalf - - - - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ExpBiasReduceJob_ActAsFloat_WeightAsHalf : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public ExpBiasReduceJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float accum = 0.0f; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - float b = Bptr[y * data.offsetReduce + x]; - accum += math.exp(v - b); - } - Optr[y * data.offsetReduce + x] = (float)accum; - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SoftmaxEndJob_ActAsFloat_WeightAsHalf : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public SoftmaxEndJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = ((i / data.offsetReduce) % data.reduceDim); - int z = ((i / data.offsetReduce) / data.reduceDim); - - Optr[i] = (float)(math.exp(Xptr[i] - Bptr[z * data.offsetReduce + x]) / Sptr[z * data.offsetReduce + x]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct LogSoftmaxEndJob_ActAsFloat_WeightAsHalf : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - public LogSoftmaxEndJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = ((i / data.offsetReduce) % data.reduceDim); - int z = ((i / data.offsetReduce) / data.reduceDim); - - Optr[i] = (float)((Xptr[i] - Bptr[z * data.offsetReduce + x]) - math.log(Sptr[z * data.offsetReduce + x])); - } - } - - - - #endregion - #region Reduce jobs declaration for mode: _Full_Half - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ReduceMaxJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ReduceMaxJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float maxV = float.MinValue; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - maxV = math.max(maxV, v); - } - Optr[y * data.offsetReduce + x] = (half)maxV; - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ReduceSumJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ReduceSumJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float sumV = 0; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - sumV += v; - } - Optr[y * data.offsetReduce + x] = (half)(sumV); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ReduceMeanJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ReduceMeanJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float sumV = 0; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - sumV += v; - } - Optr[y * data.offsetReduce + x] = (half)(sumV / (float)data.reduceDim); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ExpBiasReduceJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public ExpBiasReduceJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = i / data.offsetReduce; - - float accum = 0.0f; - for (int z = 0; z < data.reduceDim; ++z) - { - float v = Xptr[y * data.offsetReduce * data.reduceDim + z * data.offsetReduce + x]; - float b = Bptr[y * data.offsetReduce + x]; - accum += math.exp(v - b); - } - Optr[y * data.offsetReduce + x] = (half)accum; - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct SoftmaxEndJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public SoftmaxEndJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = ((i / data.offsetReduce) % data.reduceDim); - int z = ((i / data.offsetReduce) / data.reduceDim); - - Optr[i] = (half)(math.exp(Xptr[i] - Bptr[z * data.offsetReduce + x]) / Sptr[z * data.offsetReduce + x]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct LogSoftmaxEndJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXSBO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadOnlyMemResource S { get; set; } half* Sptr => S.ptrhalf; - public ReadOnlyMemResource B { get; set; } half* Bptr => B.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public LogSoftmaxEndJobHelper data; - - public void Execute(int i) - { - int x = i % data.offsetReduce; - int y = ((i / data.offsetReduce) % data.reduceDim); - int z = ((i / data.offsetReduce) / data.reduceDim); - - Optr[i] = (half)((Xptr[i] - Bptr[z * data.offsetReduce + x]) - math.log(Sptr[z * data.offsetReduce + x])); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct MaxPool2DJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public MaxPool2DJobHelper data; - - const int unrollSize = 16; - public void Execute(int y) - { - int accumulatorMemSize = data.inChannels * sizeof(half); - half* outputAccumulators = (half*)UnsafeUtility.Malloc(accumulatorMemSize, JobsUtility.CacheLineSize, Allocator.TempJob); - for (int n = 0; n < data.outBatch; ++n) - for (int x = 0; x < data.outWidth; ++x) - { - bool firstNotRejectedPixelInKernel = true; - // gather max results in accumulators - for (int dy = 0; dy < data.kernelHeight; ++dy) - { - int readY = y * data.strideY + dy - data.padY; - if (readY < 0) continue; - if (readY >= data.inHeight) continue; - - for (int dx = 0; dx < data.kernelWidth; ++dx) - { - int readX = x * data.strideX + dx - data.padY; - if (readX < 0) continue; - if (readX >= data.inWidth) continue; - - half* dst = outputAccumulators; - half* src = Xptr + n * data.inStrideN + readY * data.inStrideH + readX * data.inStrideW; - - int k = 0; - if (firstNotRejectedPixelInKernel) // first pass, write-through - { - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst = *src; - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst = *src; - } - else - { - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst = (*dst) > (*src) ? (*dst) : (*src); - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst = (*dst) > (*src) ? (*dst) : (*src); - } - firstNotRejectedPixelInKernel = false; - } - } - - // safety net, if kernel was completely outside of X - // fill with padding_value (0) to avoid uninitialized memory - if (firstNotRejectedPixelInKernel) - UnsafeUtility.MemClear(outputAccumulators, accumulatorMemSize); - - { // write accumulators to memory - int k = 0; - half* src = outputAccumulators; - half* dst = Optr + n * data.outStrideN + y * data.outStrideH + x * data.outStrideW; - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst = *src; - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst = *src; - } - } - - UnsafeUtility.Free(outputAccumulators, Allocator.TempJob); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct AvgPool2DJob_Full_Half : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - public AvgPool2DJobHelper data; - - const int unrollSize = 16; - public void Execute(int y) - { - int accumulatorMemSize = data.inChannels * sizeof(half); - half* outputAccumulators = (half*)UnsafeUtility.Malloc(accumulatorMemSize, JobsUtility.CacheLineSize, Allocator.TempJob); - - for (int n = 0; n < data.outBatch; ++n) - for (int x = 0; x < data.outWidth; ++x) - { - // reset accumulators & counter - int counter = 0; - UnsafeUtility.MemClear(outputAccumulators, accumulatorMemSize); - - // gather sums in accumulators - for (int dy = 0; dy < data.kernelHeight; ++dy) - { - int readY = y * data.strideY + dy - data.padY; - if (readY < 0) continue; - if (readY >= data.inHeight) continue; - - for (int dx = 0; dx < data.kernelWidth; ++dx) - { - int readX = x * data.strideX + dx - data.padY; - if (readX < 0) continue; - if (readX >= data.inWidth) continue; - - half* dst = outputAccumulators; - half* src = Xptr + n * data.inStrideN + readY * data.inStrideH + readX * data.inStrideW; - - int k = 0; - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst += *src; - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst += *src; - counter++; - } - } - - // safety net, if kernel was completely outside of X - counter = math.max(1, counter); - - { // write accumulators to memory - int k = 0; - float invCounter = 1f / counter; - half* src = outputAccumulators; - half* dst = Optr + n * data.outStrideN + y * data.outStrideH + x * data.outStrideW; - for (; k < data.inChannels - unrollSize + 1; k += unrollSize) // unroll of inChannels loop - for (int q = 0; q < unrollSize; q++, src++, dst++) - *dst = (half)(*src * invCounter); - for (; k < data.inChannels; k++, src++, dst++) // remainder of inChannels loop - *dst = (half)(*src * invCounter); - } - } - - UnsafeUtility.Free(outputAccumulators, Allocator.TempJob); - } - } - - #endregion -} -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Reduce.gen.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Reduce.gen.cs.meta deleted file mode 100644 index 61929bf..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.Reduce.gen.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f555ca3db5aa9674f9cdba4d5b715e79 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.cs deleted file mode 100644 index da22b24..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.cs +++ /dev/null @@ -1,1646 +0,0 @@ -using UnityEngine; -using System; -using System.Collections.Generic; -using System.Threading; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Burst; -using Unity.Jobs; -using Unity.Jobs.LowLevel.Unsafe; -using Unity.Mathematics; - -[assembly: BurstCompile(OptimizeFor = OptimizeFor.FastCompilation)] -namespace Unity.Barracuda { - -// BarracudaBurstCPU.Core.cs -- definition of class BurstCPUOps, Pin(), BurstTensorData -// BarracudaBurstCPU.Ops.cs -- impl. IOps, job schedulers -// BarracudaBurstCPU.Jobs.cs -- impl. jobs - -public partial class BurstCPUOps -{ - internal static readonly Thread MainThread = Thread.CurrentThread; - - #region Job resources declaration - - internal unsafe struct ReadOnlyMemResource - { - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public void* ptr; - public float* ptrfloat { get { return (float*)ptr; } } - public half* ptrhalf { get { return (half*)ptr; } } - } - - internal unsafe struct ReadWriteMemResource - { - [NoAlias][NativeDisableUnsafePtrRestriction] public void* ptr; - public float* ptrfloat { get { return (float*)ptr; } } - public half* ptrhalf { get { return (half*)ptr; } } - } - - internal interface IJobResourceDeclarationO - { - ReadWriteMemResource O { get; set; } - } - - internal interface IJobResourceDeclarationXO - { - ReadOnlyMemResource X { get; set; } - ReadWriteMemResource O { get; set; } - } - - internal interface IJobResourceDeclarationXBO - { - ReadOnlyMemResource X { get; set; } - ReadOnlyMemResource B { get; set; } - ReadWriteMemResource O { get; set; } - } - - internal interface IJobResourceDeclarationXSBO - { - ReadOnlyMemResource X { get; set; } - ReadOnlyMemResource S { get; set; } - ReadOnlyMemResource B { get; set; } - ReadWriteMemResource O { get; set; } - } - - #endregion - - #region Job inner data declaration - - internal partial struct HardSigmoidJobHelper - { - [ReadOnly] public float alpha, beta; - } - - internal partial struct ClipJobHelper - { - [ReadOnly] public float min, max; - } - - internal partial struct PowJobHelper - { - [ReadOnly] public float alpha; - } - - internal partial struct EluJobHelper - { - [ReadOnly] public float alpha; - } - - internal partial struct SeluJobHelper - { - [ReadOnly] public float alpha, gamma; - } - - internal partial struct PReluJobHelper - { - [ReadOnly] public int inOutChannels; - [ReadOnly] public int isGammaAVector; //1 if true, 0 if false - } - - internal partial struct LeakyReluJobHelper - { - // from Theano impl - // https://github.com/Theano/theano/blob/d395439aec5a6ddde8ef5c266fd976412a5c5695/theano/tensor/nnet/nnet.py#L2209-L2251 - [ReadOnly] public float f1, f2, alpha_; - public float alpha { get { return alpha_; } set { - alpha_ = value; - f1 = 0.5f * (1f + alpha_); - f2 = 0.5f * (1f - alpha_); - } } - } - - internal partial struct CopyJobHelper - { - [ReadOnly] public int length; - } - - internal partial struct CopyStrideJobHelper - { - [ReadOnly] public int XStride; - [ReadOnly] public int OStride; - [ReadOnly] public int count; - [ReadOnly] public int length; - } - - internal partial struct GenericSliceJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public int strideS, strideR, strideN, strideT; - [ReadOnly] public int strideD, strideH, strideW, strideC; - [ReadOnly] public int startS, startR, startN, startT; - [ReadOnly] public int startD, startH, startW, startC; - } - - internal partial struct GenericStridedSliceJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public int strideS, strideR, strideN, strideT; - [ReadOnly] public int strideD, strideH, strideW, strideC; - [ReadOnly] public int startS, startR, startN, startT; - [ReadOnly] public int startD, startH, startW, startC; - } - - internal partial struct Border2DJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public int PadWidth; - [ReadOnly] public int PadHeight; - [ReadOnly] public int PadChannels; - [ReadOnly] public int CroppedWidth; - [ReadOnly] public int CroppedHeight; - [ReadOnly] public int CroppedChannels; - [ReadOnly] public float Beta; - } - - internal unsafe partial struct TransposeJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public fixed int permutations[8]; - } - - internal partial struct Pad2DEdgeJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public int PadWidth; - [ReadOnly] public int PadHeight; - [ReadOnly] public int PadChannels; - } - - internal partial struct Pad2DReflectJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public int PadWidth; - [ReadOnly] public int PadHeight; - [ReadOnly] public int PadChannels; - } - - internal partial struct Pad2DSymmetricJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public int PadWidth; - [ReadOnly] public int PadHeight; - [ReadOnly] public int PadChannels; - } - - internal partial struct TileJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - } - - internal partial struct GatherJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public int axis; - } - - internal partial struct OneHotJobHelper - { - [ReadOnly] public TensorShape shapeO; - [ReadOnly] public TensorShape shapeX; - [ReadOnly] public int depth; - [ReadOnly] public int inputRank; - [ReadOnly] public float onValue; - [ReadOnly] public float offValue; - } - - internal partial struct RandomNormalJobHelper - { - public Unity.Mathematics.Random rng; - public float mean; - public float scale; - } - - internal partial struct RandomUniformJobHelper - { - public Unity.Mathematics.Random rng; - public float mean; - public float scale; - } - - internal partial struct TestXOJobHelper - { - public int offset; - public float bias; - } - - internal partial struct TestXBOJobHelper - { - public int offset; - } - - internal partial struct VectorBroadcastScaleBiasJobHelper - { - [ReadOnly] public int inOutChannels; - [ReadOnly] public float alpha; - } - - internal partial struct DepthwiseConv2DJobHelper - { - [ReadOnly] public int strideX, strideY, padX, padY; - [ReadOnly] public int inHeight, inWidth, inChannels, inStrideN, inStrideH, inStrideW; - [ReadOnly] public int kernelCount, kernelHeight, kernelWidth, kernelStrideH, kernelStrideW; - [ReadOnly] public int outBatch, outWidth, outStrideN, outStrideH, outStrideW; - } - - internal partial struct Dense3JobHelper - { - public int AM, AN; - public int BM, BN; - public int SM, SN; - public int dispatchThreadX, dispatchThreadY, dispatchThreadZ; - } - - internal partial struct ReduceMaxJobHelper - { - [ReadOnly] public int offsetReduce; - [ReadOnly] public int reduceDim; - } - - internal partial struct ReduceSumJobHelper - { - [ReadOnly] public int offsetReduce; - [ReadOnly] public int reduceDim; - } - - internal partial struct ReduceMeanJobHelper - { - [ReadOnly] public int offsetReduce; - [ReadOnly] public int reduceDim; - } - - internal partial struct ExpBiasReduceJobHelper - { - [ReadOnly] public int offsetReduce; - [ReadOnly] public int reduceDim; - } - - internal partial struct SoftmaxEndJobHelper - { - [ReadOnly] public int offsetReduce; - [ReadOnly] public int reduceDim; - } - - internal partial struct LogSoftmaxEndJobHelper - { - [ReadOnly] public int offsetReduce; - [ReadOnly] public int reduceDim; - } - - internal partial struct MaxPool2DJobHelper - { - [ReadOnly] public int strideX, strideY, padX, padY; - [ReadOnly] public int kernelHeight, kernelWidth; - [ReadOnly] public int inHeight, inWidth, inChannels, inStrideN, inStrideH, inStrideW; - [ReadOnly] public int outBatch, outWidth, outStrideN, outStrideH, outStrideW; - } - - internal partial struct AvgPool2DJobHelper - { - [ReadOnly] public int strideX, strideY, padX, padY; - [ReadOnly] public int kernelHeight, kernelWidth; - [ReadOnly] public int inHeight, inWidth, inChannels, inStrideN, inStrideH, inStrideW; - [ReadOnly] public int outBatch, outWidth, outStrideN, outStrideH, outStrideW; - } - - - #endregion - - - static unsafe float* AllocBlock(int blockSizeM, int blockSizeN) - { - int sz = blockSizeM * blockSizeN * sizeof(float); - // Allocator.Temp is the fastest allocator, but can only be used within jobs; No explicit need to deallocate - // Source: https://docs.unity3d.com/Packages/com.unity.collections@1.0/manual/allocation.html#allocatortemp - return (float*)UnsafeUtility.Malloc(sz, JobsUtility.CacheLineSize, Allocator.Temp); - } - - static unsafe half* AllocBlockHalf(int blockSizeM, int blockSizeN) - { - int sz = blockSizeM * blockSizeN * sizeof(half); - // Allocator.Temp is the fastest allocator, but can only be used within jobs; No explicit need to deallocate - // Source: https://docs.unity3d.com/Packages/com.unity.collections@1.0/manual/allocation.html#allocatortemp - return (half*)UnsafeUtility.Malloc(sz, JobsUtility.CacheLineSize, Allocator.Temp); - } - - static unsafe void FreeBlock(void* ptr) - { - // We are using Allocator.Temp, so there is no explicit need to deallocate - // if (ptr != null) - // UnsafeUtility.Free(ptr, Allocator.Temp); - } - - static unsafe void CopyBlock(float* blockOut, float* matrixIn, int row, int M, int col, int N, int blockSizeM, int blockSizeN) - { - var rowFinal = Math.Min(row + blockSizeM, M); - var count = Math.Min(col + blockSizeN, N) - col; - - for (var i = row; i < rowFinal; i++) - MatrixUtils.CopyFloatArray(blockOut + (i - row) * blockSizeN, matrixIn + i * N + col, count); - } - - static unsafe int CopyBlockWithPadding(float* matrixIn, int row, int M, int col, int N, float* blockOut, int blockSizeM, int blockSizeN, bool transpose = false) - { - MatrixUtils.ClearFloatArray(blockOut, 0, blockSizeM * blockSizeN); - var blockOutStride = blockSizeN; - - var rowFinal = Math.Min(row + blockSizeM, M); - var count = Math.Min(col + blockSizeN, N) - col; - - // @TODO: measure which one is better - sequential access over matrix memory or blockOut cache - if (transpose) - { - // sequential access over matrixIn, strided over blockOut - for (var j = 0; j < count; ++j) - for (var i = row; i < rowFinal; i++) - blockOut[(i - row) * blockOutStride + j] = matrixIn[i + (col + j) * M]; - } - else - for (var i = row; i < rowFinal; i++) - { - MatrixUtils.CopyFloatArray(matrixIn + i * N + col, blockOut + (i - row) * blockOutStride, count); - } - return blockOutStride; - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - internal unsafe struct MatrixMultiplyJob : IJobParallelFor - { - // Convention: M x N matrices (other areas in our code may be N x M) - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* A; - public int AM, AN; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* B; - public int BM, BN; - [NoAlias][NativeDisableUnsafePtrRestriction] public unsafe float* C; - public int CM, CN; - public bool transposeA; - public bool transposeB; - - public int blockSizeM; - public int blockSizeN; - public int blockSizeK; - - public JobHandle Schedule(JobHandle dependsOn) - { - return Schedule(blocksBatchCount:1, dependsOn); - } - - public JobHandle Schedule(int blocksBatchCount, JobHandle dependsOn) - { - if (transposeA) - { - int tmp = AM; AM = AN; AN = tmp; - } - if (transposeB) - { - int tmp = BM; BM = BN; BN = tmp; - } - - // TODO: Determine optimal kernel / block sizes for mobile/console; This code path is currently not used - // in production and instead MatrixMultiplyLegacyJob; However, this kernel size seemed to work best with - // mobile; An alternative is have codegen generate the whole job + kernel, so we can switch dynamically - // at runtime. -#if UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_PS4 || UNITY_PS5 || UNITY_XBOXONE - if (blockSizeM == 0 || blockSizeN == 0 || blockSizeK == 0) - { - blockSizeM = 64; - blockSizeN = 64; - blockSizeK = 16; - } -#else - if (blockSizeM == 0 || blockSizeN == 0 || blockSizeK == 0) - { - // Profiling across a range of matrices for best block size revealed: - // (32, 384, 16) was the best common block size for matrices <= 576 - // (32, 768, 32) for matrices > 576 and <= 1152 - // (64, 96, 32) for matrices > 1200 - int maxM = 32; - int maxN = 384; - int maxK = 16; - - if (AM > 1200) - { - maxM = 64; - maxN = 96; - maxK = 32; - } - else if (AM > 576) - { - maxM = 32; - maxN = 768; - maxK = 32; - } - - blockSizeM = Mathf.Min(AM, maxM); - - const int kernelWidth = 24; - var sizeN = Mathf.ClosestPowerOfTwo(AN); - sizeN = (sizeN / kernelWidth) * kernelWidth; - sizeN = Mathf.Max(sizeN, kernelWidth); - blockSizeN = Mathf.Min(sizeN, maxN); - - // Adjust block size down to the actual count of rows, so no allocation takes place needlessly - blockSizeK = Mathf.Min(BM, maxK); - } -#endif - - // Distribute jobs over a single axis - int longerAxis = AM; - int blockSizeForLongerAxis = blockSizeM; - if (BN > AM) - { - longerAxis = BN; blockSizeForLongerAxis = blockSizeN; - } - - var workElements = (longerAxis + blockSizeForLongerAxis - 1) / blockSizeForLongerAxis; - return IJobParallelForExtensions.Schedule(this, workElements, blocksBatchCount, dependsOn); - } - - public void Execute(int i) - { - int shorterAxis = BN; - int blockSizeForShorterAxis = blockSizeN; - if (BN > AM) - { - shorterAxis = AM; blockSizeForShorterAxis = blockSizeM; - } - - float* blockTempA = null; - float* blockTempB = null; - float* blockTempC = null; - - // this job is scheduled over the Max(AN, BM) - // need to pick the remaining (shorter) axis - for (int j = 0; j < shorterAxis; j += blockSizeForShorterAxis) - { - int rowA = (AM >= BN) ? i * blockSizeM: j; - int colB = (AM >= BN) ? j : i * blockSizeN; - - float* blockC = C + rowA * CN + colB; - int strideC = CN; - - if (rowA + blockSizeM > CM || colB + blockSizeN > CN) // copy remainder of C into zero-padded block - { - if (blockTempC == null) - blockTempC = AllocBlock(blockSizeM, blockSizeN); - blockC = blockTempC; - strideC = CopyBlockWithPadding(C, rowA, CM, colB, CN, blockC, blockSizeM, blockSizeN); - } - - for (int l = 0; l < AN; l += blockSizeK) // inner-loop - { - float* blockA = A + rowA * AN + l; - float* blockB = B + l * BN + colB; - int strideA = AN; - int strideB = BN; - - if (rowA + blockSizeM > AM || l + blockSizeK > AN || transposeA) // copy remainder of A or transposed A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlock(blockSizeM, blockSizeK); - blockA = blockTempA; - strideA = CopyBlockWithPadding(A, rowA, AM, l, AN, blockA, blockSizeM, blockSizeK, transposeA); - } - - if (colB + blockSizeN > BN || l + blockSizeK > BM || transposeB) // copy remainder of A or transposed A into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlock(blockSizeK, blockSizeN); - blockB = blockTempB; - strideB = CopyBlockWithPadding(B, l, BM, colB, BN, blockB, blockSizeK, blockSizeN, transposeB); - } - -// Use defines instead of Application.isMobilePlatform || Application.isConsolePlatform, so we don't interrupt Burst -// inlining or introduce a branch here in the inner loop -#if UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_PS4 || UNITY_PS5 || UNITY_XBOXONE - MultiplyBlockUnroll1x8(blockA, strideA, blockB, strideB, blockC, strideC, - blockSizeM, blockSizeK, Math.Min(blockSizeN, BN - colB)); -#else - MultiplyBlockUnroll3x24(blockA, strideA, blockB, strideB, blockC, strideC, - blockSizeM, blockSizeK, Math.Min(blockSizeN, BN - colB)); -#endif - } - - if (blockC == blockTempC) // copy back - CopyBlock(blockC, C, rowA, CM, colB, CN, blockSizeM, blockSizeN); - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempC); - } - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct MatrixMultiplyLegacyJob : IJobParallelFor - { - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* A; - public int AM, AN; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* B; - public int BM, BN; - [NoAlias][NativeDisableUnsafePtrRestriction] public unsafe float* C; - public int CM, CN; - public bool transposeA; - public bool transposeB; - - public const int blockSize = 16; - - public JobHandle Schedule(JobHandle dependsOn) - { - return Schedule(blocksBatchCount:1, dependsOn); - } - public JobHandle Schedule(int blocksBatchCount, JobHandle dependsOn) - { - if (transposeA) - { - int tmp = AM; AM = AN; AN = tmp; - } - if (transposeB) - { - int tmp = BM; BM = BN; BN = tmp; - } - - int n = math.max(AM, BN); - int workElements = (n + blockSize - 1) / blockSize; - return IJobParallelForExtensions.Schedule(this, workElements, blocksBatchCount, dependsOn); - } - - public void Execute(int i) - { - int bs = blockSize; - unsafe - { - float* blockTempA = null; - float* blockTempB = null; - float* blockTempC = null; - - // this job is scheduled over the Max(AN, BM) - // need to pick the remaining (shorter) axis - for (int j = 0; j < Math.Min(AM, BN); j += bs) - { - int rowA = (AM > BN) ? i * bs: j; - int colB = (AM > BN) ? j : i * bs; - - float* blockC = C + rowA * CN + colB; - int strideC = CN; - - if (rowA + bs > CM || colB + bs > CN) // copy remainder of C into zero-padded block - { - if (blockTempC == null) - blockTempC = AllocBlock(); - blockC = blockTempC; - strideC = bs; - MatrixUtils.CopyBlockWithPadding(C, rowA, CM, colB, CN, blockC, bs); - } - - for (int l = 0; l < AN; l += bs) // inner-loop - { - float* blockA = A + rowA * AN + l; - float* blockB = B + l * BN + colB; - int strideA = AN; - int strideB = BN; - - if (rowA + bs > AM || l + bs > AN || transposeA) // copy remainder of A or transposed A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlock(); - blockA = blockTempA; - strideA = bs; - MatrixUtils.CopyBlockWithPadding(A, rowA, AM, l, AN, blockA, bs, transposeA); - } - - if (colB + bs > BN || l + bs > BM || transposeB) // copy remainder of A or transposed A into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlock(); - blockB = blockTempB; - strideB = bs; - MatrixUtils.CopyBlockWithPadding(B, l, BM, colB, BN, blockB, bs, transposeB); - } - - MultiplyBlockUnrollHx16(blockA, strideA, blockB, strideB, blockC, strideC); - } - - if (blockC == blockTempC) // copy back - MatrixUtils.CopyBlockWithPadding(blockC, C, rowA, CM, colB, CN, bs); - } - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempC); - } - } - - static unsafe float* AllocBlock() - { - const int sz = blockSize * blockSize * sizeof(float); - return (float*)UnsafeUtility.Malloc(sz, JobsUtility.CacheLineSize, Allocator.TempJob); - } - - static unsafe void FreeBlock(float* ptr) - { - if (ptr != null) - UnsafeUtility.Free(ptr, Allocator.TempJob); - } - - static unsafe void MultiplyBlockUnrollHx16(float* Ap, int Astride, float* Bp, int Bstride, float* Cp, int Cstride) - { - for (int i = 0; i < blockSize; i++) - { - for (int j = 0; j < blockSize; j += 16) - { - int baseC = i * Cstride + j; - float sum0 = *(Cp + baseC + 0); - float sum1 = *(Cp + baseC + 1); - float sum2 = *(Cp + baseC + 2); - float sum3 = *(Cp + baseC + 3); - float sum4 = *(Cp + baseC + 4); - float sum5 = *(Cp + baseC + 5); - float sum6 = *(Cp + baseC + 6); - float sum7 = *(Cp + baseC + 7); - float sum8 = *(Cp + baseC + 8); - float sum9 = *(Cp + baseC + 9); - float sumA = *(Cp + baseC +10); - float sumB = *(Cp + baseC +11); - float sumC = *(Cp + baseC +12); - float sumD = *(Cp + baseC +13); - float sumE = *(Cp + baseC +14); - float sumF = *(Cp + baseC +15); - - for (int l = 0; l < blockSize; l++) - { - float A = *(Ap + i * Astride + l); - int baseB = l * Bstride + j; - - sum0 += A * (*(Bp + baseB + 0)); - sum1 += A * (*(Bp + baseB + 1)); - sum2 += A * (*(Bp + baseB + 2)); - sum3 += A * (*(Bp + baseB + 3)); - sum4 += A * (*(Bp + baseB + 4)); - sum5 += A * (*(Bp + baseB + 5)); - sum6 += A * (*(Bp + baseB + 6)); - sum7 += A * (*(Bp + baseB + 7)); - sum8 += A * (*(Bp + baseB + 8)); - sum9 += A * (*(Bp + baseB + 9)); - sumA += A * (*(Bp + baseB +10)); - sumB += A * (*(Bp + baseB +11)); - sumC += A * (*(Bp + baseB +12)); - sumD += A * (*(Bp + baseB +13)); - sumE += A * (*(Bp + baseB +14)); - sumF += A * (*(Bp + baseB +15)); - } - - *(Cp + baseC + 0) = sum0; - *(Cp + baseC + 1) = sum1; - *(Cp + baseC + 2) = sum2; - *(Cp + baseC + 3) = sum3; - *(Cp + baseC + 4) = sum4; - *(Cp + baseC + 5) = sum5; - *(Cp + baseC + 6) = sum6; - *(Cp + baseC + 7) = sum7; - *(Cp + baseC + 8) = sum8; - *(Cp + baseC + 9) = sum9; - *(Cp + baseC +10) = sumA; - *(Cp + baseC +11) = sumB; - *(Cp + baseC +12) = sumC; - *(Cp + baseC +13) = sumD; - *(Cp + baseC +14) = sumE; - *(Cp + baseC +15) = sumF; - } - } - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct MatrixMultiply3x2Job : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Aptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Cptr => O.ptrfloat; - public int AM, AN; - public int BM, BN; - public int CM, CN; - - public int dispatchThreadX, dispatchThreadY, dispatchThreadZ; - public const int blockSize = 16; - - public void Execute(int threadID) - { - - int dispatchThreadXY = dispatchThreadX * dispatchThreadY; - - int batch = (threadID / dispatchThreadXY); - int i = (threadID % dispatchThreadXY) % dispatchThreadX; - int j = (threadID % dispatchThreadXY) / dispatchThreadX; - - int batchOffSetA = (batch * AM * AN); - int batchOffSetC = (batch * CM * CN); - - int rowA = i * blockSize; - int colB = j * blockSize; - - unsafe - { - float* blockTempA = null; - float* blockTempB = null; - float* blockTempC = null; - - float* blockC = Cptr + rowA + CM * colB + batchOffSetC; - int strideC = CM; - - if (rowA + blockSize > CM || colB + blockSize > CN) // copy remainder of C into zero-padded block - { - blockTempC = AllocBlock(blockSize, blockSize); - strideC = blockSize; - blockC = blockTempC; - } - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockC[x + strideC * y] = 0.0f; - - for (int l = 0; l < AN; l += blockSize) // inner-loop - { - float* blockA = Aptr + rowA + AM * l + batchOffSetA; - float* blockB = Bptr + l * BN + colB; - int strideA = AM; - int strideB = BN; - - if (rowA + blockSize > AM || l + blockSize > AN) // copy remainder of A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlock(blockSize, blockSize); - strideA = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempA[x + blockSize * y] = ((rowA + x) < AM && (l + y < AN)) ? blockA[x + AM * y] : 0.0f; - - blockA = blockTempA; - } - - if (colB + blockSize > BN || l + blockSize > BM) // copy remainder of B into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlock(blockSize, blockSize); - strideB = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempB[x + blockSize * y] = ((colB + x) < BN && (l + y < BM)) ? blockB[x + BN * y] : 0.0f; - - blockB = blockTempB; - } - - MultiplyBlockUnrollHx16(blockA, strideA, blockB, strideB, blockC, strideC); - } - - if (blockC == blockTempC) // copy back - { - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - { - if (((rowA + x) < CM) && ((colB + y) < CN)) - Cptr[(rowA + x) + CM * (colB + y) + batchOffSetC] = blockTempC[x + blockSize * y]; - } - } - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempC); - } - } - - static void MultiplyBlockUnrollHx16(float* Ap, int Astride, float* Bp, int Bstride, float* Cp, int Cstride) - { - for (int i = 0; i < blockSize; i++) - { - float sum0 = *(Cp + i + Cstride * 0); - float sum1 = *(Cp + i + Cstride * 1); - float sum2 = *(Cp + i + Cstride * 2); - float sum3 = *(Cp + i + Cstride * 3); - float sum4 = *(Cp + i + Cstride * 4); - float sum5 = *(Cp + i + Cstride * 5); - float sum6 = *(Cp + i + Cstride * 6); - float sum7 = *(Cp + i + Cstride * 7); - float sum8 = *(Cp + i + Cstride * 8); - float sum9 = *(Cp + i + Cstride * 9); - float sumA = *(Cp + i + Cstride * 10); - float sumB = *(Cp + i + Cstride * 11); - float sumC = *(Cp + i + Cstride * 12); - float sumD = *(Cp + i + Cstride * 13); - float sumE = *(Cp + i + Cstride * 14); - float sumF = *(Cp + i + Cstride * 15); - - for (int l = 0; l < blockSize; l++) - { - float A = *(Ap + i + Astride * l); - - float B0 = *(Bp + l * Bstride + 0); - float B1 = *(Bp + l * Bstride + 1); - float B2 = *(Bp + l * Bstride + 2); - float B3 = *(Bp + l * Bstride + 3); - float B4 = *(Bp + l * Bstride + 4); - float B5 = *(Bp + l * Bstride + 5); - float B6 = *(Bp + l * Bstride + 6); - float B7 = *(Bp + l * Bstride + 7); - float B8 = *(Bp + l * Bstride + 8); - float B9 = *(Bp + l * Bstride + 9); - float BA = *(Bp + l * Bstride + 10); - float BB = *(Bp + l * Bstride + 11); - float BC = *(Bp + l * Bstride + 12); - float BD = *(Bp + l * Bstride + 13); - float BE = *(Bp + l * Bstride + 14); - float BF = *(Bp + l * Bstride + 15); - - - sum0 += A * B0; - sum1 += A * B1; - sum2 += A * B2; - sum3 += A * B3; - sum4 += A * B4; - sum5 += A * B5; - sum6 += A * B6; - sum7 += A * B7; - sum8 += A * B8; - sum9 += A * B9; - sumA += A * BA; - sumB += A * BB; - sumC += A * BC; - sumD += A * BD; - sumE += A * BE; - sumF += A * BF; - } - - *(Cp + i + Cstride * 0 ) = sum0; - *(Cp + i + Cstride * 1 ) = sum1; - *(Cp + i + Cstride * 2 ) = sum2; - *(Cp + i + Cstride * 3 ) = sum3; - *(Cp + i + Cstride * 4 ) = sum4; - *(Cp + i + Cstride * 5 ) = sum5; - *(Cp + i + Cstride * 6 ) = sum6; - *(Cp + i + Cstride * 7 ) = sum7; - *(Cp + i + Cstride * 8 ) = sum8; - *(Cp + i + Cstride * 9 ) = sum9; - *(Cp + i + Cstride * 10) = sumA; - *(Cp + i + Cstride * 11) = sumB; - *(Cp + i + Cstride * 12) = sumC; - *(Cp + i + Cstride * 13) = sumD; - *(Cp + i + Cstride * 14) = sumE; - *(Cp + i + Cstride * 15) = sumF; - } - } - } - - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct MatrixMultiply4x4Job : IJobParallelFor, IJobResourceDeclarationXBO - { - public ReadOnlyMemResource X { get; set; } float* Aptr => X.ptrfloat; - public ReadOnlyMemResource B { get; set; } float* Bptr => B.ptrfloat; - public ReadWriteMemResource O { get; set; } float* Cptr => O.ptrfloat; - public int AB0, AB1, AM, AN; - public int BB0, BB1, BM, BN; - public int CB1, CM, CN; - - public int dispatchThreadX, dispatchThreadY, dispatchThreadZ; - public const int blockSize = 16; - - public void Execute(int threadID) - { - int dispatchThreadXY = dispatchThreadX * dispatchThreadY; - - int batch1 = (threadID % CB1); - int batch0 = (threadID / CB1) / dispatchThreadXY; - int i = ((threadID / CB1) % dispatchThreadXY) % dispatchThreadX; - int j = ((threadID / CB1) % dispatchThreadXY) / dispatchThreadX; - - int batchOffSetA = ((batch0 % AB0) * AM * AN * AB1 + (batch1 % AB1)); - int batchOffSetB = ((batch0 % BB0) * BM * BN * BB1 + (batch1 % BB1)); - int batchOffSetC = (batch0 * CM * CN * CB1 + batch1); - - int rowA = i * blockSize; - int colB = j * blockSize; - - unsafe - { - float* blockTempA = null; - float* blockTempB = null; - float* blockTempC = null; - - float* blockC = Cptr + (rowA * CN + colB)*CB1 + batchOffSetC; - int strideC = CN; - int strideBatchC = CB1; - - if (rowA + blockSize > CM || colB + blockSize > CN) // copy remainder of A into zero-padded block - { - blockTempC = AllocBlock(blockSize, blockSize); - strideC = blockSize; - strideBatchC = 1; - blockC = blockTempC; - } - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockC[(x + strideC * y) * strideBatchC] = 0.0f; - - for (int l = 0; l < AN; l += blockSize) // inner-loop - { - float* blockA = Aptr + (rowA * AN + l)*AB1 + batchOffSetA; - float* blockB = Bptr + (l * BN + colB)*BB1 + batchOffSetB; - int strideA = AN; - int strideBatchA = AB1; - int strideB = BN; - int strideBatchB = BB1; - - if (rowA + blockSize > AM || l + blockSize > AN) // copy remainder of A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlock(blockSize, blockSize); - strideA = blockSize; - strideBatchA = 1; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempA[x + blockSize * y] = ((rowA + y) < AM && (l + x < AN)) ? blockA[(x + AN * y)*AB1] : 0.0f; - - blockA = blockTempA; - } - - if (colB + blockSize > BN || l + blockSize > BM) // copy remainder of A into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlock(blockSize, blockSize); - strideB = blockSize; - strideBatchB = 1; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempB[x + blockSize * y] = ((colB + x) < BN && (l + y < BM)) ? blockB[(x + BN * y)*BB1] : 0.0f; - - blockB = blockTempB; - } - - MultiplyBlockUnrollHx16(blockA, strideA, strideBatchA, blockB, strideB, strideBatchB, blockC, strideC, strideBatchC); - } - - if (blockC == blockTempC) // copy back - { - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - { - if (((rowA + y) < CM) && (colB + x < CN)) - Cptr[((rowA + y) * CN + (colB + x)) * CB1 + batchOffSetC] = blockTempC[x + blockSize * y]; - } - } - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempC); - } - } - - static void MultiplyBlockUnrollHx16(float* Ap, int Astride, int ABatchStride, float* Bp, int Bstride, int BBatchStride, float* Cp, int Cstride, int CBatchStride) - { - for (int i = 0; i < blockSize; i++) - { - float sum0 = *(Cp + (i * Cstride + 0 )*CBatchStride); - float sum1 = *(Cp + (i * Cstride + 1 )*CBatchStride); - float sum2 = *(Cp + (i * Cstride + 2 )*CBatchStride); - float sum3 = *(Cp + (i * Cstride + 3 )*CBatchStride); - float sum4 = *(Cp + (i * Cstride + 4 )*CBatchStride); - float sum5 = *(Cp + (i * Cstride + 5 )*CBatchStride); - float sum6 = *(Cp + (i * Cstride + 6 )*CBatchStride); - float sum7 = *(Cp + (i * Cstride + 7 )*CBatchStride); - float sum8 = *(Cp + (i * Cstride + 8 )*CBatchStride); - float sum9 = *(Cp + (i * Cstride + 9 )*CBatchStride); - float sumA = *(Cp + (i * Cstride + 10)*CBatchStride); - float sumB = *(Cp + (i * Cstride + 11)*CBatchStride); - float sumC = *(Cp + (i * Cstride + 12)*CBatchStride); - float sumD = *(Cp + (i * Cstride + 13)*CBatchStride); - float sumE = *(Cp + (i * Cstride + 14)*CBatchStride); - float sumF = *(Cp + (i * Cstride + 15)*CBatchStride); - - for (int l = 0; l < blockSize; l++) - { - float A = *(Ap + (i * Astride + l)*ABatchStride); - - float B0 = *(Bp + (l * Bstride + 0 )*BBatchStride); - float B1 = *(Bp + (l * Bstride + 1 )*BBatchStride); - float B2 = *(Bp + (l * Bstride + 2 )*BBatchStride); - float B3 = *(Bp + (l * Bstride + 3 )*BBatchStride); - float B4 = *(Bp + (l * Bstride + 4 )*BBatchStride); - float B5 = *(Bp + (l * Bstride + 5 )*BBatchStride); - float B6 = *(Bp + (l * Bstride + 6 )*BBatchStride); - float B7 = *(Bp + (l * Bstride + 7 )*BBatchStride); - float B8 = *(Bp + (l * Bstride + 8 )*BBatchStride); - float B9 = *(Bp + (l * Bstride + 9 )*BBatchStride); - float BA = *(Bp + (l * Bstride + 10)*BBatchStride); - float BB = *(Bp + (l * Bstride + 11)*BBatchStride); - float BC = *(Bp + (l * Bstride + 12)*BBatchStride); - float BD = *(Bp + (l * Bstride + 13)*BBatchStride); - float BE = *(Bp + (l * Bstride + 14)*BBatchStride); - float BF = *(Bp + (l * Bstride + 15)*BBatchStride); - - sum0 += A * B0; - sum1 += A * B1; - sum2 += A * B2; - sum3 += A * B3; - sum4 += A * B4; - sum5 += A * B5; - sum6 += A * B6; - sum7 += A * B7; - sum8 += A * B8; - sum9 += A * B9; - sumA += A * BA; - sumB += A * BB; - sumC += A * BC; - sumD += A * BD; - sumE += A * BE; - sumF += A * BF; - } - - *(Cp + (i * Cstride + 0 )*CBatchStride) = sum0; - *(Cp + (i * Cstride + 1 )*CBatchStride) = sum1; - *(Cp + (i * Cstride + 2 )*CBatchStride) = sum2; - *(Cp + (i * Cstride + 3 )*CBatchStride) = sum3; - *(Cp + (i * Cstride + 4 )*CBatchStride) = sum4; - *(Cp + (i * Cstride + 5 )*CBatchStride) = sum5; - *(Cp + (i * Cstride + 6 )*CBatchStride) = sum6; - *(Cp + (i * Cstride + 7 )*CBatchStride) = sum7; - *(Cp + (i * Cstride + 8 )*CBatchStride) = sum8; - *(Cp + (i * Cstride + 9 )*CBatchStride) = sum9; - *(Cp + (i * Cstride + 10)*CBatchStride) = sumA; - *(Cp + (i * Cstride + 11)*CBatchStride) = sumB; - *(Cp + (i * Cstride + 12)*CBatchStride) = sumC; - *(Cp + (i * Cstride + 13)*CBatchStride) = sumD; - *(Cp + (i * Cstride + 14)*CBatchStride) = sumE; - *(Cp + (i * Cstride + 15)*CBatchStride) = sumF; - } - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ConvertHalfToFloatJob : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } half* Xptr => X.ptrhalf; - public ReadWriteMemResource O { get; set; } float* Optr => O.ptrfloat; - - public void Execute(int threadID) - { - Optr[threadID] = (float)(Xptr[threadID]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ConvertFloatToHalfJob : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } float* Xptr => X.ptrfloat; - public ReadWriteMemResource O { get; set; } half* Optr => O.ptrhalf; - - public void Execute(int threadID) - { - Optr[threadID] = (half)(Xptr[threadID]); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct Im2ColSliceJob : IJobParallelFor, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } - public ReadWriteMemResource O { get; set; } - [ReadOnly] public int inOutBatch, inOutChannels; - [ReadOnly] public int inHeight, inStrideN, inStrideH, inStrideW; - [ReadOnly] public int outWidth, outStrideN, outStrideH; - [ReadOnly] public int strideX, strideY, offsetY; - [ReadOnly] public int padLeft, padRight, skipFromInputRow, copyFromInputRow; - public void Execute(int y) - { - for (int n = 0; n < inOutBatch; ++n) - { - int readY = strideY * y + offsetY; - float* from = X.ptrfloat + n * inStrideN + readY * inStrideH + skipFromInputRow * inStrideW; - float* to = O.ptrfloat + n * outStrideN + y * outStrideH; - - if (readY < 0 || - readY >= inHeight) - { - // pad-0 top or bottom line, len = outWidth - UnsafeUtility.MemClear(destination: to, - size: inOutChannels * outWidth * sizeof(float)); - to += inOutChannels * outWidth; - } - else - { - // pad-0 left, len = padLeft - UnsafeUtility.MemClear(destination: to, - size: inOutChannels * padLeft * sizeof(float)); - to += inOutChannels * padLeft; - - // copy from X with stride, if necessary - if (strideX == 1) - { - UnsafeUtility.MemCpy(destination: to, - source: from, - size: inOutChannels * copyFromInputRow * sizeof(float)); - to += inOutChannels * copyFromInputRow; - } - else - { - UnsafeUtility.MemCpyStride(destination: to, destinationStride: inOutChannels * sizeof(float), - source: from, sourceStride: strideX * inOutChannels * sizeof(float), - elementSize: inOutChannels * sizeof(float), - count: copyFromInputRow); - to += inOutChannels * copyFromInputRow; - } - - // pad-0 right, len = padRight - UnsafeUtility.MemClear(destination: to, - size: inOutChannels * padRight * sizeof(float)); - to += inOutChannels * padRight; - } - } - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct ZeroBroadcastJob : IJob, IJobResourceDeclarationO - { - public ReadWriteMemResource O { get; set; } - [ReadOnly] public int repeat; - public void Execute() - { - UnsafeUtility.MemClear(destination: O.ptr, size: repeat * sizeof(float)); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct VectorBroadcastJob : IJob, IJobResourceDeclarationXO - { - public ReadOnlyMemResource X { get; set; } - public ReadWriteMemResource O { get; set; } - [ReadOnly] public int channels; - [ReadOnly] public int repeat; - public void Execute() - { - UnsafeUtility.MemCpyReplicate(destination: O.ptr, - source: X.ptr, - size: channels * sizeof(float), - count: repeat); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct MemFreeJob : IJob - { - [NoAlias] [NativeDisableUnsafePtrRestriction] public void* buffer0; - [NoAlias] [NativeDisableUnsafePtrRestriction] public void* buffer1; - [ReadOnly] public Allocator allocator; - public void Execute() - { - if (buffer0 != null) - UnsafeUtility.Free(buffer0, allocator); - if (buffer1 != null) - UnsafeUtility.Free(buffer1, allocator); - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Default, FloatPrecision = FloatPrecision.Standard)] - unsafe struct LSTMEndJob : IJobParallelFor - { - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* i_mad_w; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* j_mad_w; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* f_mad_w; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* o_mad_w; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* i_mad_r; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* j_mad_r; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* f_mad_r; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* o_mad_r; - - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* cell; - - [NoAlias][NativeDisableUnsafePtrRestriction] public unsafe float* O; - [NoAlias][NativeDisableUnsafePtrRestriction] public unsafe float* cell_out; - [NoAlias][NativeDisableUnsafePtrRestriction] public unsafe float* hidden_out; - - public int sequenceIndexO, sequenceIndexI; - public int batchSize, hiddenSize; - public int batchSizeR; - - public JobHandle Schedule(int arrayLength, int innerloopBatchCount, JobHandle dependsOn) - { - return IJobParallelForExtensions.Schedule(this, arrayLength, innerloopBatchCount, dependsOn); - } - - public void Execute(int threadId) - { - int b_tID = (threadId / hiddenSize); - int h_tID = (threadId % hiddenSize); - int threadId_r = (b_tID % batchSizeR) * hiddenSize + h_tID; - float i_mad = i_mad_w[batchSize * hiddenSize * sequenceIndexI + threadId] + i_mad_r[threadId_r]; - float j_mad = j_mad_w[batchSize * hiddenSize * sequenceIndexI + threadId] + j_mad_r[threadId_r]; - float f_mad = f_mad_w[batchSize * hiddenSize * sequenceIndexI + threadId] + f_mad_r[threadId_r]; - float o_mad = o_mad_w[batchSize * hiddenSize * sequenceIndexI + threadId] + o_mad_r[threadId_r]; - - float i = 1f / (1f + math.exp(-i_mad)); - float j = math.tanh(j_mad); - float f = 1f / (1f + math.exp(-f_mad)); - float o = 1f / (1f + math.exp(-o_mad)); - - float state_c_mul = cell[threadId_r] * f; - float i_j_mul = i * j; - float state_c = state_c_mul + i_j_mul; - float state_c_tanh = math.tanh(state_c); - float state_h = o * state_c_tanh; - - O[batchSize * hiddenSize * sequenceIndexO + threadId] = state_h; - hidden_out[threadId] = state_h; - cell_out[threadId] = state_c; - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct LSTMDense3Job : IJobParallelFor - { - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* A; - public int AM, AN; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* B; - public int BM, BN; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* C; - public int CN; - - [NoAlias][NativeDisableUnsafePtrRestriction] public unsafe float* S; - public int SM, SN; - - public int dispatchThreadX, dispatchThreadY, dispatchThreadZ; - public const int blockSize = 16; - - public JobHandle Schedule(JobHandle dependsOn) - { - return Schedule(blocksBatchCount:1, dependsOn); - } - public JobHandle Schedule(int blocksBatchCount, JobHandle dependsOn) - { - return IJobParallelForExtensions.Schedule(this, dispatchThreadX * dispatchThreadY * dispatchThreadZ, blocksBatchCount, dependsOn); - } - - public void Execute(int threadID) - { - int dispatchThreadXY = dispatchThreadX * dispatchThreadY; - - int batch = (threadID / dispatchThreadXY); - int i = (threadID % dispatchThreadXY) % dispatchThreadX; - int j = (threadID % dispatchThreadXY) / dispatchThreadX; - - int batchOffSetA = (batch * AM * AN); - int batchOffSetS = (batch * SM * SN); - - int rowA = i * blockSize; - int colB = j * blockSize; - - unsafe - { - float* blockTempA = null; - float* blockTempB = null; - float* blockTempS = null; - - float* blockS = S + rowA * SN + colB + batchOffSetS; - int strideS = SN; - - if (rowA + blockSize > SM || colB + blockSize > SN) // copy remainder of C into zero-padded block - { - blockTempS = AllocBlock(blockSize, blockSize); - strideS = blockSize; - blockS = blockTempS; - } - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockS[x + strideS * y] = (colB + x) < BN ? C[(colB + x)%CN] : 0.0f; - - for (int l = 0; l < AN; l += blockSize) // inner-loop - { - float* blockA = A + rowA * AN + l + batchOffSetA; - float* blockB = B + l * BN + colB; - int strideA = AN; - int strideB = BN; - - if (rowA + blockSize > AM || l + blockSize > AN) // copy remainder of A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlock(blockSize, blockSize); - strideA = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempA[x + blockSize * y] = ((rowA + y) < AM && (l + x < AN)) ? blockA[x + AN * y] : 0.0f; - - blockA = blockTempA; - } - - if (colB + blockSize > BN || l + blockSize > BM) // copy remainder of B into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlock(blockSize, blockSize); - strideB = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempB[x + blockSize * y] = ((colB + x) < BN && (l + y < BM)) ? blockB[x + BN * y] : 0.0f; - - blockB = blockTempB; - } - - MultiplyBlockUnrollHx16(blockA, strideA, blockB, strideB, blockS, strideS); - } - - if (blockS == blockTempS) // copy back - { - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - { - if (((rowA + y) < SM) && ((colB + x) < SN)) - S[(rowA + y) * SN + (colB + x) + batchOffSetS] = blockTempS[x + blockSize * y]; - } - } - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempS); - } - } - - static void MultiplyBlockUnrollHx16(float* Ap, int Astride, float* Bp, int Bstride, float* Sp, int Sstride) - { - for (int i = 0; i < blockSize; i++) - { - float sum0 = *(Sp + i * Sstride + 0); - float sum1 = *(Sp + i * Sstride + 1); - float sum2 = *(Sp + i * Sstride + 2); - float sum3 = *(Sp + i * Sstride + 3); - float sum4 = *(Sp + i * Sstride + 4); - float sum5 = *(Sp + i * Sstride + 5); - float sum6 = *(Sp + i * Sstride + 6); - float sum7 = *(Sp + i * Sstride + 7); - float sum8 = *(Sp + i * Sstride + 8); - float sum9 = *(Sp + i * Sstride + 9); - float sumA = *(Sp + i * Sstride + 10); - float sumB = *(Sp + i * Sstride + 11); - float sumC = *(Sp + i * Sstride + 12); - float sumD = *(Sp + i * Sstride + 13); - float sumE = *(Sp + i * Sstride + 14); - float sumF = *(Sp + i * Sstride + 15); - - for (int l = 0; l < blockSize; l++) - { - float A = *(Ap + i * Astride + l); - - float B0 = *(Bp + l * Bstride + 0); - float B1 = *(Bp + l * Bstride + 1); - float B2 = *(Bp + l * Bstride + 2); - float B3 = *(Bp + l * Bstride + 3); - float B4 = *(Bp + l * Bstride + 4); - float B5 = *(Bp + l * Bstride + 5); - float B6 = *(Bp + l * Bstride + 6); - float B7 = *(Bp + l * Bstride + 7); - float B8 = *(Bp + l * Bstride + 8); - float B9 = *(Bp + l * Bstride + 9); - float BA = *(Bp + l * Bstride + 10); - float BB = *(Bp + l * Bstride + 11); - float BC = *(Bp + l * Bstride + 12); - float BD = *(Bp + l * Bstride + 13); - float BE = *(Bp + l * Bstride + 14); - float BF = *(Bp + l * Bstride + 15); - - - sum0 += A * B0; - sum1 += A * B1; - sum2 += A * B2; - sum3 += A * B3; - sum4 += A * B4; - sum5 += A * B5; - sum6 += A * B6; - sum7 += A * B7; - sum8 += A * B8; - sum9 += A * B9; - sumA += A * BA; - sumB += A * BB; - sumC += A * BC; - sumD += A * BD; - sumE += A * BE; - sumF += A * BF; - } - - *(Sp + i * Sstride + 0 ) = sum0; - *(Sp + i * Sstride + 1 ) = sum1; - *(Sp + i * Sstride + 2 ) = sum2; - *(Sp + i * Sstride + 3 ) = sum3; - *(Sp + i * Sstride + 4 ) = sum4; - *(Sp + i * Sstride + 5 ) = sum5; - *(Sp + i * Sstride + 6 ) = sum6; - *(Sp + i * Sstride + 7 ) = sum7; - *(Sp + i * Sstride + 8 ) = sum8; - *(Sp + i * Sstride + 9 ) = sum9; - *(Sp + i * Sstride + 10) = sumA; - *(Sp + i * Sstride + 11) = sumB; - *(Sp + i * Sstride + 12) = sumC; - *(Sp + i * Sstride + 13) = sumD; - *(Sp + i * Sstride + 14) = sumE; - *(Sp + i * Sstride + 15) = sumF; - } - } - } - - [BurstCompile(OptimizeFor = OptimizeFor.Performance, FloatMode = FloatMode.Fast, FloatPrecision = FloatPrecision.Low)] - unsafe struct LSTMDenseJob : IJobParallelFor - { - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* A; - public int AM, AN; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* B; - public int BM, BN; - [NoAlias][NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* C; - public int CN; - - [NoAlias][NativeDisableUnsafePtrRestriction] public unsafe float* S; - public int SM, SN; - - public int dispatchThreadX, dispatchThreadY; - public const int blockSize = 16; - - public JobHandle Schedule(JobHandle dependsOn) - { - return Schedule(blocksBatchCount: 1, dependsOn); - } - public JobHandle Schedule(int blocksBatchCount, JobHandle dependsOn) - { - return IJobParallelForExtensions.Schedule(this, dispatchThreadX * dispatchThreadY, blocksBatchCount, dependsOn); - } - - - public void Execute(int threadID) - { - int i = (threadID % dispatchThreadX); - int j = (threadID / dispatchThreadX); - - int rowA = i * blockSize; - int colB = j * blockSize; - - unsafe - { - float* blockTempA = null; - float* blockTempB = null; - float* blockTempS = null; - - float* blockS = S + rowA * SN + colB; - int strideS = SN; - - if (rowA + blockSize > SM || colB + blockSize > SN) // copy remainder of C into zero-padded block - { - blockTempS = AllocBlock(blockSize, blockSize); - strideS = blockSize; - blockS = blockTempS; - } - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockS[x + strideS * y] = (colB + x) < BN ? C[(colB + x)%CN] : 0.0f; - - for (int l = 0; l < AN; l += blockSize) // inner-loop - { - float* blockA = A + rowA * AN + l; - float* blockB = B + l * BN + colB; - int strideA = AN; - int strideB = BN; - - if (rowA + blockSize > AM || l + blockSize > AN) // copy remainder of A into zero-padded block - { - if (blockTempA == null) - blockTempA = AllocBlock(blockSize, blockSize); - strideA = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempA[x + blockSize * y] = ((rowA + y) < AM && (l + x < AN)) ? blockA[x + AN * y] : 0.0f; - - blockA = blockTempA; - } - - if (colB + blockSize > BN || l + blockSize > BM) // copy remainder of B into zero-padded block - { - if (blockTempB == null) - blockTempB = AllocBlock(blockSize, blockSize); - strideB = blockSize; - - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - blockTempB[x + blockSize * y] = ((colB + x) < BN && (l + y < BM)) ? blockB[x + BN * y] : 0.0f; - - blockB = blockTempB; - } - - MultiplyBlockUnrollHx16(blockA, strideA, blockB, strideB, blockS, strideS); - } - - if (blockS == blockTempS) // copy back - { - for (int y = 0; y < blockSize; y++) - for (int x = 0; x < blockSize; x++) - { - if (((rowA + y) < SM) && ((colB + x) < SN)) - S[(rowA + y) * SN + (colB + x)] = blockTempS[x + blockSize * y]; - } - } - - FreeBlock(blockTempA); - FreeBlock(blockTempB); - FreeBlock(blockTempS); - } - } - - static void MultiplyBlockUnrollHx16(float* Ap, int Astride, float* Bp, int Bstride, float* Sp, int Sstride) - { - for (int i = 0; i < blockSize; i++) - { - float sum0 = *(Sp + i * Sstride + 0); - float sum1 = *(Sp + i * Sstride + 1); - float sum2 = *(Sp + i * Sstride + 2); - float sum3 = *(Sp + i * Sstride + 3); - float sum4 = *(Sp + i * Sstride + 4); - float sum5 = *(Sp + i * Sstride + 5); - float sum6 = *(Sp + i * Sstride + 6); - float sum7 = *(Sp + i * Sstride + 7); - float sum8 = *(Sp + i * Sstride + 8); - float sum9 = *(Sp + i * Sstride + 9); - float sumA = *(Sp + i * Sstride + 10); - float sumB = *(Sp + i * Sstride + 11); - float sumC = *(Sp + i * Sstride + 12); - float sumD = *(Sp + i * Sstride + 13); - float sumE = *(Sp + i * Sstride + 14); - float sumF = *(Sp + i * Sstride + 15); - - for (int l = 0; l < blockSize; l++) - { - float A = *(Ap + i * Astride + l); - - float B0 = *(Bp + l * Bstride + 0); - float B1 = *(Bp + l * Bstride + 1); - float B2 = *(Bp + l * Bstride + 2); - float B3 = *(Bp + l * Bstride + 3); - float B4 = *(Bp + l * Bstride + 4); - float B5 = *(Bp + l * Bstride + 5); - float B6 = *(Bp + l * Bstride + 6); - float B7 = *(Bp + l * Bstride + 7); - float B8 = *(Bp + l * Bstride + 8); - float B9 = *(Bp + l * Bstride + 9); - float BA = *(Bp + l * Bstride + 10); - float BB = *(Bp + l * Bstride + 11); - float BC = *(Bp + l * Bstride + 12); - float BD = *(Bp + l * Bstride + 13); - float BE = *(Bp + l * Bstride + 14); - float BF = *(Bp + l * Bstride + 15); - - - sum0 += A * B0; - sum1 += A * B1; - sum2 += A * B2; - sum3 += A * B3; - sum4 += A * B4; - sum5 += A * B5; - sum6 += A * B6; - sum7 += A * B7; - sum8 += A * B8; - sum9 += A * B9; - sumA += A * BA; - sumB += A * BB; - sumC += A * BC; - sumD += A * BD; - sumE += A * BE; - sumF += A * BF; - } - - *(Sp + i * Sstride + 0 ) = sum0; - *(Sp + i * Sstride + 1 ) = sum1; - *(Sp + i * Sstride + 2 ) = sum2; - *(Sp + i * Sstride + 3 ) = sum3; - *(Sp + i * Sstride + 4 ) = sum4; - *(Sp + i * Sstride + 5 ) = sum5; - *(Sp + i * Sstride + 6 ) = sum6; - *(Sp + i * Sstride + 7 ) = sum7; - *(Sp + i * Sstride + 8 ) = sum8; - *(Sp + i * Sstride + 9 ) = sum9; - *(Sp + i * Sstride + 10) = sumA; - *(Sp + i * Sstride + 11) = sumB; - *(Sp + i * Sstride + 12) = sumC; - *(Sp + i * Sstride + 13) = sumD; - *(Sp + i * Sstride + 14) = sumE; - *(Sp + i * Sstride + 15) = sumF; - } - } - } -} - -} // namespace Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.cs.meta deleted file mode 100644 index 4a4ce74..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Jobs.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1f9c24a13966b425fa5bfd1a4007c3f4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.MatMul.gen.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.MatMul.gen.cs deleted file mode 100644 index b8c7636..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.MatMul.gen.cs +++ /dev/null @@ -1,4409 +0,0 @@ -// This is auto-generated -- do not modify directly -using UnityEngine; -using System; -using Unity.Burst; -using Unity.Burst.Intrinsics; -using Unity.Collections; -using Unity.Jobs; -using Unity.Mathematics; -using static Unity.Burst.Intrinsics.X86.Avx; -using static Unity.Burst.Intrinsics.X86.Fma; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs.LowLevel.Unsafe; -using FencingHelperMode = Unity.Barracuda.BurstSchedulingHelper.FencingHelperMode; - -namespace Unity.Barracuda { -public partial class BurstCPUOps -{ - static unsafe void MultiplyBlockUnroll1x8( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(8, n); - int i = 0; - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 8) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - } - } - } - - static unsafe void MultiplyBlockUnroll1x8I( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(8, n); - int i = 0; - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 8) - { - int baseC_0 = i_0 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - } - } - } - - static unsafe void MultiplyBlockUnroll1x16( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(16, n); - int i = 0; - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - sum8_0 += A_0 * B_8; - sum9_0 += A_0 * B_9; - sum10_0 += A_0 * B_10; - sum11_0 += A_0 * B_11; - sum12_0 += A_0 * B_12; - sum13_0 += A_0 * B_13; - sum14_0 += A_0 * B_14; - sum15_0 += A_0 * B_15; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - } - } - } - - static unsafe void MultiplyBlockUnroll1x16I( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(16, n); - int i = 0; - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - } - } - } - - static unsafe void MultiplyBlockUnroll2x24( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(24, n); - int i = 0; - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - sum8_0 += A_0 * B_8; - sum9_0 += A_0 * B_9; - sum10_0 += A_0 * B_10; - sum11_0 += A_0 * B_11; - sum12_0 += A_0 * B_12; - sum13_0 += A_0 * B_13; - sum14_0 += A_0 * B_14; - sum15_0 += A_0 * B_15; - sum16_0 += A_0 * B_16; - sum17_0 += A_0 * B_17; - sum18_0 += A_0 * B_18; - sum19_0 += A_0 * B_19; - sum20_0 += A_0 * B_20; - sum21_0 += A_0 * B_21; - sum22_0 += A_0 * B_22; - sum23_0 += A_0 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - } - } - } - - static unsafe void MultiplyBlockUnroll2x24I( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(24, n); - int i = 0; - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - v256 gamma_0_16 = mm256_loadu_ps(Cp + baseC_0 + 16); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - v256 gamma_1_16 = mm256_loadu_ps(Cp + baseC_1 + 16); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - v256 beta_p_16 = mm256_loadu_ps(Bp + l * Bstride + j + 16); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - gamma_0_16 = mm256_fmadd_ps(alpha_0_p, beta_p_16, gamma_0_16); - gamma_1_16 = mm256_fmadd_ps(alpha_1_p, beta_p_16, gamma_1_16); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - mm256_storeu_ps(Cp + baseC_0 + 16, gamma_0_16); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - mm256_storeu_ps(Cp + baseC_1 + 16, gamma_1_16); - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - v256 gamma_0_16 = mm256_loadu_ps(Cp + baseC_0 + 16); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - v256 beta_p_16 = mm256_loadu_ps(Bp + l * Bstride + j + 16); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_0_16 = mm256_fmadd_ps(alpha_0_p, beta_p_16, gamma_0_16); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - mm256_storeu_ps(Cp + baseC_0 + 16, gamma_0_16); - } - } - } - - static unsafe void MultiplyBlockUnroll2x32( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(32, n); - int i = 0; - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 32) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - float sum24_0 = *(Cp + baseC_0 + 24); - float sum25_0 = *(Cp + baseC_0 + 25); - float sum26_0 = *(Cp + baseC_0 + 26); - float sum27_0 = *(Cp + baseC_0 + 27); - float sum28_0 = *(Cp + baseC_0 + 28); - float sum29_0 = *(Cp + baseC_0 + 29); - float sum30_0 = *(Cp + baseC_0 + 30); - float sum31_0 = *(Cp + baseC_0 + 31); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - float sum24_1 = *(Cp + baseC_1 + 24); - float sum25_1 = *(Cp + baseC_1 + 25); - float sum26_1 = *(Cp + baseC_1 + 26); - float sum27_1 = *(Cp + baseC_1 + 27); - float sum28_1 = *(Cp + baseC_1 + 28); - float sum29_1 = *(Cp + baseC_1 + 29); - float sum30_1 = *(Cp + baseC_1 + 30); - float sum31_1 = *(Cp + baseC_1 + 31); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - float B_24 = (*(Bp + baseB + 24)); - float B_25 = (*(Bp + baseB + 25)); - float B_26 = (*(Bp + baseB + 26)); - float B_27 = (*(Bp + baseB + 27)); - float B_28 = (*(Bp + baseB + 28)); - float B_29 = (*(Bp + baseB + 29)); - float B_30 = (*(Bp + baseB + 30)); - float B_31 = (*(Bp + baseB + 31)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; - sum24_0 += A_0 * B_24; sum24_1 += A_1 * B_24; - sum25_0 += A_0 * B_25; sum25_1 += A_1 * B_25; - sum26_0 += A_0 * B_26; sum26_1 += A_1 * B_26; - sum27_0 += A_0 * B_27; sum27_1 += A_1 * B_27; - sum28_0 += A_0 * B_28; sum28_1 += A_1 * B_28; - sum29_0 += A_0 * B_29; sum29_1 += A_1 * B_29; - sum30_0 += A_0 * B_30; sum30_1 += A_1 * B_30; - sum31_0 += A_0 * B_31; sum31_1 += A_1 * B_31; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - *(Cp + baseC_0 + 24) = sum24_0; - *(Cp + baseC_0 + 25) = sum25_0; - *(Cp + baseC_0 + 26) = sum26_0; - *(Cp + baseC_0 + 27) = sum27_0; - *(Cp + baseC_0 + 28) = sum28_0; - *(Cp + baseC_0 + 29) = sum29_0; - *(Cp + baseC_0 + 30) = sum30_0; - *(Cp + baseC_0 + 31) = sum31_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - *(Cp + baseC_1 + 24) = sum24_1; - *(Cp + baseC_1 + 25) = sum25_1; - *(Cp + baseC_1 + 26) = sum26_1; - *(Cp + baseC_1 + 27) = sum27_1; - *(Cp + baseC_1 + 28) = sum28_1; - *(Cp + baseC_1 + 29) = sum29_1; - *(Cp + baseC_1 + 30) = sum30_1; - *(Cp + baseC_1 + 31) = sum31_1; - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 32) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - float sum24_0 = *(Cp + baseC_0 + 24); - float sum25_0 = *(Cp + baseC_0 + 25); - float sum26_0 = *(Cp + baseC_0 + 26); - float sum27_0 = *(Cp + baseC_0 + 27); - float sum28_0 = *(Cp + baseC_0 + 28); - float sum29_0 = *(Cp + baseC_0 + 29); - float sum30_0 = *(Cp + baseC_0 + 30); - float sum31_0 = *(Cp + baseC_0 + 31); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - float B_24 = (*(Bp + baseB + 24)); - float B_25 = (*(Bp + baseB + 25)); - float B_26 = (*(Bp + baseB + 26)); - float B_27 = (*(Bp + baseB + 27)); - float B_28 = (*(Bp + baseB + 28)); - float B_29 = (*(Bp + baseB + 29)); - float B_30 = (*(Bp + baseB + 30)); - float B_31 = (*(Bp + baseB + 31)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - sum8_0 += A_0 * B_8; - sum9_0 += A_0 * B_9; - sum10_0 += A_0 * B_10; - sum11_0 += A_0 * B_11; - sum12_0 += A_0 * B_12; - sum13_0 += A_0 * B_13; - sum14_0 += A_0 * B_14; - sum15_0 += A_0 * B_15; - sum16_0 += A_0 * B_16; - sum17_0 += A_0 * B_17; - sum18_0 += A_0 * B_18; - sum19_0 += A_0 * B_19; - sum20_0 += A_0 * B_20; - sum21_0 += A_0 * B_21; - sum22_0 += A_0 * B_22; - sum23_0 += A_0 * B_23; - sum24_0 += A_0 * B_24; - sum25_0 += A_0 * B_25; - sum26_0 += A_0 * B_26; - sum27_0 += A_0 * B_27; - sum28_0 += A_0 * B_28; - sum29_0 += A_0 * B_29; - sum30_0 += A_0 * B_30; - sum31_0 += A_0 * B_31; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - *(Cp + baseC_0 + 24) = sum24_0; - *(Cp + baseC_0 + 25) = sum25_0; - *(Cp + baseC_0 + 26) = sum26_0; - *(Cp + baseC_0 + 27) = sum27_0; - *(Cp + baseC_0 + 28) = sum28_0; - *(Cp + baseC_0 + 29) = sum29_0; - *(Cp + baseC_0 + 30) = sum30_0; - *(Cp + baseC_0 + 31) = sum31_0; - } - } - } - - static unsafe void MultiplyBlockUnroll2x32I( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(32, n); - int i = 0; - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 32) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - v256 gamma_0_16 = mm256_loadu_ps(Cp + baseC_0 + 16); - v256 gamma_0_24 = mm256_loadu_ps(Cp + baseC_0 + 24); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - v256 gamma_1_16 = mm256_loadu_ps(Cp + baseC_1 + 16); - v256 gamma_1_24 = mm256_loadu_ps(Cp + baseC_1 + 24); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - v256 beta_p_16 = mm256_loadu_ps(Bp + l * Bstride + j + 16); - v256 beta_p_24 = mm256_loadu_ps(Bp + l * Bstride + j + 24); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - gamma_0_16 = mm256_fmadd_ps(alpha_0_p, beta_p_16, gamma_0_16); - gamma_1_16 = mm256_fmadd_ps(alpha_1_p, beta_p_16, gamma_1_16); - gamma_0_24 = mm256_fmadd_ps(alpha_0_p, beta_p_24, gamma_0_24); - gamma_1_24 = mm256_fmadd_ps(alpha_1_p, beta_p_24, gamma_1_24); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - mm256_storeu_ps(Cp + baseC_0 + 16, gamma_0_16); - mm256_storeu_ps(Cp + baseC_0 + 24, gamma_0_24); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - mm256_storeu_ps(Cp + baseC_1 + 16, gamma_1_16); - mm256_storeu_ps(Cp + baseC_1 + 24, gamma_1_24); - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 32) - { - int baseC_0 = i_0 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - v256 gamma_0_16 = mm256_loadu_ps(Cp + baseC_0 + 16); - v256 gamma_0_24 = mm256_loadu_ps(Cp + baseC_0 + 24); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - v256 beta_p_16 = mm256_loadu_ps(Bp + l * Bstride + j + 16); - v256 beta_p_24 = mm256_loadu_ps(Bp + l * Bstride + j + 24); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_0_16 = mm256_fmadd_ps(alpha_0_p, beta_p_16, gamma_0_16); - gamma_0_24 = mm256_fmadd_ps(alpha_0_p, beta_p_24, gamma_0_24); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - mm256_storeu_ps(Cp + baseC_0 + 16, gamma_0_16); - mm256_storeu_ps(Cp + baseC_0 + 24, gamma_0_24); - } - } - } - - static unsafe void MultiplyBlockUnroll3x16( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(16, n); - int i = 0; - for (; i < blockSizeM - 2; i += 3) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - // 2 - float sum0_2 = *(Cp + baseC_2 + 0); - float sum1_2 = *(Cp + baseC_2 + 1); - float sum2_2 = *(Cp + baseC_2 + 2); - float sum3_2 = *(Cp + baseC_2 + 3); - float sum4_2 = *(Cp + baseC_2 + 4); - float sum5_2 = *(Cp + baseC_2 + 5); - float sum6_2 = *(Cp + baseC_2 + 6); - float sum7_2 = *(Cp + baseC_2 + 7); - float sum8_2 = *(Cp + baseC_2 + 8); - float sum9_2 = *(Cp + baseC_2 + 9); - float sum10_2 = *(Cp + baseC_2 + 10); - float sum11_2 = *(Cp + baseC_2 + 11); - float sum12_2 = *(Cp + baseC_2 + 12); - float sum13_2 = *(Cp + baseC_2 + 13); - float sum14_2 = *(Cp + baseC_2 + 14); - float sum15_2 = *(Cp + baseC_2 + 15); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - float A_2 = *(Ap + i_2 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; sum0_2 += A_2 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; sum1_2 += A_2 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; sum2_2 += A_2 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; sum3_2 += A_2 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; sum4_2 += A_2 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; sum5_2 += A_2 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; sum6_2 += A_2 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; sum7_2 += A_2 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; sum8_2 += A_2 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; sum9_2 += A_2 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; sum10_2 += A_2 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; sum11_2 += A_2 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; sum12_2 += A_2 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; sum13_2 += A_2 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; sum14_2 += A_2 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; sum15_2 += A_2 * B_15; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - // 2 - *(Cp + baseC_2 + 0) = sum0_2; - *(Cp + baseC_2 + 1) = sum1_2; - *(Cp + baseC_2 + 2) = sum2_2; - *(Cp + baseC_2 + 3) = sum3_2; - *(Cp + baseC_2 + 4) = sum4_2; - *(Cp + baseC_2 + 5) = sum5_2; - *(Cp + baseC_2 + 6) = sum6_2; - *(Cp + baseC_2 + 7) = sum7_2; - *(Cp + baseC_2 + 8) = sum8_2; - *(Cp + baseC_2 + 9) = sum9_2; - *(Cp + baseC_2 + 10) = sum10_2; - *(Cp + baseC_2 + 11) = sum11_2; - *(Cp + baseC_2 + 12) = sum12_2; - *(Cp + baseC_2 + 13) = sum13_2; - *(Cp + baseC_2 + 14) = sum14_2; - *(Cp + baseC_2 + 15) = sum15_2; - } - } - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - sum8_0 += A_0 * B_8; - sum9_0 += A_0 * B_9; - sum10_0 += A_0 * B_10; - sum11_0 += A_0 * B_11; - sum12_0 += A_0 * B_12; - sum13_0 += A_0 * B_13; - sum14_0 += A_0 * B_14; - sum15_0 += A_0 * B_15; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - } - } - } - - static unsafe void MultiplyBlockUnroll3x16I( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(16, n); - int i = 0; - for (; i < blockSizeM - 2; i += 3) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - // row 2 - v256 gamma_2_0 = mm256_loadu_ps(Cp + baseC_2 + 0); - v256 gamma_2_8 = mm256_loadu_ps(Cp + baseC_2 + 8); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - v256 alpha_2_p = mm256_broadcast_ss(Ap + i_2 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_2_0 = mm256_fmadd_ps(alpha_2_p, beta_p_0, gamma_2_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - gamma_2_8 = mm256_fmadd_ps(alpha_2_p, beta_p_8, gamma_2_8); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - // row 2 - mm256_storeu_ps(Cp + baseC_2 + 0, gamma_2_0); - mm256_storeu_ps(Cp + baseC_2 + 8, gamma_2_8); - } - } - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - } - } - } - - static unsafe void MultiplyBlockUnroll3x24( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(24, n); - int i = 0; - for (; i < blockSizeM - 2; i += 3) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - // 2 - float sum0_2 = *(Cp + baseC_2 + 0); - float sum1_2 = *(Cp + baseC_2 + 1); - float sum2_2 = *(Cp + baseC_2 + 2); - float sum3_2 = *(Cp + baseC_2 + 3); - float sum4_2 = *(Cp + baseC_2 + 4); - float sum5_2 = *(Cp + baseC_2 + 5); - float sum6_2 = *(Cp + baseC_2 + 6); - float sum7_2 = *(Cp + baseC_2 + 7); - float sum8_2 = *(Cp + baseC_2 + 8); - float sum9_2 = *(Cp + baseC_2 + 9); - float sum10_2 = *(Cp + baseC_2 + 10); - float sum11_2 = *(Cp + baseC_2 + 11); - float sum12_2 = *(Cp + baseC_2 + 12); - float sum13_2 = *(Cp + baseC_2 + 13); - float sum14_2 = *(Cp + baseC_2 + 14); - float sum15_2 = *(Cp + baseC_2 + 15); - float sum16_2 = *(Cp + baseC_2 + 16); - float sum17_2 = *(Cp + baseC_2 + 17); - float sum18_2 = *(Cp + baseC_2 + 18); - float sum19_2 = *(Cp + baseC_2 + 19); - float sum20_2 = *(Cp + baseC_2 + 20); - float sum21_2 = *(Cp + baseC_2 + 21); - float sum22_2 = *(Cp + baseC_2 + 22); - float sum23_2 = *(Cp + baseC_2 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - float A_2 = *(Ap + i_2 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; sum0_2 += A_2 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; sum1_2 += A_2 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; sum2_2 += A_2 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; sum3_2 += A_2 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; sum4_2 += A_2 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; sum5_2 += A_2 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; sum6_2 += A_2 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; sum7_2 += A_2 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; sum8_2 += A_2 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; sum9_2 += A_2 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; sum10_2 += A_2 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; sum11_2 += A_2 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; sum12_2 += A_2 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; sum13_2 += A_2 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; sum14_2 += A_2 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; sum15_2 += A_2 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; sum16_2 += A_2 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; sum17_2 += A_2 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; sum18_2 += A_2 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; sum19_2 += A_2 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; sum20_2 += A_2 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; sum21_2 += A_2 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; sum22_2 += A_2 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; sum23_2 += A_2 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - // 2 - *(Cp + baseC_2 + 0) = sum0_2; - *(Cp + baseC_2 + 1) = sum1_2; - *(Cp + baseC_2 + 2) = sum2_2; - *(Cp + baseC_2 + 3) = sum3_2; - *(Cp + baseC_2 + 4) = sum4_2; - *(Cp + baseC_2 + 5) = sum5_2; - *(Cp + baseC_2 + 6) = sum6_2; - *(Cp + baseC_2 + 7) = sum7_2; - *(Cp + baseC_2 + 8) = sum8_2; - *(Cp + baseC_2 + 9) = sum9_2; - *(Cp + baseC_2 + 10) = sum10_2; - *(Cp + baseC_2 + 11) = sum11_2; - *(Cp + baseC_2 + 12) = sum12_2; - *(Cp + baseC_2 + 13) = sum13_2; - *(Cp + baseC_2 + 14) = sum14_2; - *(Cp + baseC_2 + 15) = sum15_2; - *(Cp + baseC_2 + 16) = sum16_2; - *(Cp + baseC_2 + 17) = sum17_2; - *(Cp + baseC_2 + 18) = sum18_2; - *(Cp + baseC_2 + 19) = sum19_2; - *(Cp + baseC_2 + 20) = sum20_2; - *(Cp + baseC_2 + 21) = sum21_2; - *(Cp + baseC_2 + 22) = sum22_2; - *(Cp + baseC_2 + 23) = sum23_2; - } - } - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - sum8_0 += A_0 * B_8; - sum9_0 += A_0 * B_9; - sum10_0 += A_0 * B_10; - sum11_0 += A_0 * B_11; - sum12_0 += A_0 * B_12; - sum13_0 += A_0 * B_13; - sum14_0 += A_0 * B_14; - sum15_0 += A_0 * B_15; - sum16_0 += A_0 * B_16; - sum17_0 += A_0 * B_17; - sum18_0 += A_0 * B_18; - sum19_0 += A_0 * B_19; - sum20_0 += A_0 * B_20; - sum21_0 += A_0 * B_21; - sum22_0 += A_0 * B_22; - sum23_0 += A_0 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - } - } - } - - static unsafe void MultiplyBlockUnroll3x24I( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(24, n); - int i = 0; - for (; i < blockSizeM - 2; i += 3) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - v256 gamma_0_16 = mm256_loadu_ps(Cp + baseC_0 + 16); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - v256 gamma_1_16 = mm256_loadu_ps(Cp + baseC_1 + 16); - // row 2 - v256 gamma_2_0 = mm256_loadu_ps(Cp + baseC_2 + 0); - v256 gamma_2_8 = mm256_loadu_ps(Cp + baseC_2 + 8); - v256 gamma_2_16 = mm256_loadu_ps(Cp + baseC_2 + 16); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - v256 alpha_2_p = mm256_broadcast_ss(Ap + i_2 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - v256 beta_p_16 = mm256_loadu_ps(Bp + l * Bstride + j + 16); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_2_0 = mm256_fmadd_ps(alpha_2_p, beta_p_0, gamma_2_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - gamma_2_8 = mm256_fmadd_ps(alpha_2_p, beta_p_8, gamma_2_8); - gamma_0_16 = mm256_fmadd_ps(alpha_0_p, beta_p_16, gamma_0_16); - gamma_1_16 = mm256_fmadd_ps(alpha_1_p, beta_p_16, gamma_1_16); - gamma_2_16 = mm256_fmadd_ps(alpha_2_p, beta_p_16, gamma_2_16); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - mm256_storeu_ps(Cp + baseC_0 + 16, gamma_0_16); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - mm256_storeu_ps(Cp + baseC_1 + 16, gamma_1_16); - // row 2 - mm256_storeu_ps(Cp + baseC_2 + 0, gamma_2_0); - mm256_storeu_ps(Cp + baseC_2 + 8, gamma_2_8); - mm256_storeu_ps(Cp + baseC_2 + 16, gamma_2_16); - } - } - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - v256 gamma_0_16 = mm256_loadu_ps(Cp + baseC_0 + 16); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - v256 gamma_1_16 = mm256_loadu_ps(Cp + baseC_1 + 16); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - v256 beta_p_16 = mm256_loadu_ps(Bp + l * Bstride + j + 16); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - gamma_0_16 = mm256_fmadd_ps(alpha_0_p, beta_p_16, gamma_0_16); - gamma_1_16 = mm256_fmadd_ps(alpha_1_p, beta_p_16, gamma_1_16); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - mm256_storeu_ps(Cp + baseC_0 + 16, gamma_0_16); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - mm256_storeu_ps(Cp + baseC_1 + 16, gamma_1_16); - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - v256 gamma_0_16 = mm256_loadu_ps(Cp + baseC_0 + 16); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - v256 beta_p_16 = mm256_loadu_ps(Bp + l * Bstride + j + 16); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_0_16 = mm256_fmadd_ps(alpha_0_p, beta_p_16, gamma_0_16); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - mm256_storeu_ps(Cp + baseC_0 + 16, gamma_0_16); - } - } - } - - static unsafe void MultiplyBlockUnroll3x32( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(32, n); - int i = 0; - for (; i < blockSizeM - 2; i += 3) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - - for (int j = 0; j < n; j += 32) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - float sum24_0 = *(Cp + baseC_0 + 24); - float sum25_0 = *(Cp + baseC_0 + 25); - float sum26_0 = *(Cp + baseC_0 + 26); - float sum27_0 = *(Cp + baseC_0 + 27); - float sum28_0 = *(Cp + baseC_0 + 28); - float sum29_0 = *(Cp + baseC_0 + 29); - float sum30_0 = *(Cp + baseC_0 + 30); - float sum31_0 = *(Cp + baseC_0 + 31); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - float sum24_1 = *(Cp + baseC_1 + 24); - float sum25_1 = *(Cp + baseC_1 + 25); - float sum26_1 = *(Cp + baseC_1 + 26); - float sum27_1 = *(Cp + baseC_1 + 27); - float sum28_1 = *(Cp + baseC_1 + 28); - float sum29_1 = *(Cp + baseC_1 + 29); - float sum30_1 = *(Cp + baseC_1 + 30); - float sum31_1 = *(Cp + baseC_1 + 31); - // 2 - float sum0_2 = *(Cp + baseC_2 + 0); - float sum1_2 = *(Cp + baseC_2 + 1); - float sum2_2 = *(Cp + baseC_2 + 2); - float sum3_2 = *(Cp + baseC_2 + 3); - float sum4_2 = *(Cp + baseC_2 + 4); - float sum5_2 = *(Cp + baseC_2 + 5); - float sum6_2 = *(Cp + baseC_2 + 6); - float sum7_2 = *(Cp + baseC_2 + 7); - float sum8_2 = *(Cp + baseC_2 + 8); - float sum9_2 = *(Cp + baseC_2 + 9); - float sum10_2 = *(Cp + baseC_2 + 10); - float sum11_2 = *(Cp + baseC_2 + 11); - float sum12_2 = *(Cp + baseC_2 + 12); - float sum13_2 = *(Cp + baseC_2 + 13); - float sum14_2 = *(Cp + baseC_2 + 14); - float sum15_2 = *(Cp + baseC_2 + 15); - float sum16_2 = *(Cp + baseC_2 + 16); - float sum17_2 = *(Cp + baseC_2 + 17); - float sum18_2 = *(Cp + baseC_2 + 18); - float sum19_2 = *(Cp + baseC_2 + 19); - float sum20_2 = *(Cp + baseC_2 + 20); - float sum21_2 = *(Cp + baseC_2 + 21); - float sum22_2 = *(Cp + baseC_2 + 22); - float sum23_2 = *(Cp + baseC_2 + 23); - float sum24_2 = *(Cp + baseC_2 + 24); - float sum25_2 = *(Cp + baseC_2 + 25); - float sum26_2 = *(Cp + baseC_2 + 26); - float sum27_2 = *(Cp + baseC_2 + 27); - float sum28_2 = *(Cp + baseC_2 + 28); - float sum29_2 = *(Cp + baseC_2 + 29); - float sum30_2 = *(Cp + baseC_2 + 30); - float sum31_2 = *(Cp + baseC_2 + 31); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - float A_2 = *(Ap + i_2 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - float B_24 = (*(Bp + baseB + 24)); - float B_25 = (*(Bp + baseB + 25)); - float B_26 = (*(Bp + baseB + 26)); - float B_27 = (*(Bp + baseB + 27)); - float B_28 = (*(Bp + baseB + 28)); - float B_29 = (*(Bp + baseB + 29)); - float B_30 = (*(Bp + baseB + 30)); - float B_31 = (*(Bp + baseB + 31)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; sum0_2 += A_2 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; sum1_2 += A_2 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; sum2_2 += A_2 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; sum3_2 += A_2 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; sum4_2 += A_2 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; sum5_2 += A_2 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; sum6_2 += A_2 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; sum7_2 += A_2 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; sum8_2 += A_2 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; sum9_2 += A_2 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; sum10_2 += A_2 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; sum11_2 += A_2 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; sum12_2 += A_2 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; sum13_2 += A_2 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; sum14_2 += A_2 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; sum15_2 += A_2 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; sum16_2 += A_2 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; sum17_2 += A_2 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; sum18_2 += A_2 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; sum19_2 += A_2 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; sum20_2 += A_2 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; sum21_2 += A_2 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; sum22_2 += A_2 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; sum23_2 += A_2 * B_23; - sum24_0 += A_0 * B_24; sum24_1 += A_1 * B_24; sum24_2 += A_2 * B_24; - sum25_0 += A_0 * B_25; sum25_1 += A_1 * B_25; sum25_2 += A_2 * B_25; - sum26_0 += A_0 * B_26; sum26_1 += A_1 * B_26; sum26_2 += A_2 * B_26; - sum27_0 += A_0 * B_27; sum27_1 += A_1 * B_27; sum27_2 += A_2 * B_27; - sum28_0 += A_0 * B_28; sum28_1 += A_1 * B_28; sum28_2 += A_2 * B_28; - sum29_0 += A_0 * B_29; sum29_1 += A_1 * B_29; sum29_2 += A_2 * B_29; - sum30_0 += A_0 * B_30; sum30_1 += A_1 * B_30; sum30_2 += A_2 * B_30; - sum31_0 += A_0 * B_31; sum31_1 += A_1 * B_31; sum31_2 += A_2 * B_31; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - *(Cp + baseC_0 + 24) = sum24_0; - *(Cp + baseC_0 + 25) = sum25_0; - *(Cp + baseC_0 + 26) = sum26_0; - *(Cp + baseC_0 + 27) = sum27_0; - *(Cp + baseC_0 + 28) = sum28_0; - *(Cp + baseC_0 + 29) = sum29_0; - *(Cp + baseC_0 + 30) = sum30_0; - *(Cp + baseC_0 + 31) = sum31_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - *(Cp + baseC_1 + 24) = sum24_1; - *(Cp + baseC_1 + 25) = sum25_1; - *(Cp + baseC_1 + 26) = sum26_1; - *(Cp + baseC_1 + 27) = sum27_1; - *(Cp + baseC_1 + 28) = sum28_1; - *(Cp + baseC_1 + 29) = sum29_1; - *(Cp + baseC_1 + 30) = sum30_1; - *(Cp + baseC_1 + 31) = sum31_1; - // 2 - *(Cp + baseC_2 + 0) = sum0_2; - *(Cp + baseC_2 + 1) = sum1_2; - *(Cp + baseC_2 + 2) = sum2_2; - *(Cp + baseC_2 + 3) = sum3_2; - *(Cp + baseC_2 + 4) = sum4_2; - *(Cp + baseC_2 + 5) = sum5_2; - *(Cp + baseC_2 + 6) = sum6_2; - *(Cp + baseC_2 + 7) = sum7_2; - *(Cp + baseC_2 + 8) = sum8_2; - *(Cp + baseC_2 + 9) = sum9_2; - *(Cp + baseC_2 + 10) = sum10_2; - *(Cp + baseC_2 + 11) = sum11_2; - *(Cp + baseC_2 + 12) = sum12_2; - *(Cp + baseC_2 + 13) = sum13_2; - *(Cp + baseC_2 + 14) = sum14_2; - *(Cp + baseC_2 + 15) = sum15_2; - *(Cp + baseC_2 + 16) = sum16_2; - *(Cp + baseC_2 + 17) = sum17_2; - *(Cp + baseC_2 + 18) = sum18_2; - *(Cp + baseC_2 + 19) = sum19_2; - *(Cp + baseC_2 + 20) = sum20_2; - *(Cp + baseC_2 + 21) = sum21_2; - *(Cp + baseC_2 + 22) = sum22_2; - *(Cp + baseC_2 + 23) = sum23_2; - *(Cp + baseC_2 + 24) = sum24_2; - *(Cp + baseC_2 + 25) = sum25_2; - *(Cp + baseC_2 + 26) = sum26_2; - *(Cp + baseC_2 + 27) = sum27_2; - *(Cp + baseC_2 + 28) = sum28_2; - *(Cp + baseC_2 + 29) = sum29_2; - *(Cp + baseC_2 + 30) = sum30_2; - *(Cp + baseC_2 + 31) = sum31_2; - } - } - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 32) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - float sum24_0 = *(Cp + baseC_0 + 24); - float sum25_0 = *(Cp + baseC_0 + 25); - float sum26_0 = *(Cp + baseC_0 + 26); - float sum27_0 = *(Cp + baseC_0 + 27); - float sum28_0 = *(Cp + baseC_0 + 28); - float sum29_0 = *(Cp + baseC_0 + 29); - float sum30_0 = *(Cp + baseC_0 + 30); - float sum31_0 = *(Cp + baseC_0 + 31); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - float sum24_1 = *(Cp + baseC_1 + 24); - float sum25_1 = *(Cp + baseC_1 + 25); - float sum26_1 = *(Cp + baseC_1 + 26); - float sum27_1 = *(Cp + baseC_1 + 27); - float sum28_1 = *(Cp + baseC_1 + 28); - float sum29_1 = *(Cp + baseC_1 + 29); - float sum30_1 = *(Cp + baseC_1 + 30); - float sum31_1 = *(Cp + baseC_1 + 31); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - float B_24 = (*(Bp + baseB + 24)); - float B_25 = (*(Bp + baseB + 25)); - float B_26 = (*(Bp + baseB + 26)); - float B_27 = (*(Bp + baseB + 27)); - float B_28 = (*(Bp + baseB + 28)); - float B_29 = (*(Bp + baseB + 29)); - float B_30 = (*(Bp + baseB + 30)); - float B_31 = (*(Bp + baseB + 31)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; - sum24_0 += A_0 * B_24; sum24_1 += A_1 * B_24; - sum25_0 += A_0 * B_25; sum25_1 += A_1 * B_25; - sum26_0 += A_0 * B_26; sum26_1 += A_1 * B_26; - sum27_0 += A_0 * B_27; sum27_1 += A_1 * B_27; - sum28_0 += A_0 * B_28; sum28_1 += A_1 * B_28; - sum29_0 += A_0 * B_29; sum29_1 += A_1 * B_29; - sum30_0 += A_0 * B_30; sum30_1 += A_1 * B_30; - sum31_0 += A_0 * B_31; sum31_1 += A_1 * B_31; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - *(Cp + baseC_0 + 24) = sum24_0; - *(Cp + baseC_0 + 25) = sum25_0; - *(Cp + baseC_0 + 26) = sum26_0; - *(Cp + baseC_0 + 27) = sum27_0; - *(Cp + baseC_0 + 28) = sum28_0; - *(Cp + baseC_0 + 29) = sum29_0; - *(Cp + baseC_0 + 30) = sum30_0; - *(Cp + baseC_0 + 31) = sum31_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - *(Cp + baseC_1 + 24) = sum24_1; - *(Cp + baseC_1 + 25) = sum25_1; - *(Cp + baseC_1 + 26) = sum26_1; - *(Cp + baseC_1 + 27) = sum27_1; - *(Cp + baseC_1 + 28) = sum28_1; - *(Cp + baseC_1 + 29) = sum29_1; - *(Cp + baseC_1 + 30) = sum30_1; - *(Cp + baseC_1 + 31) = sum31_1; - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 32) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - float sum24_0 = *(Cp + baseC_0 + 24); - float sum25_0 = *(Cp + baseC_0 + 25); - float sum26_0 = *(Cp + baseC_0 + 26); - float sum27_0 = *(Cp + baseC_0 + 27); - float sum28_0 = *(Cp + baseC_0 + 28); - float sum29_0 = *(Cp + baseC_0 + 29); - float sum30_0 = *(Cp + baseC_0 + 30); - float sum31_0 = *(Cp + baseC_0 + 31); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - float B_24 = (*(Bp + baseB + 24)); - float B_25 = (*(Bp + baseB + 25)); - float B_26 = (*(Bp + baseB + 26)); - float B_27 = (*(Bp + baseB + 27)); - float B_28 = (*(Bp + baseB + 28)); - float B_29 = (*(Bp + baseB + 29)); - float B_30 = (*(Bp + baseB + 30)); - float B_31 = (*(Bp + baseB + 31)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - sum8_0 += A_0 * B_8; - sum9_0 += A_0 * B_9; - sum10_0 += A_0 * B_10; - sum11_0 += A_0 * B_11; - sum12_0 += A_0 * B_12; - sum13_0 += A_0 * B_13; - sum14_0 += A_0 * B_14; - sum15_0 += A_0 * B_15; - sum16_0 += A_0 * B_16; - sum17_0 += A_0 * B_17; - sum18_0 += A_0 * B_18; - sum19_0 += A_0 * B_19; - sum20_0 += A_0 * B_20; - sum21_0 += A_0 * B_21; - sum22_0 += A_0 * B_22; - sum23_0 += A_0 * B_23; - sum24_0 += A_0 * B_24; - sum25_0 += A_0 * B_25; - sum26_0 += A_0 * B_26; - sum27_0 += A_0 * B_27; - sum28_0 += A_0 * B_28; - sum29_0 += A_0 * B_29; - sum30_0 += A_0 * B_30; - sum31_0 += A_0 * B_31; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - *(Cp + baseC_0 + 24) = sum24_0; - *(Cp + baseC_0 + 25) = sum25_0; - *(Cp + baseC_0 + 26) = sum26_0; - *(Cp + baseC_0 + 27) = sum27_0; - *(Cp + baseC_0 + 28) = sum28_0; - *(Cp + baseC_0 + 29) = sum29_0; - *(Cp + baseC_0 + 30) = sum30_0; - *(Cp + baseC_0 + 31) = sum31_0; - } - } - } - - static unsafe void MultiplyBlockUnroll4x16( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(16, n); - int i = 0; - for (; i < blockSizeM - 3; i += 4) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - var i_3 = i + 3; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - int baseC_3 = i_3 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - // 2 - float sum0_2 = *(Cp + baseC_2 + 0); - float sum1_2 = *(Cp + baseC_2 + 1); - float sum2_2 = *(Cp + baseC_2 + 2); - float sum3_2 = *(Cp + baseC_2 + 3); - float sum4_2 = *(Cp + baseC_2 + 4); - float sum5_2 = *(Cp + baseC_2 + 5); - float sum6_2 = *(Cp + baseC_2 + 6); - float sum7_2 = *(Cp + baseC_2 + 7); - float sum8_2 = *(Cp + baseC_2 + 8); - float sum9_2 = *(Cp + baseC_2 + 9); - float sum10_2 = *(Cp + baseC_2 + 10); - float sum11_2 = *(Cp + baseC_2 + 11); - float sum12_2 = *(Cp + baseC_2 + 12); - float sum13_2 = *(Cp + baseC_2 + 13); - float sum14_2 = *(Cp + baseC_2 + 14); - float sum15_2 = *(Cp + baseC_2 + 15); - // 3 - float sum0_3 = *(Cp + baseC_3 + 0); - float sum1_3 = *(Cp + baseC_3 + 1); - float sum2_3 = *(Cp + baseC_3 + 2); - float sum3_3 = *(Cp + baseC_3 + 3); - float sum4_3 = *(Cp + baseC_3 + 4); - float sum5_3 = *(Cp + baseC_3 + 5); - float sum6_3 = *(Cp + baseC_3 + 6); - float sum7_3 = *(Cp + baseC_3 + 7); - float sum8_3 = *(Cp + baseC_3 + 8); - float sum9_3 = *(Cp + baseC_3 + 9); - float sum10_3 = *(Cp + baseC_3 + 10); - float sum11_3 = *(Cp + baseC_3 + 11); - float sum12_3 = *(Cp + baseC_3 + 12); - float sum13_3 = *(Cp + baseC_3 + 13); - float sum14_3 = *(Cp + baseC_3 + 14); - float sum15_3 = *(Cp + baseC_3 + 15); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - float A_2 = *(Ap + i_2 * Astride + l); - float A_3 = *(Ap + i_3 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; sum0_2 += A_2 * B_0; sum0_3 += A_3 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; sum1_2 += A_2 * B_1; sum1_3 += A_3 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; sum2_2 += A_2 * B_2; sum2_3 += A_3 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; sum3_2 += A_2 * B_3; sum3_3 += A_3 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; sum4_2 += A_2 * B_4; sum4_3 += A_3 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; sum5_2 += A_2 * B_5; sum5_3 += A_3 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; sum6_2 += A_2 * B_6; sum6_3 += A_3 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; sum7_2 += A_2 * B_7; sum7_3 += A_3 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; sum8_2 += A_2 * B_8; sum8_3 += A_3 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; sum9_2 += A_2 * B_9; sum9_3 += A_3 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; sum10_2 += A_2 * B_10; sum10_3 += A_3 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; sum11_2 += A_2 * B_11; sum11_3 += A_3 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; sum12_2 += A_2 * B_12; sum12_3 += A_3 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; sum13_2 += A_2 * B_13; sum13_3 += A_3 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; sum14_2 += A_2 * B_14; sum14_3 += A_3 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; sum15_2 += A_2 * B_15; sum15_3 += A_3 * B_15; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - // 2 - *(Cp + baseC_2 + 0) = sum0_2; - *(Cp + baseC_2 + 1) = sum1_2; - *(Cp + baseC_2 + 2) = sum2_2; - *(Cp + baseC_2 + 3) = sum3_2; - *(Cp + baseC_2 + 4) = sum4_2; - *(Cp + baseC_2 + 5) = sum5_2; - *(Cp + baseC_2 + 6) = sum6_2; - *(Cp + baseC_2 + 7) = sum7_2; - *(Cp + baseC_2 + 8) = sum8_2; - *(Cp + baseC_2 + 9) = sum9_2; - *(Cp + baseC_2 + 10) = sum10_2; - *(Cp + baseC_2 + 11) = sum11_2; - *(Cp + baseC_2 + 12) = sum12_2; - *(Cp + baseC_2 + 13) = sum13_2; - *(Cp + baseC_2 + 14) = sum14_2; - *(Cp + baseC_2 + 15) = sum15_2; - // 3 - *(Cp + baseC_3 + 0) = sum0_3; - *(Cp + baseC_3 + 1) = sum1_3; - *(Cp + baseC_3 + 2) = sum2_3; - *(Cp + baseC_3 + 3) = sum3_3; - *(Cp + baseC_3 + 4) = sum4_3; - *(Cp + baseC_3 + 5) = sum5_3; - *(Cp + baseC_3 + 6) = sum6_3; - *(Cp + baseC_3 + 7) = sum7_3; - *(Cp + baseC_3 + 8) = sum8_3; - *(Cp + baseC_3 + 9) = sum9_3; - *(Cp + baseC_3 + 10) = sum10_3; - *(Cp + baseC_3 + 11) = sum11_3; - *(Cp + baseC_3 + 12) = sum12_3; - *(Cp + baseC_3 + 13) = sum13_3; - *(Cp + baseC_3 + 14) = sum14_3; - *(Cp + baseC_3 + 15) = sum15_3; - } - } - for (; i < blockSizeM - 2; i += 3) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - // 2 - float sum0_2 = *(Cp + baseC_2 + 0); - float sum1_2 = *(Cp + baseC_2 + 1); - float sum2_2 = *(Cp + baseC_2 + 2); - float sum3_2 = *(Cp + baseC_2 + 3); - float sum4_2 = *(Cp + baseC_2 + 4); - float sum5_2 = *(Cp + baseC_2 + 5); - float sum6_2 = *(Cp + baseC_2 + 6); - float sum7_2 = *(Cp + baseC_2 + 7); - float sum8_2 = *(Cp + baseC_2 + 8); - float sum9_2 = *(Cp + baseC_2 + 9); - float sum10_2 = *(Cp + baseC_2 + 10); - float sum11_2 = *(Cp + baseC_2 + 11); - float sum12_2 = *(Cp + baseC_2 + 12); - float sum13_2 = *(Cp + baseC_2 + 13); - float sum14_2 = *(Cp + baseC_2 + 14); - float sum15_2 = *(Cp + baseC_2 + 15); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - float A_2 = *(Ap + i_2 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; sum0_2 += A_2 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; sum1_2 += A_2 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; sum2_2 += A_2 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; sum3_2 += A_2 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; sum4_2 += A_2 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; sum5_2 += A_2 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; sum6_2 += A_2 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; sum7_2 += A_2 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; sum8_2 += A_2 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; sum9_2 += A_2 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; sum10_2 += A_2 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; sum11_2 += A_2 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; sum12_2 += A_2 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; sum13_2 += A_2 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; sum14_2 += A_2 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; sum15_2 += A_2 * B_15; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - // 2 - *(Cp + baseC_2 + 0) = sum0_2; - *(Cp + baseC_2 + 1) = sum1_2; - *(Cp + baseC_2 + 2) = sum2_2; - *(Cp + baseC_2 + 3) = sum3_2; - *(Cp + baseC_2 + 4) = sum4_2; - *(Cp + baseC_2 + 5) = sum5_2; - *(Cp + baseC_2 + 6) = sum6_2; - *(Cp + baseC_2 + 7) = sum7_2; - *(Cp + baseC_2 + 8) = sum8_2; - *(Cp + baseC_2 + 9) = sum9_2; - *(Cp + baseC_2 + 10) = sum10_2; - *(Cp + baseC_2 + 11) = sum11_2; - *(Cp + baseC_2 + 12) = sum12_2; - *(Cp + baseC_2 + 13) = sum13_2; - *(Cp + baseC_2 + 14) = sum14_2; - *(Cp + baseC_2 + 15) = sum15_2; - } - } - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - sum8_0 += A_0 * B_8; - sum9_0 += A_0 * B_9; - sum10_0 += A_0 * B_10; - sum11_0 += A_0 * B_11; - sum12_0 += A_0 * B_12; - sum13_0 += A_0 * B_13; - sum14_0 += A_0 * B_14; - sum15_0 += A_0 * B_15; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - } - } - } - - static unsafe void MultiplyBlockUnroll4x16I( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(16, n); - int i = 0; - for (; i < blockSizeM - 3; i += 4) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - var i_3 = i + 3; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - int baseC_3 = i_3 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - // row 2 - v256 gamma_2_0 = mm256_loadu_ps(Cp + baseC_2 + 0); - v256 gamma_2_8 = mm256_loadu_ps(Cp + baseC_2 + 8); - // row 3 - v256 gamma_3_0 = mm256_loadu_ps(Cp + baseC_3 + 0); - v256 gamma_3_8 = mm256_loadu_ps(Cp + baseC_3 + 8); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - v256 alpha_2_p = mm256_broadcast_ss(Ap + i_2 * Astride + l); - v256 alpha_3_p = mm256_broadcast_ss(Ap + i_3 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_2_0 = mm256_fmadd_ps(alpha_2_p, beta_p_0, gamma_2_0); - gamma_3_0 = mm256_fmadd_ps(alpha_3_p, beta_p_0, gamma_3_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - gamma_2_8 = mm256_fmadd_ps(alpha_2_p, beta_p_8, gamma_2_8); - gamma_3_8 = mm256_fmadd_ps(alpha_3_p, beta_p_8, gamma_3_8); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - // row 2 - mm256_storeu_ps(Cp + baseC_2 + 0, gamma_2_0); - mm256_storeu_ps(Cp + baseC_2 + 8, gamma_2_8); - // row 3 - mm256_storeu_ps(Cp + baseC_3 + 0, gamma_3_0); - mm256_storeu_ps(Cp + baseC_3 + 8, gamma_3_8); - } - } - for (; i < blockSizeM - 2; i += 3) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - // row 2 - v256 gamma_2_0 = mm256_loadu_ps(Cp + baseC_2 + 0); - v256 gamma_2_8 = mm256_loadu_ps(Cp + baseC_2 + 8); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - v256 alpha_2_p = mm256_broadcast_ss(Ap + i_2 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_2_0 = mm256_fmadd_ps(alpha_2_p, beta_p_0, gamma_2_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - gamma_2_8 = mm256_fmadd_ps(alpha_2_p, beta_p_8, gamma_2_8); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - // row 2 - mm256_storeu_ps(Cp + baseC_2 + 0, gamma_2_0); - mm256_storeu_ps(Cp + baseC_2 + 8, gamma_2_8); - } - } - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - // row 1 - v256 gamma_1_0 = mm256_loadu_ps(Cp + baseC_1 + 0); - v256 gamma_1_8 = mm256_loadu_ps(Cp + baseC_1 + 8); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - v256 alpha_1_p = mm256_broadcast_ss(Ap + i_1 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_1_0 = mm256_fmadd_ps(alpha_1_p, beta_p_0, gamma_1_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - gamma_1_8 = mm256_fmadd_ps(alpha_1_p, beta_p_8, gamma_1_8); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - // row 1 - mm256_storeu_ps(Cp + baseC_1 + 0, gamma_1_0); - mm256_storeu_ps(Cp + baseC_1 + 8, gamma_1_8); - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 16) - { - int baseC_0 = i_0 * Cstride + j; - - // row 0 - v256 gamma_0_0 = mm256_loadu_ps(Cp + baseC_0 + 0); - v256 gamma_0_8 = mm256_loadu_ps(Cp + baseC_0 + 8); - - for (int l = 0; l < blockSizeK; l++) - { - v256 alpha_0_p = mm256_broadcast_ss(Ap + i_0 * Astride + l); - - v256 beta_p_0 = mm256_loadu_ps(Bp + l * Bstride + j + 0); - v256 beta_p_8 = mm256_loadu_ps(Bp + l * Bstride + j + 8); - - gamma_0_0 = mm256_fmadd_ps(alpha_0_p, beta_p_0, gamma_0_0); - gamma_0_8 = mm256_fmadd_ps(alpha_0_p, beta_p_8, gamma_0_8); - } - // row 0 - mm256_storeu_ps(Cp + baseC_0 + 0, gamma_0_0); - mm256_storeu_ps(Cp + baseC_0 + 8, gamma_0_8); - } - } - } - - static unsafe void MultiplyBlockUnroll4x24( - [NoAlias] float* Ap, int Astride, - [NoAlias] float* Bp, int Bstride, - [NoAlias] float* Cp, int Cstride, - int blockSizeM, int blockSizeK, - int n) - { - n = Math.Max(24, n); - int i = 0; - for (; i < blockSizeM - 3; i += 4) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - var i_3 = i + 3; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - int baseC_3 = i_3 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - // 2 - float sum0_2 = *(Cp + baseC_2 + 0); - float sum1_2 = *(Cp + baseC_2 + 1); - float sum2_2 = *(Cp + baseC_2 + 2); - float sum3_2 = *(Cp + baseC_2 + 3); - float sum4_2 = *(Cp + baseC_2 + 4); - float sum5_2 = *(Cp + baseC_2 + 5); - float sum6_2 = *(Cp + baseC_2 + 6); - float sum7_2 = *(Cp + baseC_2 + 7); - float sum8_2 = *(Cp + baseC_2 + 8); - float sum9_2 = *(Cp + baseC_2 + 9); - float sum10_2 = *(Cp + baseC_2 + 10); - float sum11_2 = *(Cp + baseC_2 + 11); - float sum12_2 = *(Cp + baseC_2 + 12); - float sum13_2 = *(Cp + baseC_2 + 13); - float sum14_2 = *(Cp + baseC_2 + 14); - float sum15_2 = *(Cp + baseC_2 + 15); - float sum16_2 = *(Cp + baseC_2 + 16); - float sum17_2 = *(Cp + baseC_2 + 17); - float sum18_2 = *(Cp + baseC_2 + 18); - float sum19_2 = *(Cp + baseC_2 + 19); - float sum20_2 = *(Cp + baseC_2 + 20); - float sum21_2 = *(Cp + baseC_2 + 21); - float sum22_2 = *(Cp + baseC_2 + 22); - float sum23_2 = *(Cp + baseC_2 + 23); - // 3 - float sum0_3 = *(Cp + baseC_3 + 0); - float sum1_3 = *(Cp + baseC_3 + 1); - float sum2_3 = *(Cp + baseC_3 + 2); - float sum3_3 = *(Cp + baseC_3 + 3); - float sum4_3 = *(Cp + baseC_3 + 4); - float sum5_3 = *(Cp + baseC_3 + 5); - float sum6_3 = *(Cp + baseC_3 + 6); - float sum7_3 = *(Cp + baseC_3 + 7); - float sum8_3 = *(Cp + baseC_3 + 8); - float sum9_3 = *(Cp + baseC_3 + 9); - float sum10_3 = *(Cp + baseC_3 + 10); - float sum11_3 = *(Cp + baseC_3 + 11); - float sum12_3 = *(Cp + baseC_3 + 12); - float sum13_3 = *(Cp + baseC_3 + 13); - float sum14_3 = *(Cp + baseC_3 + 14); - float sum15_3 = *(Cp + baseC_3 + 15); - float sum16_3 = *(Cp + baseC_3 + 16); - float sum17_3 = *(Cp + baseC_3 + 17); - float sum18_3 = *(Cp + baseC_3 + 18); - float sum19_3 = *(Cp + baseC_3 + 19); - float sum20_3 = *(Cp + baseC_3 + 20); - float sum21_3 = *(Cp + baseC_3 + 21); - float sum22_3 = *(Cp + baseC_3 + 22); - float sum23_3 = *(Cp + baseC_3 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - float A_2 = *(Ap + i_2 * Astride + l); - float A_3 = *(Ap + i_3 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; sum0_2 += A_2 * B_0; sum0_3 += A_3 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; sum1_2 += A_2 * B_1; sum1_3 += A_3 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; sum2_2 += A_2 * B_2; sum2_3 += A_3 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; sum3_2 += A_2 * B_3; sum3_3 += A_3 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; sum4_2 += A_2 * B_4; sum4_3 += A_3 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; sum5_2 += A_2 * B_5; sum5_3 += A_3 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; sum6_2 += A_2 * B_6; sum6_3 += A_3 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; sum7_2 += A_2 * B_7; sum7_3 += A_3 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; sum8_2 += A_2 * B_8; sum8_3 += A_3 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; sum9_2 += A_2 * B_9; sum9_3 += A_3 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; sum10_2 += A_2 * B_10; sum10_3 += A_3 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; sum11_2 += A_2 * B_11; sum11_3 += A_3 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; sum12_2 += A_2 * B_12; sum12_3 += A_3 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; sum13_2 += A_2 * B_13; sum13_3 += A_3 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; sum14_2 += A_2 * B_14; sum14_3 += A_3 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; sum15_2 += A_2 * B_15; sum15_3 += A_3 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; sum16_2 += A_2 * B_16; sum16_3 += A_3 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; sum17_2 += A_2 * B_17; sum17_3 += A_3 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; sum18_2 += A_2 * B_18; sum18_3 += A_3 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; sum19_2 += A_2 * B_19; sum19_3 += A_3 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; sum20_2 += A_2 * B_20; sum20_3 += A_3 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; sum21_2 += A_2 * B_21; sum21_3 += A_3 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; sum22_2 += A_2 * B_22; sum22_3 += A_3 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; sum23_2 += A_2 * B_23; sum23_3 += A_3 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - // 2 - *(Cp + baseC_2 + 0) = sum0_2; - *(Cp + baseC_2 + 1) = sum1_2; - *(Cp + baseC_2 + 2) = sum2_2; - *(Cp + baseC_2 + 3) = sum3_2; - *(Cp + baseC_2 + 4) = sum4_2; - *(Cp + baseC_2 + 5) = sum5_2; - *(Cp + baseC_2 + 6) = sum6_2; - *(Cp + baseC_2 + 7) = sum7_2; - *(Cp + baseC_2 + 8) = sum8_2; - *(Cp + baseC_2 + 9) = sum9_2; - *(Cp + baseC_2 + 10) = sum10_2; - *(Cp + baseC_2 + 11) = sum11_2; - *(Cp + baseC_2 + 12) = sum12_2; - *(Cp + baseC_2 + 13) = sum13_2; - *(Cp + baseC_2 + 14) = sum14_2; - *(Cp + baseC_2 + 15) = sum15_2; - *(Cp + baseC_2 + 16) = sum16_2; - *(Cp + baseC_2 + 17) = sum17_2; - *(Cp + baseC_2 + 18) = sum18_2; - *(Cp + baseC_2 + 19) = sum19_2; - *(Cp + baseC_2 + 20) = sum20_2; - *(Cp + baseC_2 + 21) = sum21_2; - *(Cp + baseC_2 + 22) = sum22_2; - *(Cp + baseC_2 + 23) = sum23_2; - // 3 - *(Cp + baseC_3 + 0) = sum0_3; - *(Cp + baseC_3 + 1) = sum1_3; - *(Cp + baseC_3 + 2) = sum2_3; - *(Cp + baseC_3 + 3) = sum3_3; - *(Cp + baseC_3 + 4) = sum4_3; - *(Cp + baseC_3 + 5) = sum5_3; - *(Cp + baseC_3 + 6) = sum6_3; - *(Cp + baseC_3 + 7) = sum7_3; - *(Cp + baseC_3 + 8) = sum8_3; - *(Cp + baseC_3 + 9) = sum9_3; - *(Cp + baseC_3 + 10) = sum10_3; - *(Cp + baseC_3 + 11) = sum11_3; - *(Cp + baseC_3 + 12) = sum12_3; - *(Cp + baseC_3 + 13) = sum13_3; - *(Cp + baseC_3 + 14) = sum14_3; - *(Cp + baseC_3 + 15) = sum15_3; - *(Cp + baseC_3 + 16) = sum16_3; - *(Cp + baseC_3 + 17) = sum17_3; - *(Cp + baseC_3 + 18) = sum18_3; - *(Cp + baseC_3 + 19) = sum19_3; - *(Cp + baseC_3 + 20) = sum20_3; - *(Cp + baseC_3 + 21) = sum21_3; - *(Cp + baseC_3 + 22) = sum22_3; - *(Cp + baseC_3 + 23) = sum23_3; - } - } - for (; i < blockSizeM - 2; i += 3) - { - var i_0 = i + 0; - var i_1 = i + 1; - var i_2 = i + 2; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - int baseC_2 = i_2 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - // 2 - float sum0_2 = *(Cp + baseC_2 + 0); - float sum1_2 = *(Cp + baseC_2 + 1); - float sum2_2 = *(Cp + baseC_2 + 2); - float sum3_2 = *(Cp + baseC_2 + 3); - float sum4_2 = *(Cp + baseC_2 + 4); - float sum5_2 = *(Cp + baseC_2 + 5); - float sum6_2 = *(Cp + baseC_2 + 6); - float sum7_2 = *(Cp + baseC_2 + 7); - float sum8_2 = *(Cp + baseC_2 + 8); - float sum9_2 = *(Cp + baseC_2 + 9); - float sum10_2 = *(Cp + baseC_2 + 10); - float sum11_2 = *(Cp + baseC_2 + 11); - float sum12_2 = *(Cp + baseC_2 + 12); - float sum13_2 = *(Cp + baseC_2 + 13); - float sum14_2 = *(Cp + baseC_2 + 14); - float sum15_2 = *(Cp + baseC_2 + 15); - float sum16_2 = *(Cp + baseC_2 + 16); - float sum17_2 = *(Cp + baseC_2 + 17); - float sum18_2 = *(Cp + baseC_2 + 18); - float sum19_2 = *(Cp + baseC_2 + 19); - float sum20_2 = *(Cp + baseC_2 + 20); - float sum21_2 = *(Cp + baseC_2 + 21); - float sum22_2 = *(Cp + baseC_2 + 22); - float sum23_2 = *(Cp + baseC_2 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - float A_2 = *(Ap + i_2 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; sum0_2 += A_2 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; sum1_2 += A_2 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; sum2_2 += A_2 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; sum3_2 += A_2 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; sum4_2 += A_2 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; sum5_2 += A_2 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; sum6_2 += A_2 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; sum7_2 += A_2 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; sum8_2 += A_2 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; sum9_2 += A_2 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; sum10_2 += A_2 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; sum11_2 += A_2 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; sum12_2 += A_2 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; sum13_2 += A_2 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; sum14_2 += A_2 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; sum15_2 += A_2 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; sum16_2 += A_2 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; sum17_2 += A_2 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; sum18_2 += A_2 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; sum19_2 += A_2 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; sum20_2 += A_2 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; sum21_2 += A_2 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; sum22_2 += A_2 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; sum23_2 += A_2 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - // 2 - *(Cp + baseC_2 + 0) = sum0_2; - *(Cp + baseC_2 + 1) = sum1_2; - *(Cp + baseC_2 + 2) = sum2_2; - *(Cp + baseC_2 + 3) = sum3_2; - *(Cp + baseC_2 + 4) = sum4_2; - *(Cp + baseC_2 + 5) = sum5_2; - *(Cp + baseC_2 + 6) = sum6_2; - *(Cp + baseC_2 + 7) = sum7_2; - *(Cp + baseC_2 + 8) = sum8_2; - *(Cp + baseC_2 + 9) = sum9_2; - *(Cp + baseC_2 + 10) = sum10_2; - *(Cp + baseC_2 + 11) = sum11_2; - *(Cp + baseC_2 + 12) = sum12_2; - *(Cp + baseC_2 + 13) = sum13_2; - *(Cp + baseC_2 + 14) = sum14_2; - *(Cp + baseC_2 + 15) = sum15_2; - *(Cp + baseC_2 + 16) = sum16_2; - *(Cp + baseC_2 + 17) = sum17_2; - *(Cp + baseC_2 + 18) = sum18_2; - *(Cp + baseC_2 + 19) = sum19_2; - *(Cp + baseC_2 + 20) = sum20_2; - *(Cp + baseC_2 + 21) = sum21_2; - *(Cp + baseC_2 + 22) = sum22_2; - *(Cp + baseC_2 + 23) = sum23_2; - } - } - for (; i < blockSizeM - 1; i += 2) - { - var i_0 = i + 0; - var i_1 = i + 1; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - int baseC_1 = i_1 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - // 1 - float sum0_1 = *(Cp + baseC_1 + 0); - float sum1_1 = *(Cp + baseC_1 + 1); - float sum2_1 = *(Cp + baseC_1 + 2); - float sum3_1 = *(Cp + baseC_1 + 3); - float sum4_1 = *(Cp + baseC_1 + 4); - float sum5_1 = *(Cp + baseC_1 + 5); - float sum6_1 = *(Cp + baseC_1 + 6); - float sum7_1 = *(Cp + baseC_1 + 7); - float sum8_1 = *(Cp + baseC_1 + 8); - float sum9_1 = *(Cp + baseC_1 + 9); - float sum10_1 = *(Cp + baseC_1 + 10); - float sum11_1 = *(Cp + baseC_1 + 11); - float sum12_1 = *(Cp + baseC_1 + 12); - float sum13_1 = *(Cp + baseC_1 + 13); - float sum14_1 = *(Cp + baseC_1 + 14); - float sum15_1 = *(Cp + baseC_1 + 15); - float sum16_1 = *(Cp + baseC_1 + 16); - float sum17_1 = *(Cp + baseC_1 + 17); - float sum18_1 = *(Cp + baseC_1 + 18); - float sum19_1 = *(Cp + baseC_1 + 19); - float sum20_1 = *(Cp + baseC_1 + 20); - float sum21_1 = *(Cp + baseC_1 + 21); - float sum22_1 = *(Cp + baseC_1 + 22); - float sum23_1 = *(Cp + baseC_1 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - float A_1 = *(Ap + i_1 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; sum0_1 += A_1 * B_0; - sum1_0 += A_0 * B_1; sum1_1 += A_1 * B_1; - sum2_0 += A_0 * B_2; sum2_1 += A_1 * B_2; - sum3_0 += A_0 * B_3; sum3_1 += A_1 * B_3; - sum4_0 += A_0 * B_4; sum4_1 += A_1 * B_4; - sum5_0 += A_0 * B_5; sum5_1 += A_1 * B_5; - sum6_0 += A_0 * B_6; sum6_1 += A_1 * B_6; - sum7_0 += A_0 * B_7; sum7_1 += A_1 * B_7; - sum8_0 += A_0 * B_8; sum8_1 += A_1 * B_8; - sum9_0 += A_0 * B_9; sum9_1 += A_1 * B_9; - sum10_0 += A_0 * B_10; sum10_1 += A_1 * B_10; - sum11_0 += A_0 * B_11; sum11_1 += A_1 * B_11; - sum12_0 += A_0 * B_12; sum12_1 += A_1 * B_12; - sum13_0 += A_0 * B_13; sum13_1 += A_1 * B_13; - sum14_0 += A_0 * B_14; sum14_1 += A_1 * B_14; - sum15_0 += A_0 * B_15; sum15_1 += A_1 * B_15; - sum16_0 += A_0 * B_16; sum16_1 += A_1 * B_16; - sum17_0 += A_0 * B_17; sum17_1 += A_1 * B_17; - sum18_0 += A_0 * B_18; sum18_1 += A_1 * B_18; - sum19_0 += A_0 * B_19; sum19_1 += A_1 * B_19; - sum20_0 += A_0 * B_20; sum20_1 += A_1 * B_20; - sum21_0 += A_0 * B_21; sum21_1 += A_1 * B_21; - sum22_0 += A_0 * B_22; sum22_1 += A_1 * B_22; - sum23_0 += A_0 * B_23; sum23_1 += A_1 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - // 1 - *(Cp + baseC_1 + 0) = sum0_1; - *(Cp + baseC_1 + 1) = sum1_1; - *(Cp + baseC_1 + 2) = sum2_1; - *(Cp + baseC_1 + 3) = sum3_1; - *(Cp + baseC_1 + 4) = sum4_1; - *(Cp + baseC_1 + 5) = sum5_1; - *(Cp + baseC_1 + 6) = sum6_1; - *(Cp + baseC_1 + 7) = sum7_1; - *(Cp + baseC_1 + 8) = sum8_1; - *(Cp + baseC_1 + 9) = sum9_1; - *(Cp + baseC_1 + 10) = sum10_1; - *(Cp + baseC_1 + 11) = sum11_1; - *(Cp + baseC_1 + 12) = sum12_1; - *(Cp + baseC_1 + 13) = sum13_1; - *(Cp + baseC_1 + 14) = sum14_1; - *(Cp + baseC_1 + 15) = sum15_1; - *(Cp + baseC_1 + 16) = sum16_1; - *(Cp + baseC_1 + 17) = sum17_1; - *(Cp + baseC_1 + 18) = sum18_1; - *(Cp + baseC_1 + 19) = sum19_1; - *(Cp + baseC_1 + 20) = sum20_1; - *(Cp + baseC_1 + 21) = sum21_1; - *(Cp + baseC_1 + 22) = sum22_1; - *(Cp + baseC_1 + 23) = sum23_1; - } - } - for (; i < blockSizeM - 0; i += 1) - { - var i_0 = i + 0; - - for (int j = 0; j < n; j += 24) - { - int baseC_0 = i_0 * Cstride + j; - // 0 - float sum0_0 = *(Cp + baseC_0 + 0); - float sum1_0 = *(Cp + baseC_0 + 1); - float sum2_0 = *(Cp + baseC_0 + 2); - float sum3_0 = *(Cp + baseC_0 + 3); - float sum4_0 = *(Cp + baseC_0 + 4); - float sum5_0 = *(Cp + baseC_0 + 5); - float sum6_0 = *(Cp + baseC_0 + 6); - float sum7_0 = *(Cp + baseC_0 + 7); - float sum8_0 = *(Cp + baseC_0 + 8); - float sum9_0 = *(Cp + baseC_0 + 9); - float sum10_0 = *(Cp + baseC_0 + 10); - float sum11_0 = *(Cp + baseC_0 + 11); - float sum12_0 = *(Cp + baseC_0 + 12); - float sum13_0 = *(Cp + baseC_0 + 13); - float sum14_0 = *(Cp + baseC_0 + 14); - float sum15_0 = *(Cp + baseC_0 + 15); - float sum16_0 = *(Cp + baseC_0 + 16); - float sum17_0 = *(Cp + baseC_0 + 17); - float sum18_0 = *(Cp + baseC_0 + 18); - float sum19_0 = *(Cp + baseC_0 + 19); - float sum20_0 = *(Cp + baseC_0 + 20); - float sum21_0 = *(Cp + baseC_0 + 21); - float sum22_0 = *(Cp + baseC_0 + 22); - float sum23_0 = *(Cp + baseC_0 + 23); - - for (int l = 0; l < blockSizeK; l++) - { - float A_0 = *(Ap + i_0 * Astride + l); - int baseB = l * Bstride + j; - float B_0 = (*(Bp + baseB + 0)); - float B_1 = (*(Bp + baseB + 1)); - float B_2 = (*(Bp + baseB + 2)); - float B_3 = (*(Bp + baseB + 3)); - float B_4 = (*(Bp + baseB + 4)); - float B_5 = (*(Bp + baseB + 5)); - float B_6 = (*(Bp + baseB + 6)); - float B_7 = (*(Bp + baseB + 7)); - float B_8 = (*(Bp + baseB + 8)); - float B_9 = (*(Bp + baseB + 9)); - float B_10 = (*(Bp + baseB + 10)); - float B_11 = (*(Bp + baseB + 11)); - float B_12 = (*(Bp + baseB + 12)); - float B_13 = (*(Bp + baseB + 13)); - float B_14 = (*(Bp + baseB + 14)); - float B_15 = (*(Bp + baseB + 15)); - float B_16 = (*(Bp + baseB + 16)); - float B_17 = (*(Bp + baseB + 17)); - float B_18 = (*(Bp + baseB + 18)); - float B_19 = (*(Bp + baseB + 19)); - float B_20 = (*(Bp + baseB + 20)); - float B_21 = (*(Bp + baseB + 21)); - float B_22 = (*(Bp + baseB + 22)); - float B_23 = (*(Bp + baseB + 23)); - sum0_0 += A_0 * B_0; - sum1_0 += A_0 * B_1; - sum2_0 += A_0 * B_2; - sum3_0 += A_0 * B_3; - sum4_0 += A_0 * B_4; - sum5_0 += A_0 * B_5; - sum6_0 += A_0 * B_6; - sum7_0 += A_0 * B_7; - sum8_0 += A_0 * B_8; - sum9_0 += A_0 * B_9; - sum10_0 += A_0 * B_10; - sum11_0 += A_0 * B_11; - sum12_0 += A_0 * B_12; - sum13_0 += A_0 * B_13; - sum14_0 += A_0 * B_14; - sum15_0 += A_0 * B_15; - sum16_0 += A_0 * B_16; - sum17_0 += A_0 * B_17; - sum18_0 += A_0 * B_18; - sum19_0 += A_0 * B_19; - sum20_0 += A_0 * B_20; - sum21_0 += A_0 * B_21; - sum22_0 += A_0 * B_22; - sum23_0 += A_0 * B_23; - } - // 0 - *(Cp + baseC_0 + 0) = sum0_0; - *(Cp + baseC_0 + 1) = sum1_0; - *(Cp + baseC_0 + 2) = sum2_0; - *(Cp + baseC_0 + 3) = sum3_0; - *(Cp + baseC_0 + 4) = sum4_0; - *(Cp + baseC_0 + 5) = sum5_0; - *(Cp + baseC_0 + 6) = sum6_0; - *(Cp + baseC_0 + 7) = sum7_0; - *(Cp + baseC_0 + 8) = sum8_0; - *(Cp + baseC_0 + 9) = sum9_0; - *(Cp + baseC_0 + 10) = sum10_0; - *(Cp + baseC_0 + 11) = sum11_0; - *(Cp + baseC_0 + 12) = sum12_0; - *(Cp + baseC_0 + 13) = sum13_0; - *(Cp + baseC_0 + 14) = sum14_0; - *(Cp + baseC_0 + 15) = sum15_0; - *(Cp + baseC_0 + 16) = sum16_0; - *(Cp + baseC_0 + 17) = sum17_0; - *(Cp + baseC_0 + 18) = sum18_0; - *(Cp + baseC_0 + 19) = sum19_0; - *(Cp + baseC_0 + 20) = sum20_0; - *(Cp + baseC_0 + 21) = sum21_0; - *(Cp + baseC_0 + 22) = sum22_0; - *(Cp + baseC_0 + 23) = sum23_0; - } - } - } - -} -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.MatMul.gen.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.MatMul.gen.cs.meta deleted file mode 100644 index ec99da0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.MatMul.gen.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dd2cfd0651655b44ca226eb4f0b952aa -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Ops.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Ops.cs deleted file mode 100644 index 0e41bf4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Ops.cs +++ /dev/null @@ -1,2277 +0,0 @@ -using UnityEngine; -using UnityEngine.Assertions; -using System; -using Unity.Collections; -using Unity.Jobs; -using Unity.Jobs.LowLevel.Unsafe; -using Unity.Mathematics; - -namespace Unity.Barracuda { - -// BarracudaBurstCPU.Core.cs -- definition of class BurstCPUOps, Pin(), BurstTensorData -// BarracudaBurstCPU.Ops.cs -- impl. IOps, job schedulers -// BarracudaBurstCPU.Jobs.cs -- impl. jobs - -public partial class BurstCPUOps -{ - public enum BLAS - { - Disabled = 0, - Native, - Any - } - - /// - /// EXPERIMENTAL: Select BLAS preference - /// Production code should stick to default (Native) for now. - /// - public static BLAS PreferBLAS { get; set; } = BLAS.Native; - - internal static JobHandle Dependencies(JobHandle job, JobHandle job2) - { - return JobHandle.CombineDependencies(job, job2); - } - internal static JobHandle Dependencies(JobHandle job, JobHandle job2, JobHandle job3) - { - return JobHandle.CombineDependencies(job, job2, job3); - } - internal static JobHandle Dependencies(JobHandle job, JobHandle job2, JobHandle job3, JobHandle job4) - { - return JobHandle.CombineDependencies(job, JobHandle.CombineDependencies(job2, job3, job4)); - } - - /// - public override Tensor MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - return MatMulHelper(X, xTranspose, Y, yTranspose, null, null, null, AllocScope.LayerOutput); - } - - private Tensor MatMulHelper(Tensor X, bool xTranspose, Tensor Y, bool yTranspose, - int? blockSizeM, int? blockSizeN, int? blockSizeK, AllocScope outputScope) - { - Assert.IsTrue(X.dimensions <= 2); - Assert.IsTrue(Y.dimensions <= 2); - - int xw = X.flatWidth, xh = X.flatHeight; - int yw = Y.flatWidth, yh = Y.flatHeight; - - if (xTranspose) - { - var tmp = xw; xw = xh; xh = tmp; - } - if (yTranspose) - { - var tmp = yw; yw = yh; yh = tmp; - } - - Assert.AreEqual(xw, yh); - var O = NewTensor(X.dataType, new TensorShape(xh, yw), outputScope, ""); - - using (var ctx = new ForceFloatJobContext(X, Y, null, O)) - { - { // O = broadcast(0) - var job = new ZeroBroadcastJob(); - job.repeat = O.length; - job.ScheduleO(ctx.o); - } - - // O += X * K - ScheduleSGEMM( - ctx.x, X.flatHeight, X.flatWidth, - ctx.w, Y.flatHeight, Y.flatWidth, - ctx.o, O.flatHeight, O.flatWidth, - blockSizeM: blockSizeM, blockSizeN: blockSizeN, blockSizeK: blockSizeK); - } - - return O; - } - - //O += X x K - private unsafe void ScheduleSGEMM( - IDependableMemoryResource pinX, int XM, int XN, - IDependableMemoryResource pinK, int KM, int KN, - IDependableMemoryResource pinO, int OM, int ON, - bool transposeA = false, bool transposeB = false, int kernelOffset = 0, - int? blockSizeM = null, int? blockSizeN = null, int? blockSizeK = null) - { - JobHandle dependOn = Dependencies(pinO.reuse, pinX.fence, pinK.fence); - - JobHandle jobFence = new JobHandle(); - float* ptrX = (float*)pinX.rawPtr; - float* ptrK = (float*)pinK.rawPtr + kernelOffset; - float* ptrO = (float*)pinO.rawPtr; - - if (PreferBLAS != BLAS.Disabled) - { - jobFence = blas.ScheduleSGEMM(dependOn, - ptrX, XM, XN, - ptrK, KM, KN, - ptrO, OM, ON, - 16, transposeA, transposeB); - } - else if (Application.isMobilePlatform || Application.isConsolePlatform) - { - var job = new MatrixMultiplyLegacyJob(); - job.A = ptrX; job.AM = XM; job.AN = XN; - job.B = ptrK; job.BM = KM; job.BN = KN; - job.C = ptrO; job.CM = OM; job.CN = ON; - job.transposeA = transposeA; - job.transposeB = transposeB; - - jobFence = job.Schedule(dependOn); - } - else - { - var job = new MatrixMultiplyJob(); - job.A = ptrX; job.AM = XM; job.AN = XN; - job.B = ptrK; job.BM = KM; job.BN = KN; - job.C = ptrO; job.CM = OM; job.CN = ON; - job.transposeA = transposeA; - job.transposeB = transposeB; - - if (blockSizeM.HasValue) - job.blockSizeM = blockSizeM.Value; - - if (blockSizeN.HasValue) - job.blockSizeN = blockSizeN.Value; - - if (blockSizeK.HasValue) - job.blockSizeK = blockSizeK.Value; - - jobFence = job.Schedule(dependOn); - } - - pinO.fence = pinX.reuse = pinK.reuse = jobFence; - } - - /// - public override Tensor MatMul(Tensor X, int rankX, Tensor Y, int rankY) - { - if (rankX == 2 && rankY == 2) - return MatMul(X, false, Y, false); - - if (rankX == 3 && rankY == 2) - return MatMul3x2(X,Y); - else if (rankX == 4 && rankY == 4) - return MatMul4x4(X,Y); - else - return base.MatMul(X, rankX, Y, rankY); - } - - private Tensor MatMul3x2(Tensor X, Tensor Y) - { - int xb = X.batch, xw = X.width, xh = X.channels; - int yw = Y.channels, yh = Y.batch; - - Assert.AreEqual(xw, yh); - var O = NewOutputTensor(X.dataType, new TensorShape(xb, 1, yw, xh)); - - // O += X * K - var job = new MatrixMultiply3x2Job(); - job.AM = xh; - job.AN = xw; - job.BM = yh; - job.BN = yw; - job.CM = xh; - job.CN = yw; - - job.dispatchThreadX = ((xh + MatrixMultiply3x2Job.blockSize - 1) / MatrixMultiply3x2Job.blockSize); - job.dispatchThreadY = ((yw + MatrixMultiply3x2Job.blockSize - 1) / MatrixMultiply3x2Job.blockSize); - job.dispatchThreadZ = xb; - - using (var ctx = new ForceFloatJobContext(X, Y, null, O)) - { - job.ScheduleXBO(ctx.x, ctx.w, ctx.o, job.dispatchThreadX * job.dispatchThreadY * job.dispatchThreadZ, 1); - } - - return O; - } - - private Tensor MatMul4x4(Tensor X, Tensor Y) - { - int xb0 = X.batch, xh = X.height, xw = X.width, xb1 = X.channels; - int yb0 = Y.batch, yh = Y.height, yw = Y.width, yb1 = Y.channels; - - Assert.AreEqual(xw, yh); - int ob0 = Mathf.Max(xb0, yb0); int ob1 = Mathf.Max(xb1, yb1); - var O = NewOutputTensor(X.dataType, new TensorShape(ob0, xh, yw, ob1)); - - // O += X * K - var job = new MatrixMultiply4x4Job(); - job.AB0 = xb0; - job.AB1 = xb1; - job.AM = xh; - job.AN = xw; - job.BB0 = yb0; - job.BB1 = yb1; - job.BM = yh; - job.BN = yw; - job.CB1 = ob1; - job.CM = xh; - job.CN = yw; - - job.dispatchThreadX = ((xh + MatrixMultiply3x2Job.blockSize - 1) / MatrixMultiply3x2Job.blockSize); - job.dispatchThreadY = ((yw + MatrixMultiply3x2Job.blockSize - 1) / MatrixMultiply3x2Job.blockSize); - job.dispatchThreadZ = ob0*ob1; - - using (var ctx = new ForceFloatJobContext(X, Y, null, O)) - { - job.ScheduleXBO(ctx.x, ctx.w, ctx.o, job.dispatchThreadX * job.dispatchThreadY * job.dispatchThreadZ, 1); - } - - return O; - } - - internal struct ForceFloatJobContext : IDisposable - { - private static Allocator memoryAllocator = Allocator.TempJob; - - //static to avoid GC. TODO try FencedMemoryAlloc as a struct - private static FencedMemoryAlloc s_XFloat = new FencedMemoryAlloc(); - private static FencedMemoryAlloc s_WFloat = new FencedMemoryAlloc(); - private static FencedMemoryAlloc s_BFloat = new FencedMemoryAlloc(); - private static FencedMemoryAlloc s_OFloat = new FencedMemoryAlloc(); - - public FencedMemoryAlloc xFloat; - public FencedMemoryAlloc wFloat; - public FencedMemoryAlloc bFloat; - public FencedMemoryAlloc oFloat; - private BurstTensorData pinO; - - public IDependableMemoryResource x; - public IDependableMemoryResource w; - public IDependableMemoryResource b; - public IDependableMemoryResource o; - - public unsafe bool xConverted => xFloat.rawPtr != null; - public unsafe bool wConverted => wFloat.rawPtr != null; - public unsafe bool bConverted => bFloat.rawPtr != null; - public unsafe bool oNeedConversion => oFloat.rawPtr != null; - - public ForceFloatJobContext(Tensor X, Tensor W, Tensor B, Tensor O) - { - // input & constants - var pinX = Pin(X); - var pinW = Pin(W); - var pinB = (B!= null)? Pin(B) : null; - // output - pinO = Pin(O, uploadCache: false); - - xFloat = s_XFloat; - wFloat = s_WFloat; - bFloat = s_BFloat; - oFloat = s_OFloat; - - ScheduleConversionToFloatIfNeeded(pinX, xFloat); - ScheduleConversionToFloatIfNeeded(pinW, wFloat); - ScheduleConversionToFloatIfNeeded(pinB, bFloat); - AllocFencedMemoryIfNeeded(pinO, oFloat); - - unsafe - { - x = xFloat.rawPtr != null ? (IDependableMemoryResource)xFloat : pinX; - w = wFloat.rawPtr != null ? (IDependableMemoryResource)wFloat : pinW; - b = bFloat.rawPtr != null ? (IDependableMemoryResource)bFloat : pinB; - o = oFloat.rawPtr != null ? (IDependableMemoryResource)oFloat : pinO; - } - - if (B != null) - Assert.AreEqual(wConverted, bConverted); - Assert.AreEqual(xConverted, oNeedConversion); - } - - public void Dispose() - { - //convert output as float to half - if (oNeedConversion) - { - var convertFloatToHalfJob = new ConvertFloatToHalfJob(); - Assert.AreEqual(DataType.Float, oFloat.type); - Assert.AreEqual(DataType.Half, pinO.dataType); - Assert.AreEqual(oFloat.elementCount, pinO.count); - convertFloatToHalfJob.ScheduleXO(oFloat, pinO, pinO.count, 1024); - } - - // free activations buffers - if (xConverted || oNeedConversion) - unsafe { - var freeJob = new MemFreeJob(); - freeJob.allocator = memoryAllocator; - freeJob.buffer0 = xFloat.rawPtr; - freeJob.buffer1 = oFloat.rawPtr; - freeJob.Schedule(pinO.fence); - } - - // free weights buffers - if (wConverted || bConverted) - unsafe { - var freeJob = new MemFreeJob(); - freeJob.allocator = memoryAllocator; - freeJob.buffer0 = wFloat.rawPtr; - freeJob.buffer1 = bFloat.rawPtr; - freeJob.Schedule(pinO.fence); - } - - xFloat.ClearState(); - wFloat.ClearState(); - bFloat.ClearState(); - oFloat.ClearState(); - } - - private static bool AllocFencedMemoryIfNeeded(BurstTensorData pin, FencedMemoryAlloc fencedMem) - { - if (pin != null && pin.dataType == DataType.Half) - { - fencedMem.Allocate(pin.count, DataType.Float, JobsUtility.CacheLineSize, memoryAllocator); - return true; - } - - return false; - } - - private static void ScheduleConversionToFloatIfNeeded(BurstTensorData pinnedTensor, FencedMemoryAlloc destination) - { - if (AllocFencedMemoryIfNeeded(pinnedTensor, destination)) - { - var convertHalfToFloatJob = new ConvertHalfToFloatJob(); - Assert.AreEqual(DataType.Half, pinnedTensor.dataType); - Assert.AreEqual(DataType.Float, destination.type); - Assert.AreEqual(pinnedTensor.count, destination.elementCount); - convertHalfToFloatJob.ScheduleXO(pinnedTensor, destination, pinnedTensor.count, 1024); - } - } - } - - /// - public override Tensor Dense3(Tensor X, Tensor W, Tensor B) - { - int xb = X.batch, xw = X.width, xh = X.channels; - int yw = W.channels, yh = W.batch; - - Assert.AreEqual(xw, yh); - var O = NewOutputTensor(X.dataType, new TensorShape(xb, 1, yw, xh)); - - var job = new Dense3Job_Full_Float(); - job.data.AM = xh; - job.data.AN = xw; - job.data.BM = yh; - job.data.BN = yw; - job.data.SM = xh; - job.data.SN = yw; - - job.data.dispatchThreadX = ((xh + Dense3Job_Full_Float.blockSize - 1) / Dense3Job_Full_Float.blockSize); - job.data.dispatchThreadY = ((yw + Dense3Job_Full_Float.blockSize - 1) / Dense3Job_Full_Float.blockSize); - job.data.dispatchThreadZ = xb; - - using (var ctx = new ForceFloatJobContext(X, W, B, O)) - { - job.ScheduleXSBO(ctx.x, ctx.w, ctx.b, ctx.o, job.data.dispatchThreadX * job.data.dispatchThreadY * job.data.dispatchThreadZ, 1); - } - - return O; - } - - /// - public override Tensor Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - //D.Log(string.Format("X = {0}", X.shape)); - Assert.IsTrue(W.dimensions <= 2); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(B.flatWidth, W.flatWidth); - Assert.AreEqual(X.flatWidth, W.flatHeight); - var O = NewTensorForFusedActivation(X.dataType, new TensorShape(X.flatHeight, W.flatWidth), fusedActivation); - - using (var ctx = new ForceFloatJobContext(X, W, B, O)) - { - { // O = broadcast(B) - // @TODO: move broadcast B directly into MatrixMultiplyJob - var job = new VectorBroadcastJob(); - job.channels = O.flatWidth; - job.repeat = O.flatHeight; - job.ScheduleXO(ctx.b, ctx.o); - } - - ScheduleSGEMM( - ctx.x, X.flatHeight, X.flatWidth, - ctx.w, W.flatHeight, W.flatWidth, - ctx.o, O.flatHeight, O.flatWidth); - } - - return ApplyFusedActivation(O, fusedActivation); - } - - /// - public override Tensor Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - return Conv2DUsingIm2ColSliced(X, K, B, stride, pad, fusedActivation); - } - - Tensor Conv2DUsingIm2ColSliced(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var kernelWidth = K.kernelWidth; - var kernelHeight = K.kernelHeight; - var inChannels = K.kernelDepth; - var outChannels = K.kernelCount; - var batch = X.batch; - - bool pointwiseConvolution = kernelWidth == 1 && kernelHeight == 1 && // 1x1 kernel - stride[0] == 1 && stride[1] == 1 && // no strides - pad[0] == 0 && pad[1] == 0 && pad[2] == 0 && pad[3] == 0; // no padding - - var O = NewTensorForFusedActivation(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad), fusedActivation); - var T = pointwiseConvolution ? null: // pointwise convolution is just O=X*K, we can completely skip Im2Col() - NewTempTensor(DataType.Float, new TensorShape(O.batch, O.height, O.width, inChannels), "Conv2DUsingIm2ColSliced/T"); // T holds slice of Im2Col(X) - - var outElements = O.batch * O.height * O.width; - var inWidth = X.width; - - Assert.AreEqual(O.batch, batch); - Assert.AreEqual(O.channels, B.flatWidth); - Assert.AreEqual(O.channels, outChannels); - - using (var ctx = new ForceFloatJobContext(X, K, B, O)) - { - // temporary slice - var pinT = pointwiseConvolution ? ctx.x : Pin(T); - if (T != null) - Assert.AreEqual(DataType.Float, T.dataType); - - { // O = broadcast(B) - // @TODO: move broadcast B directly into MatrixMultiplyJob - var job = new VectorBroadcastJob(); - job.channels = outChannels; - job.repeat = outElements; - job.ScheduleXO(ctx.b, ctx.o); - } - - // We can solve convolution by iteratively accumulating - // matrix multiplication of X' and K' for each positon in kernel where: - // X' is input X repeatedly shifted according to kernel position, - // K' is slice of weights K according to kernel position. - // - // Pseudocode: - // X :: Input - // T :: Temporary - // K :: Kernel - // O :: Output - // foreach ky in kernelHeight: - // foreach kx in kernelWidth: - // Temporary = shift(Input, horizontal_shift = kx, vertical_shift = ky) - // Temporary = pad(Temporary) - // Temporary = stride(Temporary) - // Output += Temporary * Kernel[dy, dx, :, :] - // - // Note for functions above that: - // 1) shift() can be implemented by copying data from n to T in a linear fashion. - // 2) stride() can be implemented by copying data every Nth pixel in a linear fashion. - // 3) pad() can be optimized for top and bottom of the tensor by writing 0s across the whole row. - - // O += conv(X, K) - int kernelOffset = 0; - for (int dy = 0; dy < kernelHeight; ++dy) - for (int dx = 0; dx < kernelWidth; ++dx) - { - //T=im2col(X) else T=X - if (!pointwiseConvolution) - { - var offsetX = dx - pad[0]; - var offsetY = dy - pad[1]; - - var strideX = stride[0]; - var strideY = stride[1]; - - var firstPixel = 0 * strideX + offsetX; - var lastPixel = (T.width - 1) * strideX + offsetX; - int numberOfPixelsToPadLeft = SafeIntDivCeil(Math.Max(0, 0 - firstPixel), strideX); // count(x * stride[0] + offsetX < 0) - int numberOfPixelsToPadRight = SafeIntDivCeil(Math.Max(0, lastPixel - (inWidth - 1)), strideX); // count(x * stride[0] + offsetX >= inWidth) - int numberOfPixelsToSkipFromInputRow = (offsetX >= 0 || strideX == 0) - ? offsetX - : // strideX == 0 protects against div-by-zero - lastPixel % strideX; // first(x * stride[0] + offsetX >= 0) == (inWidth * stride[0] + offsetX) % stride[0] - int numberOfPixelsToCopyFromInputRow = T.width - numberOfPixelsToPadLeft - numberOfPixelsToPadRight; - - if (UnityEngine.Debug.isDebugBuild) // only to Assert correctness of the values above - { - // validate above calculations with alternative approach - int assertNumberOfPixelsToPadLeft = 0; - int assertNumberOfPixelsToPadRight = 0; - int assertNumberOfPixelsToSkipFromInputRow = 0; - for (var x = 0; x < T.width; ++x) - { - var readX = x * strideX + offsetX; - if (readX < 0) - assertNumberOfPixelsToPadLeft++; - else - { - assertNumberOfPixelsToSkipFromInputRow = readX; - break; - } - } - - for (var x = T.width - 1; x >= 0; --x) - { - var readX = x * strideX + offsetX; - if (readX >= inWidth) - assertNumberOfPixelsToPadRight++; - else - break; - } - - int assertNumberOfPixelsToCopyFromInputRow = T.width - assertNumberOfPixelsToPadLeft - assertNumberOfPixelsToPadRight; - - Assert.AreEqual(numberOfPixelsToPadLeft, assertNumberOfPixelsToPadLeft); - Assert.AreEqual(numberOfPixelsToPadRight, assertNumberOfPixelsToPadRight); - Assert.AreEqual(numberOfPixelsToSkipFromInputRow, assertNumberOfPixelsToSkipFromInputRow); - Assert.AreEqual(numberOfPixelsToCopyFromInputRow, assertNumberOfPixelsToCopyFromInputRow); - } - - Assert.IsTrue(numberOfPixelsToPadLeft >= 0); - Assert.IsTrue(numberOfPixelsToPadRight >= 0); - Assert.IsTrue(numberOfPixelsToCopyFromInputRow >= 0); - Assert.IsTrue(numberOfPixelsToSkipFromInputRow >= 0); - Assert.IsTrue(numberOfPixelsToPadLeft + numberOfPixelsToPadRight <= T.width); - Assert.IsTrue(numberOfPixelsToSkipFromInputRow <= X.width); - Assert.IsTrue(numberOfPixelsToCopyFromInputRow <= X.width); - Assert.AreEqual(numberOfPixelsToPadLeft + numberOfPixelsToCopyFromInputRow + numberOfPixelsToPadRight, T.width); - - // extra clamp for safety since we are in the unsafe code block - numberOfPixelsToPadLeft = Math.Min(Math.Max(0, numberOfPixelsToPadLeft), T.width); - numberOfPixelsToPadRight = Math.Min(Math.Max(0, numberOfPixelsToPadRight), T.width - numberOfPixelsToPadLeft); - numberOfPixelsToSkipFromInputRow = Math.Min(Math.Max(0, numberOfPixelsToSkipFromInputRow), X.width); - numberOfPixelsToCopyFromInputRow = Math.Min(Math.Max(0, numberOfPixelsToCopyFromInputRow), X.width - numberOfPixelsToSkipFromInputRow); - - var job = new Im2ColSliceJob(); - job.inOutBatch = batch; - job.inOutChannels = inChannels; - job.inHeight = X.height; - job.inStrideN = X.height * X.width * X.channels; - job.inStrideH = X.width * X.channels; - job.inStrideW = X.channels; - job.outWidth = T.width; - job.outStrideN = T.height * T.width * T.channels; - job.outStrideH = T.width * T.channels; - job.strideX = strideX; - job.strideY = strideY; - job.offsetY = offsetY; - job.padLeft = numberOfPixelsToPadLeft; - job.padRight = numberOfPixelsToPadRight; - job.skipFromInputRow = numberOfPixelsToSkipFromInputRow; - job.copyFromInputRow = numberOfPixelsToCopyFromInputRow; - - job.ScheduleXO(ctx.x, pinT, T.height, 16); - } - - // O += slice(T) * slice(K) - // With T=im2col(X) if pointwiseConvolution else T=X - ScheduleSGEMM( - pinT, outElements, inChannels, - ctx.w, inChannels, outChannels, - ctx.o, outElements, outChannels, transposeA: false, transposeB: false, kernelOffset); - - kernelOffset += inChannels * outChannels; - } - } - - //Calling Dispose on BurstTensorData will sync the fences, so this is a performance VS memory peak tradeoff here. - T?.Dispose(); - - return ApplyFusedActivation(O, fusedActivation); - } - - /// - public override Tensor MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewOutputTensor(X.dataType,X.shape.ApplyPool(pool, stride, pad)); - - var job = new MaxPool2DJobHelper(); - job.strideX = stride[0]; - job.strideY = stride[1]; - job.padX = pad[0]; - job.padY = pad[1]; - - job.inHeight = X.height; - job.inWidth = X.width; - job.inChannels = X.channels; - job.inStrideN = X.height * X.width * X.channels; - job.inStrideH = X.width * X.channels; - job.inStrideW = X.channels; - - job.kernelWidth = pool[0]; - job.kernelHeight = pool[1]; - - job.outBatch = O.batch; - job.outWidth = O.width; - job.outStrideN = O.height * O.width * O.channels; - job.outStrideH = O.width * O.channels; - job.outStrideW = O.channels; - - job.ScheduleXO(X, O, O.height, 4); - - return O; - } - - /// - public override Tensor AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewOutputTensor(X.dataType,X.shape.ApplyPool(pool, stride, pad)); - - var job = new AvgPool2DJobHelper(); - job.strideX = stride[0]; - job.strideY = stride[1]; - job.padX = pad[0]; - job.padY = pad[1]; - - job.inHeight = X.height; - job.inWidth = X.width; - job.inChannels = X.channels; - job.inStrideN = X.height * X.width * X.channels; - job.inStrideH = X.width * X.channels; - job.inStrideW = X.channels; - - job.kernelWidth = pool[0]; - job.kernelHeight = pool[1]; - - job.outBatch = O.batch; - job.outWidth = O.width; - job.outStrideN = O.height * O.width * O.channels; - job.outStrideH = O.width * O.channels; - job.outStrideW = O.channels; - - job.ScheduleXO(X, O, O.height, 4); - - return O; - } - - /// - public override Tensor GlobalMaxPool2D(Tensor X) - { - return MaxPool2D(X, new[] {X.width, X.height}, new[] {1, 1}, new[] {0, 0, 0, 0}); - } - - /// - public override Tensor GlobalAvgPool2D(Tensor X) - { - return AvgPool2D(X, new[] {X.width, X.height}, new[] {1, 1}, new[] {0, 0, 0, 0}); - } - - /// - public override Tensor DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - if (K.kernelDepth != 1) - return base.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(K.kernelDepth, 1); - Assert.AreEqual(K.kernelCount, X.channels); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewTensorForFusedActivation(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad), fusedActivation); - - var job = new DepthwiseConv2DJobHelper(); - - job.strideX = stride[0]; - job.strideY = stride[1]; - job.padX = pad[0]; - job.padY = pad[1]; - - job.inHeight = X.height; - job.inWidth = X.width; - job.inChannels = X.channels; - job.inStrideN = X.height * X.width * X.channels; - job.inStrideH = X.width * X.channels; - job.inStrideW = X.channels; - - job.kernelCount = K.kernelCount; - job.kernelHeight = K.kernelHeight; - job.kernelWidth = K.kernelWidth; - job.kernelStrideH = K.height * K.width * K.channels; - job.kernelStrideW = K.width * K.channels; - - job.outBatch = O.batch; - job.outWidth = O.width; - job.outStrideN = O.height * O.width * O.channels; - job.outStrideH = O.width * O.channels; - job.outStrideW = O.channels; - - job.ScheduleXSBO(X, K, B, O, O.height, 4); - - return ApplyFusedActivation(O, fusedActivation); - } - - /// - public override Tensor ScaleBias(Tensor X, Tensor S, Tensor B) - { - if (!X.shape.Is4D()) - base.ScaleBias(X, S, B); - - Assert.AreEqual(S.shape, B.shape); - bool isScalarOp = (S.length == 1); - bool isSaVector = (S.length == S.channels); - bool isVectorOp = (X.channels == S.channels && isSaVector); - bool isTensorOp = (X.shape == S.shape); - Assert.IsTrue(isScalarOp || isVectorOp || isTensorOp); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.shape, X.shape); - - var jobData = new VectorBroadcastScaleBiasJobHelper(); - jobData.inOutChannels = O.channels; - jobData.alpha = 1; - jobData.ScheduleXSBO(X, S, B, O, O.length / O.channels, Math.Max(16, 1024 / O.channels)); - - return O; - } - - /// - public override Tensor Relu(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new ReluJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Relu6(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new Relu6JobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor LeakyRelu(Tensor X, float alpha) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new LeakyReluJobHelper(); - job.alpha = alpha; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Tanh(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new TanhJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Softplus(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new SoftplusJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Sigmoid(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new SigmoidJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor HardSigmoid(Tensor X, float alpha, float beta) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new HardSigmoidJobHelper(); - job.alpha = alpha; - job.beta = beta; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - - /// - public override Tensor Elu(Tensor X, float alpha) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new EluJobHelper(); - job.alpha = alpha; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Selu(Tensor X, float alpha, float gamma) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new SeluJobHelper(); - job.alpha = alpha; - job.gamma = gamma; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Swish(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new SwishJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor PRelu(Tensor X, Tensor S) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - - Assert.AreEqual(X.channels, O.channels); - Assert.IsTrue((X.flatWidth == S.flatWidth) || (S.flatWidth == 1)); - - var job = new PReluJobHelper(); - job.isGammaAVector = (S.flatWidth == 1) ? 0 : 1; - job.inOutChannels = O.channels; - job.ScheduleXBO(X, S, O, O.length / O.channels, Math.Max(16, 1024 / O.channels)); - - return O; - } - - internal static FencedMemoryAlloc s_maxValues = new FencedMemoryAlloc(); - internal static FencedMemoryAlloc s_expSums = new FencedMemoryAlloc(); - - /// - public override Tensor Softmax(Tensor X, int axis) - { - var O = NewOutputTensor(X.dataType, X.shape); - Assert.AreEqual(O.length, X.length); - Assert.AreEqual(O.flatWidth, X.flatWidth); - - axis = X.shape.Axis(axis); - - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - - //Allocate memory - Allocator memoryAllocator = Allocator.TempJob; - var reduceOpShape = X.shape.Reduce(axis); - s_maxValues.Allocate(reduceOpShape.length, pinX.dataType, JobsUtility.CacheLineSize, memoryAllocator); - s_expSums.Allocate(reduceOpShape.length, pinX.dataType, JobsUtility.CacheLineSize, memoryAllocator); - - int offsetReduce = 1; - for (int i = 7; i >= axis; i--) - offsetReduce *= reduceOpShape[i]; - - // x_max = X.max(axis=1) - { - var job = new ReduceMaxJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXO(pinX, s_maxValues, reduceOpShape.length, 1024); - } - // e_x_sum = Sum[exp(x[:,c] - x_max[:]), c] - { - var job = new ExpBiasReduceJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXBO(pinX, s_maxValues, s_expSums, reduceOpShape.length, 1024); - } - // exp(x[n,c] - x_max[n]) / e_x_sum[n] - { - var job = new SoftmaxEndJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXSBO(pinX, s_expSums, s_maxValues, pinO, O.length, 1024); - } - // free memory (in job) - unsafe { - var job = new MemFreeJob(); - job.allocator = memoryAllocator; - job.buffer0 = s_maxValues.rawPtr; - job.buffer1 = s_expSums.rawPtr; - job.Schedule(pinO.fence); - } - - s_maxValues.ClearState(); - s_expSums.ClearState(); - - return O; - } - - /// - public override Tensor LogSoftmax(Tensor X, int axis) - { - var O = NewOutputTensor(X.dataType, X.shape); - Assert.AreEqual(O.length, X.length); - Assert.AreEqual(O.flatWidth, X.flatWidth); - - axis = X.shape.Axis(axis); - - var pinX = Pin(X); - var pinO = Pin(O, uploadCache: false); - - //Allocate memory - Allocator memoryAllocator = Allocator.TempJob; - var reduceOpShape = X.shape.Reduce(axis); - s_maxValues.Allocate(reduceOpShape.length, pinX.dataType, JobsUtility.CacheLineSize, memoryAllocator); - s_expSums.Allocate(reduceOpShape.length, pinX.dataType, JobsUtility.CacheLineSize, memoryAllocator); - - int offsetReduce = 1; - for (int i = 7; i >= axis; i--) - offsetReduce *= reduceOpShape[i]; - - // x_max = X.max(axis=1) - { - var job = new ReduceMaxJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXO(pinX, s_maxValues, reduceOpShape.length, 1024); - } - // e_x_sum = Sum[exp(x[:,c] - x_max[:]), c] - { - var job = new ExpBiasReduceJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXBO(pinX, s_maxValues, s_expSums, reduceOpShape.length, 1024); - } - // (x[n,c] - x_max[n]) - log(e_x_sum[n]) - { - var job = new LogSoftmaxEndJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXSBO(pinX, s_expSums, s_maxValues, pinO, O.length, 1024); - } - // free memory (in job) - unsafe { - var job = new MemFreeJob(); - job.allocator = memoryAllocator; - job.buffer0 = s_maxValues.rawPtr; - job.buffer1 = s_expSums.rawPtr; - job.Schedule(pinO.fence); - } - - s_maxValues.ClearState(); - s_expSums.ClearState(); - - return O; - } - - /// - public override Tensor Abs(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new AbsJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Neg(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new NegJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Ceil(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new CeilJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Clip(Tensor X, float min, float max) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new ClipJobHelper(); - job.min = min; - job.max = max; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Floor(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new FloorJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Round(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new RoundJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Reciprocal(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new ReciprocalJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Pow(Tensor X, float alpha) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new PowJobHelper(); - job.alpha = alpha; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Exp(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new ExpJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Log(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new LogJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Sqrt(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new SqrtJobHelper(); - job.ScheduleXO(X, O , O.length, 1024); - - return O; - } - - /// - public override Tensor Acos(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new AcosJobHelper(); - job.ScheduleXO(X, O , O.length, 1024); - - return O; - } - - /// - public override Tensor Acosh(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new AcoshJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Asin(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new AsinJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Asinh(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new AsinhJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Atan(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new AtanJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Atanh(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new AtanhJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Cos(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new CosJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Cosh(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new CoshJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Sin(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new SinJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Sinh(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new SinhJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Tan(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new TanJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Erf(Tensor X) - { - var O = NewTensorLike(X, AllocScope.LayerOutput); - Assert.AreEqual(O.length, X.length); - - var job = new ErfJobHelper(); - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - private unsafe void AssignTensorStrides8D(Tensor X, int* strides) - { - strides[0] = (X.sequenceLength == 1) ? 0 : X.numberOfDirections * X.batch * X.extraDimension * X.depth * X.height * X.width * X.channels; - strides[1] = (X.numberOfDirections == 1) ? 0 : X.batch * X.extraDimension * X.depth * X.height * X.width * X.channels; - strides[2] = (X.batch == 1) ? 0 : X.extraDimension * X.depth * X.height * X.width * X.channels; - strides[3] = (X.extraDimension == 1) ? 0 : X.depth * X.height * X.width * X.channels; - strides[4] = (X.depth == 1) ? 0 : X.height * X.width * X.channels; - strides[5] = (X.height == 1) ? 0 : X.width * X.channels; - strides[6] = (X.width == 1) ? 0 : X.channels; - strides[7] = (X.channels == 1) ? 0 : 1; - } - - private void BroadcastAdd(ref Tensor O, Tensor X, Tensor Y, float alpha = 1f) - { - if(X.shape == O.shape && Y.length == 1) - { - var job = new ScalarBroadcastAddJobHelper(); - job.alpha = alpha; - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else if (X.shape == O.shape && Y.shape == O.shape) - { - var job = new BroadcastAddJobHelper(); - job.alpha = alpha; - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else - { - var job = new ElementwiseAddJobHelper(); - job.alpha = alpha; - job.shapeO = O.shape; - unsafe { - AssignTensorStrides8D(X, job.stridesX); - AssignTensorStrides8D(Y, job.stridesY); - } - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - } - - private void BroadcastSub(ref Tensor O, Tensor X, Tensor Y) - { - BroadcastAdd(ref O, X, Y, -1f); - } - - private void BroadcastMul(ref Tensor O, Tensor X, Tensor Y) - { - if(X.shape == O.shape && Y.length == 1) - { - var job = new ScalarBroadcastMulJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else if (X.shape == O.shape && Y.shape == O.shape) - { - var job = new BroadcastMulJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else - { - var job = new ElementwiseMulJobHelper(); - job.shapeO = O.shape; - unsafe - { - AssignTensorStrides8D(X, job.stridesX); - AssignTensorStrides8D(Y, job.stridesY); - } - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - } - - private void BroadcastDiv(ref Tensor O, Tensor X, Tensor Y) - { - if(X.shape == O.shape && Y.length == 1) - { - var job = new ScalarBroadcastDivJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else if (X.shape == O.shape && Y.shape == O.shape) - { - var job = new BroadcastDivJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else - { - var job = new ElementwiseDivJobHelper(); - job.shapeO = O.shape; - unsafe - { - AssignTensorStrides8D(X, job.stridesX); - AssignTensorStrides8D(Y, job.stridesY); - } - job.ScheduleXBO(X, Y, O , O.length, 1024); - } - } - - private void BroadcastPow(ref Tensor O, Tensor X, Tensor Y) - { - if (X.shape == O.shape && Y.length == 1) - { - var job = new ScalarBroadcastPowJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else if (X.shape == O.shape && Y.shape == O.shape) - { - var job = new BroadcastPowJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else - { - var job = new ElementwisePowJobHelper(); - job.shapeO = O.shape; - unsafe - { - AssignTensorStrides8D(X, job.stridesX); - AssignTensorStrides8D(Y, job.stridesY); - } - job.ScheduleXBO(X, Y, O, O.length, 1024); } - } - - private void BroadcastMin(ref Tensor O, Tensor X, Tensor Y) - { - if(X.shape == O.shape && Y.length == 1) - { - var job = new ScalarBroadcastMinJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else if (X.shape == O.shape && Y.shape == O.shape) - { - var job = new BroadcastMinJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else - { - var job = new ElementwiseMinJobHelper(); - job.shapeO = O.shape; - unsafe - { - AssignTensorStrides8D(X, job.stridesX); - AssignTensorStrides8D(Y, job.stridesY); - } - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - } - - private void BroadcastMax(ref Tensor O, Tensor X, Tensor Y) - { - if(X.shape == O.shape && Y.length == 1) - { - var job = new ScalarBroadcastMaxJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else if (X.shape == O.shape && Y.shape == O.shape) - { - var job = new BroadcastMaxJobHelper(); - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - else - { - var job = new ElementwiseMaxJobHelper(); - job.shapeO = O.shape; - unsafe - { - AssignTensorStrides8D(X, job.stridesX); - AssignTensorStrides8D(Y, job.stridesY); - } - job.ScheduleXBO(X, Y, O, O.length, 1024); - } - } - - private Tensor AddHelper(Tensor[] tensors, AllocScope outputScope) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - return base.Add(tensors); - - var O = NewTensorLike(tensors, outputScope); - var X = tensors[0]; - - for (int t = 1; t < tensors.Length; ++t) - { - BroadcastAdd(ref O, X, tensors[t]); - X = O; - } - return O; - } - - /// - // O = tensors[0] + tensors[1] + ... + tensors[N-1] - public override Tensor Add(Tensor[] tensors) - { - return AddHelper(tensors, AllocScope.LayerOutput); - } - - /// - // O = tensors[0] - tensors[1] - ... - tensors[N-1] - public override Tensor Sub(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - return base.Sub(tensors); - - - var O = NewTensorLike(tensors, AllocScope.LayerOutput); - var X = tensors[0]; - - for (int t = 1; t < tensors.Length; ++t) - { - BroadcastSub(ref O, X, tensors[t]); - X = O; - } - return O; - } - - /// - // O = tensors[0] * tensors[1] * ... * tensors[N-1] - public override Tensor Mul(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - return base.Mul(tensors); - - - var O = NewTensorLike(tensors, AllocScope.LayerOutput); - var X = tensors[0]; - - for (int t = 1; t < tensors.Length; ++t) - { - BroadcastMul(ref O, X, tensors[t]); - X = O; - } - return O; - } - - /// - // O = tensors[0] / tensors[1] / ... / tensors[N-1] - public override Tensor Div(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - return base.Div(tensors); - - - var O = NewTensorLike(tensors, AllocScope.LayerOutput); - var X = tensors[0]; - - for (int t = 1; t < tensors.Length; ++t) - { - BroadcastDiv(ref O, X, tensors[t]); - X = O; - } - return O; - } - - /// - // O = tensors[0] ^ tensors[1] ^ ... ^ tensors[N-1] - public override Tensor Pow(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - return base.Pow(tensors); - - - var O = NewTensorLike(tensors, AllocScope.LayerOutput); - var X = tensors[0]; - - for (int t = 1; t < tensors.Length; ++t) - { - BroadcastPow(ref O, X, tensors[t]); - X = O; - } - return O; - } - - /// - // O = min(tensors[0], tensors[1], ... , tensors[N-1]) - public override Tensor Min(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - return base.Min(tensors); - - var O = NewTensorLike(tensors, AllocScope.LayerOutput); - var X = tensors[0]; - - for (int t = 1; t < tensors.Length; ++t) - { - BroadcastMin(ref O, X, tensors[t]); - X = O; - } - return O; - } - - /// - // O = max(tensors[0], tensors[1], ... , tensors[N-1]) - public override Tensor Max(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - return base.Max(tensors); - - var O = NewTensorLike(tensors, AllocScope.LayerOutput); - var X = tensors[0]; - - for (int t = 1; t < tensors.Length; ++t) - { - BroadcastMax(ref O, X, tensors[t]); - X = O; - } - return O; - } - - // // O = (1/N) * (tensors[0] + tensors[1] + ... + tensors[N-1]) - // public override Tensor Mean(Tensor[] tensors) - // { - // if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - // base.Mean(tensors); - - // // accumulate - // Func op = (a, b) => a + b; - // var O = ApplyElementwiseWithBroadcast(tensors, op); - - // // div by N - // var invN = 1.0f / tensors.Length; - // var end = O.length; - // for (int i = 0; i < O.length; ++i) - // { - // float v = O[i]; - // v *= invN; - // O[i] = v; - // } - // return O; - // } - - /// - protected override Tensor CopyAndReshape(Tensor X, TensorShape shape) - { - Assert.AreEqual(X.length, shape.length); - var O = NewOutputTensor(X.dataType, shape); - - var job = new CopyJobHelper(); - job.length = O.length; - job.ScheduleXO(X, O); - - return O; - } - - public override Tensor Reshape(Tensor X, TensorShape newShape) - { - if (X.shape == newShape) - return base.Reshape(X, newShape); - - return CopyAndReshape(X, newShape); - } - - /// - public override Tensor Concat(Tensor[] tensors, int axis) - { - var concatShape = TensorExtensions.Concat(tensors, axis); - var dataType = tensors.Length > 0 ? tensors[0].dataType : DataType.Float; - var O = NewOutputTensor(dataType, concatShape); - - unsafe - { - // product of all tensor dimensions starting from axis - var copyBlockLengths = stackalloc int[tensors.Length]; - var copyBlockLengthsAcum = stackalloc int[tensors.Length]; - int copyBlockLengthsSum = 0; - for (int i = 0; i < tensors.Length; ++i) - { - copyBlockLengthsAcum[i] = copyBlockLengthsSum; - copyBlockLengths[i] = (int)GetAggregatedDimLength(tensors[i].shape, tensors[i].shape.Axis(axis), TensorShape.MaxRank); - copyBlockLengthsSum += copyBlockLengths[i]; - } - - // copy tensor data interleaved into O - int takes = (int)GetAggregatedDimLength(concatShape, 0, concatShape.Axis(axis)); - var pinO = Pin(O, uploadCache: false); - using (var ctx = new ParallelJobsContext(pinO)) - { - for (int i = 0; i < tensors.Length; ++i) - { - var pinX = Pin(tensors[i]); - var job = new CopyStrideJobHelper(); - job.OStride = copyBlockLengthsSum; - job.XStride = copyBlockLengths[i]; - job.length = copyBlockLengths[i]; - job.count = takes; - ctx.ScheduleXO(job, pinX, 0, pinO, copyBlockLengthsAcum[i]); - } - } - } - return O; - } - - /// - public override Tensor StridedSlice(Tensor X, int[] starts4Dor8D, int[] ends4Dor8D, int[] strides4Dor8D) - { - return StridedSliceHelper(X, starts4Dor8D, ends4Dor8D, strides4Dor8D, AllocScope.LayerOutput); - } - - private Tensor StridedSliceHelper(Tensor X, int[] starts4Dor8D, int[] ends4Dor8D, int[] strides4Dor8D, AllocScope outputScope) - { - unsafe - { - int* starts = stackalloc int[TensorShape.MaxRank]; - int* ends = stackalloc int[TensorShape.MaxRank]; - int* strides = stackalloc int[TensorShape.MaxRank]; - TensorExtensions.Get8DParametersNoAlloc(X.shape, starts4Dor8D, starts, 0); - TensorExtensions.Get8DParametersNoAlloc(X.shape, ends4Dor8D, ends, 1); - TensorExtensions.Get8DParametersNoAlloc(X.shape, strides4Dor8D, strides, 1); - - var O = NewTensor(X.dataType, X.shape.ApplyStridedSlice8DUnsafeNoAlloc(starts, ends, strides), outputScope); - - int* wrappedStartsIndices = ends; //reuse buffer to save a stack allocation. - for (int i = 0; i < TensorShape.MaxRank; ++i) - wrappedStartsIndices[i] = Math.Min(TensorExtensions.WrapIndex(starts[i], X.shape[i]), X.shape[i] - 1); - - Assert.AreEqual(8, TensorShape.MaxRank); - - //TODO/Idea for further optimisation: Add a version using UnsafeUtility.MemCpyStride when many strides are 1 (starting from C amd going upward). - if (strides[TensorShape.C] == 1) - { - var job = new GenericSliceJobHelper(); - job.shapeX = X.shape; - job.shapeO = O.shape; - job.startS = wrappedStartsIndices[0]; - job.startR = wrappedStartsIndices[1]; - job.startN = wrappedStartsIndices[2]; - job.startT = wrappedStartsIndices[3]; - job.startD = wrappedStartsIndices[4]; - job.startH = wrappedStartsIndices[5]; - job.startW = wrappedStartsIndices[6]; - job.startC = wrappedStartsIndices[7]; - job.strideS = strides[0]; - job.strideR = strides[1]; - job.strideN = strides[2]; - job.strideT = strides[3]; - job.strideD = strides[4]; - job.strideH = strides[5]; - job.strideW = strides[6]; - job.strideC = strides[7]; - int numCopy = O.shape.length / O.shape.channels; - job.ScheduleXO(X, O, numCopy, 64); - } - else - { - var job = new GenericStridedSliceJobHelper(); - job.shapeX = X.shape; - job.shapeO = O.shape; - job.startS = wrappedStartsIndices[0]; - job.startR = wrappedStartsIndices[1]; - job.startN = wrappedStartsIndices[2]; - job.startT = wrappedStartsIndices[3]; - job.startD = wrappedStartsIndices[4]; - job.startH = wrappedStartsIndices[5]; - job.startW = wrappedStartsIndices[6]; - job.startC = wrappedStartsIndices[7]; - job.strideS = strides[0]; - job.strideR = strides[1]; - job.strideN = strides[2]; - job.strideT = strides[3]; - job.strideD = strides[4]; - job.strideH = strides[5]; - job.strideW = strides[6]; - job.strideC = strides[7]; - job.ScheduleXO(X, O, O.length, 1024); - } - - return O; - } - } - - /// - public override Tensor Border2D(Tensor X, int[] pad, float constant) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pad.Length, 6); - - var O = NewOutputTensor(X.dataType, X.shape.ApplyBorder(pad)); - - int croppedWidth = X.width - Math.Max(0, -pad[3]); - int croppedHeight = X.height - Math.Max(0, -pad[4]); - int croppedChannels = X.channels - Math.Max(0, -pad[5]); - - var job = new Border2DJobHelper(); - - job.shapeX = X.shape; - job.shapeO = O.shape; - - job.PadWidth = pad[0]; - job.PadHeight = pad[1]; - job.PadChannels = pad[2]; - - job.CroppedWidth = croppedWidth; - job.CroppedHeight = croppedHeight; - job.CroppedChannels = croppedChannels; - - job.Beta = constant; - - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Pad2DReflect(Tensor X, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pad.Length, 6); - - var O = NewOutputTensor(X.dataType, X.shape.ApplyBorder(pad)); - - var job = new Pad2DReflectJobHelper(); - - job.shapeX = X.shape; - job.shapeO = O.shape; - - job.PadWidth = pad[0]; - job.PadHeight = pad[1]; - job.PadChannels = pad[2]; - - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Pad2DSymmetric(Tensor X, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pad.Length, 6); - - var O = NewOutputTensor(X.dataType, X.shape.ApplyBorder(pad)); - - var job = new Pad2DSymmetricJobHelper(); - - job.shapeX = X.shape; - job.shapeO = O.shape; - - job.PadWidth = pad[0]; - job.PadHeight = pad[1]; - job.PadChannels = pad[2]; - - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Pad2DEdge(Tensor X, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pad.Length, 6); - - var O = NewOutputTensor(X.dataType, X.shape.ApplyBorder(pad)); - - var job = new Pad2DEdgeJobHelper(); - - job.shapeX = X.shape; - job.shapeO = O.shape; - - job.PadWidth = pad[0]; - job.PadHeight = pad[1]; - job.PadChannels = pad[2]; - - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Transpose(Tensor X, int[] permutations) - { - return TransposeHelper(X, permutations, AllocScope.LayerOutput); - } - - private Tensor TransposeHelper(Tensor X, int[] permutations, AllocScope outputScope) - { - - var outPermutations = TensorExtensions.Get8DPermutationsForNHWCPermutationsAndShape( - X.shape, new NativeArray(permutations, Allocator.Temp)); - var O = NewTensor(X.dataType, X.shape.Permute(outPermutations), outputScope); - - var job = new TransposeJobHelper(); - job.shapeX = X.shape; - job.shapeO = O.shape; - unsafe - { - job.permutations[0] = outPermutations[0]; - job.permutations[1] = outPermutations[1]; - job.permutations[2] = outPermutations[2]; - job.permutations[3] = outPermutations[3]; - job.permutations[4] = outPermutations[4]; - job.permutations[5] = outPermutations[5]; - job.permutations[6] = outPermutations[6]; - job.permutations[7] = outPermutations[7]; - } - - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor ReduceMean(Tensor X, int axis) - { - axis = X.shape.Axis(axis); - var O = NewOutputTensor(X.dataType, X.shape.Reduce(axis)); - - int offsetReduce = 1; - for (int i = TensorShape.MaxRank - 1; i >= axis; i--) - offsetReduce *= O.shape[i]; - - var job = new ReduceMeanJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor ReduceSum(Tensor X, int axis) - { - axis = X.shape.Axis(axis); - var O = NewOutputTensor(X.dataType, X.shape.Reduce(axis)); - - int offsetReduce = 1; - for (int i = TensorShape.MaxRank - 1; i >= axis; i--) - offsetReduce *= O.shape[i]; - - var job = new ReduceSumJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - public override Tensor ReduceMax(Tensor X, int axis) - { - axis = X.shape.Axis(axis); - var O = NewOutputTensor(X.dataType, X.shape.Reduce(axis)); - - int offsetReduce = 1; - for (int i = TensorShape.MaxRank - 1; i >= axis; i--) - offsetReduce *= O.shape[i]; - - var job = new ReduceMaxJobHelper(); - job.offsetReduce = offsetReduce; - job.reduceDim = X.shape[axis]; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Tile(Tensor X, int[] repeats) - { - Tensor O = NewOutputTensor(X.dataType, X.shape.Scale(repeats)); - - var job = new TileJobHelper(); - job.shapeX = X.shape; - job.shapeO = O.shape; - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - /// - public override Tensor Gather(Tensor[] tensors, int axis) - { - Tensor X = tensors[0]; - Tensor indices = tensors[1]; - - var shape = X.shape; - shape[axis] = indices.length; - - var O = NewOutputTensor(X.dataType, shape); - - Assert.AreEqual(TensorShape.MaxRank, 8); - - var job = new GatherJobHelper(); - job.axis = axis; - job.shapeX = X.shape; - job.shapeO = O.shape; - job.ScheduleXBO(X, indices, O, O.length, 1024); - - return O; - } - - /// - public override Tensor OneHot(Tensor X, int depth, float onValue, float offValue, int inputRank=-1) - { - if (inputRank == -1) - inputRank = X.dimensions; - - if (inputRank >= 4) - throw new NotImplementedException(); - - Tensor O; - if (inputRank == 1) - O = NewOutputTensor(X.dataType, new TensorShape(X.flatHeight, depth)); - else if (inputRank == 2) - O = NewOutputTensor(X.dataType, new TensorShape(X.flatHeight, 1, depth, X.flatWidth)); - else - O = NewOutputTensor(X.dataType, new TensorShape(X.batch, X.width, depth, X.channels)); - - var job = new OneHotJobHelper(); - job.depth = depth; - job.shapeX = X.shape; - job.shapeO = O.shape; - job.inputRank = inputRank; - job.onValue = onValue; - job.offValue = offValue; - - job.ScheduleXO(X, O, O.length, 1024); - - return O; - } - - internal uint jobCountCall = 0; - - /// - public override Tensor RandomNormal(TensorShape s, float mean, float scale, int seed) - { - var O = NewOutputTensor(DataType.Float, s); - //TODO fp16: RandomNormal should be able to select output type - //see dtype here https://github.com/onnx/onnx/blob/master/docs/Operators.md#RandomNormal - - var pinO = Pin(O, uploadCache: false); - - var job = new RandomNormalJobHelper(); - // seed is combined with jobCountCall to keep rng persistent over frame - var finalSeed = (uint) (seed ^ (++jobCountCall)); - job.rng = new Unity.Mathematics.Random(finalSeed != 0 ? finalSeed : 1); - job.mean = mean; - job.scale = scale; - job.ScheduleO(pinO, 0, O.length, 1024); - - return O; - } - - /// - public override Tensor RandomUniform(TensorShape s, float mean, float scale, int seed) - { - var O = NewOutputTensor(DataType.Float, s); - //TODO fp16: RandomNormal should be able to select output type - //see dtype here https://github.com/onnx/onnx/blob/master/docs/Operators.md#RandomUniform - - var pinO = Pin(O, uploadCache: false); - - var job = new RandomUniformJobHelper(); - - // seed is combined with jobCountCall to keep rng persistent over frame - var finalSeed = (uint) (seed ^ (++jobCountCall)); - job.rng = new Unity.Mathematics.Random(finalSeed != 0 ? finalSeed : 1); - job.mean = mean; - job.scale = scale; - job.ScheduleO(pinO, 0, O.length, 1024); - - return O; - } - - Tensor LSTMDense3Helper(Tensor X, Tensor W, Tensor B) - { - int xb = X.batch, xh = X.width, xw = X.channels; - int yh = W.batch, yw = W.channels; - - Assert.AreEqual(xw, yh); - var Otemp = NewTempTensor(X.dataType, new TensorShape(xb, 1, xh, yw)); - - var pinX = Pin(X); - var pinW = Pin(W); - var pinB = Pin(B); - var pinO = Pin(Otemp, uploadCache: false); - - unsafe - { - float* ptrX = pinX.array.AddressAt(pinX.offset); - float* ptrW = pinW.array.AddressAt(pinW.offset); - float* ptrB = pinB.array.AddressAt(pinB.offset); - float* ptrO = pinO.array.AddressAt(pinO.offset); - { - var job = new LSTMDense3Job(); - job.A = ptrX; - job.AM = xh; - job.AN = xw; - job.B = ptrW; - job.BM = yh; - job.BN = yw; - job.C = ptrB; - job.CN = B.channels; - job.S = ptrO; - job.SM = xh; - job.SN = yw; - - job.dispatchThreadX = ((xh + LSTMDense3Job.blockSize - 1) / LSTMDense3Job.blockSize); - job.dispatchThreadY = ((yw + LSTMDense3Job.blockSize - 1) / LSTMDense3Job.blockSize); - job.dispatchThreadZ = xb; - - pinO.fence = pinX.reuse = pinW.reuse = pinB.reuse = - job.Schedule(Dependencies(pinO.reuse, pinX.fence, pinW.fence, pinB.fence)); - } - } - - return Otemp; - } - - Tensor LSTMDenseHelper(Tensor X, Tensor W, Tensor B) - { - int xw = X.channels, xh = X.batch; - int yw = W.channels, yh = W.batch; - - Assert.AreEqual(xw, yh); - var Otemp = NewTempTensor(X.dataType, new TensorShape(xh, yw)); - - var pinX = Pin(X); - var pinW = Pin(W); - var pinB = Pin(B); - var pinO = Pin(Otemp, uploadCache: false); - - unsafe - { - float* ptrX = pinX.array.AddressAt(pinX.offset); - float* ptrW = pinW.array.AddressAt(pinW.offset); - float* ptrB = pinB.array.AddressAt(pinB.offset); - float* ptrO = pinO.array.AddressAt(pinO.offset); - { - var job = new LSTMDenseJob(); - job.A = ptrX; - job.AM = xh; - job.AN = xw; - job.B = ptrW; - job.BM = yh; - job.BN = yw; - job.C = ptrB; - job.CN = B.channels; - job.S = ptrO; - job.SM = xh; - job.SN = yw; - - job.dispatchThreadX = ((xh + LSTMDenseJob.blockSize - 1) / LSTMDenseJob.blockSize); - job.dispatchThreadY = ((yw + LSTMDenseJob.blockSize - 1) / LSTMDenseJob.blockSize); - - pinO.fence = pinX.reuse = pinW.reuse = pinB.reuse = - job.Schedule(Dependencies(pinO.reuse, pinX.fence, pinW.fence, pinB.fence)); - } - } - - return Otemp; - } - - public override Tensor[] LSTM(Tensor X, Tensor[] W, Tensor[] R, Tensor[] Wb, Tensor[] Rb, Tensor hidden, Tensor cell) - { - // Gate indices [iofj] - const int g_i = 0, g_o = 1, g_f = 2, g_j = 3; - - TensorShape xShape = X.shape; // X shape is [seq_length, batch_size, input_size] - int sequenceLength = xShape.batch; - int batchSize = xShape.channels; - int inputSize = xShape.width; - int hiddenSize = cell.channels; - - Tensor O = NewOutputTensor(X.dataType, new TensorShape(sequenceLength, batchSize, hiddenSize, 1)); - var pinO = Pin(O, uploadCache: false); - - var cell_out = NewOutputTensor(X.dataType, new TensorShape(batchSize, hiddenSize)); //TODO this can create fragmentation in ping pong buffer - var hidden_out = NewOutputTensor(X.dataType, new TensorShape(batchSize, hiddenSize));//TODO this can create fragmentation in ping pong buffer - var pinCellOut = Pin(cell_out, uploadCache: false); var pinHiddenOut = Pin(hidden_out, uploadCache: false); - - Tensor i_mad_w_tmp = null; - Tensor j_mad_w_tmp = null; - Tensor f_mad_w_tmp = null; - Tensor o_mad_w_tmp = null; - Tensor i_mad_w = null; - Tensor j_mad_w = null; - Tensor f_mad_w = null; - Tensor o_mad_w = null; - - // if platforms supports Blas, favor that path, this is faster than our Dense3 implem atm - - // transpose once for sequential Dense access - Tensor Xt = TransposeHelper(X, new[] { 0, 1, 3, 2 }, AllocScope.InternalToLayer); - var useBLAS = PreferBLAS != BLAS.Disabled; - if (!useBLAS) - { - i_mad_w = LSTMDense3Helper(Xt, W[g_i], Wb[g_i]); - j_mad_w = LSTMDense3Helper(Xt, W[g_j], Wb[g_j]); - f_mad_w = LSTMDense3Helper(Xt, W[g_f], Wb[g_f]); - o_mad_w = LSTMDense3Helper(Xt, W[g_o], Wb[g_o]); - } - - JobHandle jobFence = new JobHandle(); - for (int s = 0; s < sequenceLength; s++) - { - Tensor X_sequence = null; - if (useBLAS) - { - //Note/TODO: if Wb are not 4D tensors AddHelper will allocate via ping pong allocator leading to allocator fragmentation. - X_sequence = StridedSliceHelper(Xt, new[] { s, 0, 0, 0 }, new[] { s + 1, int.MaxValue, int.MaxValue, int.MaxValue }, new[] { 1, 1, 1, 1 }, AllocScope.InternalToLayer); - X_sequence = X_sequence.Reshape(new TensorShape(batchSize, inputSize)); - i_mad_w_tmp = MatMulHelper(X_sequence, false, W[g_i], false, null, null, null, AllocScope.InternalToLayer); - j_mad_w_tmp = MatMulHelper(X_sequence, false, W[g_j], false, null, null, null, AllocScope.InternalToLayer); - f_mad_w_tmp = MatMulHelper(X_sequence, false, W[g_f], false, null, null, null, AllocScope.InternalToLayer); - o_mad_w_tmp = MatMulHelper(X_sequence, false, W[g_o], false, null, null, null, AllocScope.InternalToLayer); - i_mad_w = AddHelper(new[]{i_mad_w_tmp, Wb[g_i]}, AllocScope.InternalToLayer); - j_mad_w = AddHelper(new[]{j_mad_w_tmp, Wb[g_j]}, AllocScope.InternalToLayer); - f_mad_w = AddHelper(new[]{f_mad_w_tmp, Wb[g_f]}, AllocScope.InternalToLayer); - o_mad_w = AddHelper(new[]{o_mad_w_tmp, Wb[g_o]}, AllocScope.InternalToLayer); - } - - var i_mad_r = LSTMDenseHelper(hidden, R[g_i], Rb[g_i]); - var j_mad_r = LSTMDenseHelper(hidden, R[g_j], Rb[g_j]); - var f_mad_r = LSTMDenseHelper(hidden, R[g_f], Rb[g_f]); - var o_mad_r = LSTMDenseHelper(hidden, R[g_o], Rb[g_o]); - - var pinCell = Pin(cell); var pinHidden = Pin(hidden); - var pinImadW = Pin(i_mad_w); var pinImadR = Pin(i_mad_r); - var pinJmadW = Pin(j_mad_w); var pinJmadR = Pin(j_mad_r); - var pinFmadW = Pin(f_mad_w); var pinFmadR = Pin(f_mad_r); - var pinOmadW = Pin(o_mad_w); var pinOmadR = Pin(o_mad_r); - - unsafe - { - float* ptrCell = pinCell.array.AddressAt(pinCell.offset); - float* ptrImadW = pinImadW.array.AddressAt(pinImadW.offset); float* ptrImadR = pinImadR.array.AddressAt(pinImadR.offset); - float* ptrJmadW = pinJmadW.array.AddressAt(pinJmadW.offset); float* ptrJmadR = pinJmadR.array.AddressAt(pinJmadR.offset); - float* ptrFmadW = pinFmadW.array.AddressAt(pinFmadW.offset); float* ptrFmadR = pinFmadR.array.AddressAt(pinFmadR.offset); - float* ptrOmadW = pinOmadW.array.AddressAt(pinOmadW.offset); float* ptrOmadR = pinOmadR.array.AddressAt(pinOmadR.offset); - float* ptrCellOut = pinCellOut.array.AddressAt(pinCellOut.offset); float* ptrHiddenOut = pinHiddenOut.array.AddressAt(pinHiddenOut.offset); - float* ptrO = pinO.array.AddressAt(pinO.offset); - { - var job = new LSTMEndJob(); - job.cell_out = ptrCellOut; - job.hidden_out = ptrHiddenOut; - job.i_mad_w = ptrImadW; - job.j_mad_w = ptrJmadW; - job.f_mad_w = ptrFmadW; - job.o_mad_w = ptrOmadW; - job.i_mad_r = ptrImadR; - job.j_mad_r = ptrJmadR; - job.f_mad_r = ptrFmadR; - job.o_mad_r = ptrOmadR; - job.cell = ptrCell; - job.O = ptrO; - job.sequenceIndexO = s; - job.sequenceIndexI = useBLAS ? 0 : s; - job.batchSize = batchSize; - job.hiddenSize = hiddenSize; - job.batchSizeR = hidden.batch; - - jobFence = pinCellOut.fence = pinHiddenOut.fence = - pinHidden.reuse = pinCell.reuse = - pinImadW.reuse = pinJmadW.reuse = pinFmadW.reuse = pinOmadW.reuse = - pinImadR.reuse = pinJmadR.reuse = pinFmadR.reuse = pinOmadR.reuse = - job.Schedule(batchSize*hiddenSize, 1024, JobHandle.CombineDependencies(pinO.reuse, pinCellOut.reuse, JobHandle.CombineDependencies(pinHiddenOut.reuse, - pinImadW.fence, JobHandle.CombineDependencies(pinJmadW.fence, pinFmadW.fence, JobHandle.CombineDependencies(pinOmadW.fence, - pinImadR.fence, JobHandle.CombineDependencies(pinJmadR.fence, pinFmadR.fence, JobHandle.CombineDependencies(pinOmadR.fence, pinCell.fence, pinHidden.fence))))))); - } - } - - hidden = hidden_out; - cell = cell_out; - - i_mad_r.Dispose(); - j_mad_r.Dispose(); - f_mad_r.Dispose(); - o_mad_r.Dispose(); - - if (useBLAS) - { - X_sequence.Dispose(); - i_mad_w_tmp.Dispose(); - j_mad_w_tmp.Dispose(); - f_mad_w_tmp.Dispose(); - o_mad_w_tmp.Dispose(); - i_mad_w.Dispose(); - j_mad_w.Dispose(); - f_mad_w.Dispose(); - o_mad_w.Dispose(); - } - } - - pinO.fence = jobFence; - - Xt.Dispose(); - if (!useBLAS) - { - i_mad_w.Dispose(); - j_mad_w.Dispose(); - f_mad_w.Dispose(); - o_mad_w.Dispose(); - } - - return new[] { O, hidden, cell }; - } -} - -} // namespace Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Ops.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Ops.cs.meta deleted file mode 100644 index bf4884f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaBurstCPU.Ops.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6bc05bfa1b9544e8a813df0c3eaab6b0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaCompute.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaCompute.cs deleted file mode 100644 index 38fcbf3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaCompute.cs +++ /dev/null @@ -1,2561 +0,0 @@ -using UnityEngine; -using UnityEngine.Assertions; -using System; -using System.Collections.Generic; -using Unity.Collections; - -/* -PERFORMANCE COMPARISON after the latest OPTIMIZATION pass -default @ be623ff20d72 VS compute-optimizations2 @ 13946c6c7e50 - -NOTES: -1) 33% in 1 batch cases and over 100% for 16 batch cases in most models -2) Most models saw boost with large batches due to "unrolling" of images over N,W,H dimensions in optimized Convolution kernel -3) INCEPTION saw large performance boost due to introduction of Convolution kernel that efficiently supports arbitrary input/output channel counts - -------------------------------------------------------------- -BASELINE: default @ be623ff20d72 -log comment: “Added Conv2d_L1Cache32 variant, removed extra check in the kernel, restored performance on older Radeons + Intel” - -VGG -@1 Exec #50: 95.2 ms, cpu: 1.0 ms, avg: 64.8 ms, result:OK -@16 Exec #8: 1108.1 ms, cpu: 1.2 ms, avg: 1112.6 ms, result:OK - -MOBILENET -@1 Exec #100: 37.9 ms, cpu: 7.9 ms, avg: 22.5 ms, result:OK -@16 Exec #32: 213.0 ms, cpu: 9.3 ms, avg: 216.3 ms, result:OK - -RES -@1 Exec #50: 42.4 ms, cpu: 7.0 ms, avg: 43.2 ms, result:OK -@16 Exec #15: 654.8 ms, cpu: 16.0 ms, avg: 682.6 ms, result:OK - -INCEPTION -@1 Exec #32: 86.8 ms, cpu: 21.8 ms, avg: 92.6 ms, result:OK -@16 Exec #8: 1344.2 ms, cpu: 26.4 ms, avg: 1349.7 ms, result:OK - - -PIX2PIX -@1 Exec #15: 279.0 ms, cpu: 2.5 ms, avg: 239.6 ms, result:OK -PIX2PIX_T -@1 Exec #32: 114.3 ms, cpu: 2.3 ms, avg: 117.2 ms, result:OK - - -------------------------------------------------------------- -OPTIMIZED: compute-optimizations2 @ 13946c6c7e50 -log comment: “Optimizations: added path that support arbitrary number of input and ouptut channels in Convolutions (toggled via STRICT_CHANNELS)” - -VGG -@1 Exec #50: 45.8 ms, cpu: 1.0 ms, avg: 46.5 ms, result:OK 39% -@16 Exec #16: 529.1 ms, cpu: 1.1 ms, avg: 539.6 ms, result:OK 106% - -MOBILENET -@1 Exec #100: 28.6 ms, cpu: 6.7 ms, avg: 16.8 ms, result:OK 33% -@16 Exec #48: 138.2 ms, cpu: 9.4 ms, avg: 116.4 ms, result:OK 85% - -RES -@1 Exec #50: 32.7 ms, cpu: 6.6 ms, avg: 33.6 ms, result:OK 28% -@16 Exec #31: 312.2 ms, cpu: 8.3 ms, avg: 319.4 ms, result:OK 113% - -INCEPTION -@1 Exec #50: 48.0 ms, cpu: 21.9 ms, avg: 55.2 ms, result:OK 67% -@16 Exec #32: 188.7 ms, cpu: 25.7 ms, avg: 198.4 ms, result:OK 580% - -PIX2PIX -@1 Exec #32: 152.2 ms, cpu: 2.6 ms, avg: 154.6 ms, result:OK 55% -PIX2PIX_T -@1 Exec #32: 123.1 ms, cpu: 2.4 ms, avg: 107.1 ms, result:OK 9.4% - - -*/ - -namespace Unity.Barracuda { - -internal sealed class ComputeKernelLibrary -{ - static private StringCache s_StringCache = new StringCache(); - static private List s_DenseFP16Entries = new List(1); - static private List s_DenseFP32Entries = new List(10); - static public List Dense(TensorShape X, TensorShape W, TensorShape O, int type) - { - var h = O.flatHeight; - var w = O.flatWidth; - - var entries = type > 0 ? s_DenseFP32Entries : s_DenseFP16Entries; - entries.Clear(); - - if (type == 0) // FP16 - { - entries.Add(new Entry("DenseFP16Div2", - Int3(w / 2, h), BigO(X.flatWidth) - // @TODO: w % 2 == 0 - )); - } - else // FP32 - { - entries.Add(new Entry("Dense_Tilled2x2_Cached", - Int3(ComputeHelper.IDivC(w, 2), ComputeHelper.IDivC(h, 2)), BigO(X.flatWidth)/2, - StrictAnd(w % 2 == 0 && h % 2 == 0 && X.flatWidth % 32 == 0), - (Application.platform == RuntimePlatform.Android) || - (Application.platform == RuntimePlatform.IPhonePlayer) || - (ComputeInfo.graphicsDeviceVendor.Contains("Intel")) - )); - entries.Add(new Entry("Dense_Tilled4x4_Cached", - Int3(ComputeHelper.IDivC(w, 4), ComputeHelper.IDivC(h, 4)), BigO(X.flatWidth)/4, - StrictAnd(w % 4 == 0 && h % 4 == 0 && X.flatWidth % 32 == 0), - (Application.platform == RuntimePlatform.Android) || - (Application.platform == RuntimePlatform.IPhonePlayer) || - (ComputeInfo.graphicsDeviceVendor.Contains("Intel")) - )); - entries.Add(new Entry("Dense_T8x8_R8x8", - Int3(w / 8, h / 8), BigO(X.flatWidth)/8, - StrictAnd(w % 64 == 0 && h % 64 == 0 && X.flatWidth % 64 == 0) - )); - entries.Add(new Entry("Dense_T16x16_R4x4", - Int3(w / 4, h / 4), BigO(X.flatWidth)/4, - StrictAnd(w % 64 == 0 && h % 64 == 0 && X.flatWidth % 64 == 0) - )); - entries.Add(new Entry("Dense_T8x8_R4x4", - Int3(w / 4, h / 4), BigO(X.flatWidth)/4, - StrictAnd(w % 32 == 0 && h % 32 == 0 && X.flatWidth % 32 == 0) - )); - - // old - entries.Add( - new Entry("DenseTiled64x64", - Int3(w / 4, h / 4), BigO(X.flatWidth)*1.33f/4, - StrictAnd(w % 4 == 0 && h % 4 == 0 - && X.flatWidth % 64 == 0 && ComputeInfo.supportsDense64x64) - )); - entries.Add(new Entry("DenseTiled32x32", - Int3(w / 2, h / 2), BigO(X.flatWidth)*1.33f/2, - StrictAnd(w % 2 == 0 && h % 2 == 0 - && X.flatWidth % 32 == 0 && ComputeInfo.supportsDense32x32) - )); - entries.Add(new Entry("DenseTiled16x16", - Int3(w, h), BigO(X.flatWidth)*1.33f, - StrictAnd(X.flatWidth % 16 == 0) - // @TODO: relax Strict constraint, only And part should be necessary due to mask - )); - - entries.Add(new Entry("Dense_L1Cached64", - Int3(w, h), BigO(X.flatWidth) - )); - - // optimized H == 1 fast path - entries.Add(new Entry("Dense_V_L1Cached64", - Int3(w, 1), 0.9f * BigO(X.flatWidth), - valid_: h == 1 - )); - } - - return entries; - } - - private static List s_MultidimMatMulEntries = new List(4); - static public List MultidimMatMul(TensorShape X, int rankX, TensorShape Y, int rankY, TensorShape O) - { - var entries = s_MultidimMatMulEntries; - entries.Clear(); - { - // rank3 x rank2 - if (rankX == 3 && rankY == 2) - { - var h = O.channels; - var w = O.width; - var n = O.batch; - - // R8x8 - entries.Add(new Entry("MultidimMatMul_T8x8_R8x8_AR3_BR2", - Int3(ComputeHelper.IDivC(w, 8), ComputeHelper.IDivC(h, 8), n), BigO(X.width) / 8, - valid_: w % 8 == 0 - )); - entries.Add(new Entry("MultidimMatMul_L1Cached64_AR3_BR2", - Int3(w, h, n), BigO(X.flatWidth) / 64 - )); - // // R4x4 - // entries.Add(new Entry("MultidimMatMul_T16x16_R4x4_AR3_BR2", - // Int3(w / 4, h / 4, n), BigO(X.width) / 4, - // StrictAnd(w % 64 == 0 && h % 64 == 0) - // )); - } - } - return entries; - } - private static List s_Dense3MulEntries = new List(4); - static public List Dense3(TensorShape X, TensorShape Y, TensorShape O) - { - var entries = s_Dense3MulEntries; - entries.Clear(); - { - // rank3 - var h = O.channels; - var w = O.width; - var n = O.batch; - - // R4x4 - // TODO optimize - entries.Add(new Entry("Dense3_T8x16_R4x4", - Int3(ComputeHelper.IDivC(w, 4), ComputeHelper.IDivC(h, 4), n), (BigO(X.width) / 8), - valid_: w % 32 == 0 && h % 16 == 0 - )); - // R8x8 - entries.Add(new Entry("Dense3_T8x8_R8x8", - Int3(ComputeHelper.IDivC(w, 8), ComputeHelper.IDivC(h, 8), n), (BigO(X.width) / 8)*0.7f, - valid_: w % 8 == 0 - )); - entries.Add(new Entry("Dense3_L1Cached64", - Int3(w, h, n), BigO(X.flatWidth)/64 - )); - } - return entries; - } - - private enum ChannelMode - { - Strict, - Lax - } - - private enum KernelMode - { - Strict, - Lax - } - - private const int k_MinimumThreads = 4096;//Heuristic to try to avoid R8x8 path when number of GPU threads would be to low for parallelism. - private const int k_MinimumKernelCountForT8x8_R8x8 = 32; - private const int k_MinimumPixelCountForT8x8_R8x8 = 64; - private const int k_MinimumPixelCountForT2x32_R8x8 = k_MinimumPixelCountForT8x8_R8x8 * 4;//T2_32 consume 4x more pixels per TG than T8x8 - private static bool IsT8x8_R8x8KernelValid(ChannelMode channelMode, KernelMode kernelMode, int c, int k, int h, int w, int n) - { - bool valid; - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW) - { - valid = ComputeInfo.supportsComputeSharedMemory; - if (channelMode==ChannelMode.Strict) - valid &= (c % 8) == 0; - - if (kernelMode==KernelMode.Strict) - valid &= (k % 64) == 0; - else - valid &= (k % 16) == 0; - } - else - { - //Conv2DKernelKxK_StrictC4K16_T8x8_R8x8 is only enabled in NCHW mode. - //The kernel was tested to be faster than R4x4 at various workload in NHWC too. However to avoid - //any potential regression and maintenance, the NHWC path is disabled of this kernel is disabled. - valid = false; - } - - //Performance wise this kernel will drop fast when k < 64 or w*h < 64. - valid &= k >= k_MinimumKernelCountForT8x8_R8x8; - valid &= (w*h) >= k_MinimumPixelCountForT8x8_R8x8; - - //If this kernel can't go wide enough we will probably waste GPU parallelism should prefer another kernel. - int numThreadsR8x8 = ComputeHelper.IDivC(k,8 ) * ComputeHelper.IDivC(w * h , 8) * n; - valid &= numThreadsR8x8 >= k_MinimumThreads; - - //valid &= (h*w) > (64*64); - - return valid; - } - - private static bool IsT2x32_R8x8KernelValid(ChannelMode channelMode, KernelMode kernelMode, int c, int k, int h, int w, int n) - { - bool valid; - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW) - { - valid = ComputeInfo.supportsComputeSharedMemory; - if (channelMode==ChannelMode.Strict) - valid &= (c % 4) == 0; - - if (kernelMode == KernelMode.Strict) - { - valid &= (k % 16) == 0; - } - } - else - { - //Conv2DKernelKxK_StrictC4K16_T2x32_R8x8 Only viable in NCHW mode perf wise. - valid = false; - } - - //Performance wise this kernel will drop fast when h*w < 128*128. - valid &= (h*w) > k_MinimumPixelCountForT2x32_R8x8; - - //If this kernel can't go wide enough we will probably waste GPU parallelism should prefer another kernel. - int numThreadsR8x8 = ComputeHelper.IDivC(k,8 ) * ComputeHelper.IDivC(w * h , 8) * n; - valid &= numThreadsR8x8 >= k_MinimumThreads; - - return valid; - } - - private static bool IsWinograd16x16_R4x4KernelValid(ChannelMode channelMode, KernelMode kernelMode, int c, int k, int h, int w, int n) - { - bool valid = (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW); // NHWC not implemented - - valid &= ComputeInfo.supportsComputeSharedMemory; - if (channelMode == ChannelMode.Strict) - valid &= (c % 8) == 0; - - if (kernelMode == KernelMode.Strict) - valid &= (k % 16) == 0; - - bool isMobile = (Application.platform == RuntimePlatform.Android) || (Application.platform == RuntimePlatform.IPhonePlayer); - bool isOSX = (Application.platform == RuntimePlatform.OSXEditor) || (Application.platform == RuntimePlatform.OSXPlayer); - bool isIntelUHD = ComputeInfo.graphicsDeviceVendor.Contains("Intel"); - // winograd always better on these platforms - if (isMobile || isOSX || isIntelUHD) - return valid; - - // Performance wise this kernel is less efficient than T8x8_R8x8 for lower channels count and big pixel dims - if ((k % 64) == 0) - valid &= (c >= 64) || (h*w <= 128*128); - - return valid; - } - - private static List s_Conv3DEntries = new List(4); - internal static List Conv3D(TensorShape X, TensorShape K, TensorShape O, int[] stride, int[] pad) - { - var n = O.batch; - var d = O.depth; - var h = O.height; - var w = O.width; - var k = K.kernelCount; - var c = X.channels; - - var entries = s_Conv3DEntries; - entries.Clear(); - - entries.Add(new Entry("Conv3D", - Int3(k, w, h), BigO(O.batch * X.depth * X.channels))); - - entries.Add(new Entry("Conv3DKernelKxK_LaxC8LaxK32_T8x16_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(d*w*h, 4), n), BigO(X.channels) * 0.8f, - valid_: (k>=8) && ComputeInfo.supportsComputeSharedMemory)); - - entries.Add(new Entry("Conv3DKernelKxK_StrictC8LaxK32_T8x16_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(d*w*h, 4), n), BigO(X.channels) * 0.7f, - valid_: (c % 8 == 0) && (k>=8) && ComputeInfo.supportsComputeSharedMemory)); - - entries.Add(new Entry("Conv3DKernelKxK_StrictC8StrictK32_T8x16_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(d*w*h, 4), n), BigO(X.channels) * 0.6f, - valid_: (c % 8 == 0) && (k % 32 == 0) && ComputeInfo.supportsComputeSharedMemory)); - - return entries; - } - - private static List s_Conv2DEntries = new List(16); - internal static List Conv2D(TensorShape X, TensorShape K, TensorShape O, int[] stride, int[] pad) - { - var n = O.batch; - var h = O.height; - var w = O.width; - var k = K.kernelCount; - var c = X.channels; - - var entries = s_Conv2DEntries; - entries.Clear(); - - // Mobile - // ARM + iPhone - entries.Add(new Entry("Conv2D_KernelKxK_T8x8_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(w*h, 4), n), BigO(X.channels) * 1.0f / 4, - valid_: ComputeInfo.IsiPhoneGPU() || ComputeInfo.IsARMGPU(), - devicePriority_: ComputeInfo.IsiPhoneGPU() || ComputeInfo.IsARMGPU())); - - entries.Add(new Entry("Conv2D_Kernel1x1_T8x8_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(w * h, 4), n), BigO(X.channels) * 0.8f / 4, - valid_: K.batch == 1 && K.height == 1 && (ComputeInfo.IsiPhoneGPU() || ComputeInfo.IsARMGPU()), - devicePriority_: ComputeInfo.IsiPhoneGPU() || ComputeInfo.IsARMGPU())); - // Qualcomm - entries.Add(new Entry("Conv2D_KernelKxK_T16x16_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(w * h, 4), n), BigO(X.channels) * 1.0f / 4, - valid_: ComputeInfo.IsQualcommGPU(), - devicePriority_: ComputeInfo.IsQualcommGPU())); - - entries.Add(new Entry("Conv2D_Kernel1x1_T16x16_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(w * h, 4), n), BigO(X.channels) * 0.8f / 4, - valid_: K.batch == 1 && K.height == 1 && ComputeInfo.IsQualcommGPU(), - devicePriority_: ComputeInfo.IsQualcommGPU())); - - entries.Add(new Entry("Conv2D_Winograd_2x2_Kernel3x3_LDS", - Int3(k, ComputeHelper.IDivC(w, 2), ComputeHelper.IDivC(h, 2)), BigO(X.channels) * (0.05f / 2.25f), - valid_: K.batch == 3 && K.height == 3 && (stride[0] == 1) && (stride[1] == 1) && w*h <= 128*128 && (c <= 64) && (O.channels < 64) && - ComputeInfo.IsQualcommGPU(), - devicePriority_: ComputeInfo.IsQualcommGPU())); - - // Winograd - // R4x4_T16x16 : R4x4 T16x(4x4) - entries.Add(new Entry("Conv2DWinograd_2x2_Kernel3x3_StrictC8StrictK16_T16x16_R4x4", - Int3(16*16 * ComputeHelper.IDivC(k, 16), ComputeHelper.IDivC(ComputeHelper.IDivC(w, 2) * ComputeHelper.IDivC(h, 2), 16), n), BigO(X.channels) * (0.8f / 64) * (1.0f/2.25f), - valid_: K.kernelWidth == 3 && K.kernelHeight == 3 && - stride[0] == 1 && stride[1] == 1 && - IsWinograd16x16_R4x4KernelValid(ChannelMode.Strict, KernelMode.Strict, c, k, h, w, n))); - entries.Add(new Entry("Conv2DWinograd_2x2_Kernel3x3_StrictC8LaxK16_T16x16_R4x4", - Int3(16*16 * ComputeHelper.IDivC(k, 16), ComputeHelper.IDivC(ComputeHelper.IDivC(w, 2) * ComputeHelper.IDivC(h, 2), 16), n), BigO(X.channels) * (0.9f / 64) * (1.0f/2.25f), - valid_: K.kernelWidth == 3 && K.kernelHeight == 3 && - stride[0] == 1 && stride[1] == 1 && - IsWinograd16x16_R4x4KernelValid(ChannelMode.Strict, KernelMode.Lax, c, k, h, w, n))); - // R8x8_16k - entries.Add( - new Entry("Conv2DKernelKxK_LaxC4StrictK16_T2x32_R8x8", - Int3(ComputeHelper.IDivC(k, 8), ComputeHelper.IDivC(w*h, 8), n), BigO(X.channels) * 1.3f, - valid_: IsT2x32_R8x8KernelValid(ChannelMode.Lax,KernelMode.Strict,c,k,h,w,n))); - - entries.Add(new Entry("Conv2DKernelKxK_StrictC4LaxK16_T2x32_R8x8", - Int3(ComputeHelper.IDivC(k, 8), ComputeHelper.IDivC(w*h, 8), n), BigO(X.channels) * 1.2f, - valid_: IsT2x32_R8x8KernelValid(ChannelMode.Strict,KernelMode.Lax,c,k,h,w,n))); - - entries.Add(new Entry("Conv2DKernelKxK_StrictC4StrictK16_T2x32_R8x8", - Int3(ComputeHelper.IDivC(k, 8), ComputeHelper.IDivC(w*h, 8), n), BigO(X.channels) * 1.1f, - valid_: IsT2x32_R8x8KernelValid(ChannelMode.Strict,KernelMode.Strict,c,k,h,w,n))); - - // R8x8_64k - entries.Add(new Entry("Conv2DKernelKxK_StrictC16StrictK64_T8x8_R8x8", - Int3(ComputeHelper.IDivC(k, 8), ComputeHelper.IDivC(w*h, 8), n), BigO(X.channels) * 0.7f, - valid_: IsT8x8_R8x8KernelValid(ChannelMode.Strict, KernelMode.Strict,c,k,h,w,n))); - - entries.Add(new Entry("Conv2DKernelKxK_StrictC16LaxK64_T8x8_R8x8", - Int3(ComputeHelper.IDivC(k, 8), ComputeHelper.IDivC(w*h, 8), n), BigO(X.channels) * 0.75f, - valid_: IsT8x8_R8x8KernelValid(ChannelMode.Strict, KernelMode.Lax,c,k,h,w,n))); - - // R4x4 - int r4x4dispatchY = (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NHWC) ? n * w * h : w * h; - int r4x4dispatchZ = (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NHWC) ? 1 : n; - entries.Add(new Entry("Conv2DKernel1x1_StrictC16K64_T16x16_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(r4x4dispatchY, 4), r4x4dispatchZ), BigO(X.channels) * 0.8f / 4, - K.kernelWidth == 1 && K.kernelHeight == 1 && - stride[0] == 1 && stride[1] == 1 && - (k % 64) == 0 && (c % 16) == 0 && - ComputeInfo.supportsComputeSharedMemory)); - - entries.Add(new Entry("Conv2DKernelKxK_StrictC16K64_T16x16_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(r4x4dispatchY, 4), r4x4dispatchZ), BigO(X.channels) * 0.9f / 4, - (k % 64) == 0 && (c % 16) == 0 && ComputeInfo.supportsComputeSharedMemory)); - - entries.Add(new Entry("Conv2DKernelKxK_T16x16_R4x4", - Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(r4x4dispatchY, 4), r4x4dispatchZ), BigO(X.channels) * 1.0f / 4, - k >= 16 && c >= 16 && ComputeInfo.supportsComputeSharedMemory)); -// entries.Add(new Entry("Conv2DKernelKxK_T16x16_R4x4", -// Int3(ComputeHelper.IDivC(k, 4), ComputeHelper.IDivC(n*w*h, 4)), BigO(X.channels) * 1.1f / 4)); - - // Old -// entries.Add(new Entry("Conv2D_L1Cached64_RegisterBlock4x4", -// Int3(K.kernelCount, w/4+1, h/4+1), BigO(O.batch * X.channels) * 1.1f / 4, -// (k % 64) == 0 && (c % 64) == 0 && ComputeInfo.supportsComputeSharedMemory)); -// -// entries.Add(new Entry("Conv2D_L1Cached32_RegisterBlock4x4", -// Int3(K.kernelCount, w/4+1, h/4+1), BigO(O.batch * X.channels) / 3, -// (k % 32) == 0 && (c % 32) == 0 && ComputeInfo.supportsComputeSharedMemory)); - - entries.Add(new Entry("Conv2D_RegisterBlock4x2", - Int3(K.kernelCount, w/4, h/2), BigO(O.batch * X.channels) * 1.1f / 2, - StrictAnd( - (w % 4) == 0 && (h % 2) == 0))); - - entries.Add(new Entry("Conv2D", - Int3(k, w, h), BigO(O.batch * X.channels))); - - return entries; - } - - private static List s_DepthwiseConv2DEntries = new List(1); - internal static List DepthwiseConv2D(TensorShape X, TensorShape K, TensorShape O, int[] stride) - { - var h = O.height; - var w = O.width; - - var entries = s_DepthwiseConv2DEntries; - entries.Clear(); - - entries.Add(new Entry("DepthwiseConv2D", - Int3(K.kernelCount, w, h), BigO(O.batch * X.channels))); - - entries.Add(new Entry("DepthwiseConv2D_Default", - Int3(K.kernelCount, w, h), BigO(O.batch), - valid_: ComputeInfo.IsQualcommGPU(), - devicePriority_: ComputeInfo.IsQualcommGPU())); - - entries.Add(new Entry("DepthwiseConv2D_Winograd_2x2_Kernel3x3", - Int3(K.kernelCount, ComputeHelper.IDivC(w, 2), ComputeHelper.IDivC(h, 2)), BigO(O.batch) * (1.0f / 2.25f), - valid_: K.batch == 3 && K.height == 3 && (stride[0] == 1) && (stride[1] == 1) && - ComputeInfo.IsQualcommGPU(), - devicePriority_: ComputeInfo.IsQualcommGPU())); - - // Too many registers, TODO re-order math - // entries.Add(new Entry("DepthwiseConv2D_Winograd_2x2_Kernel5x5", - // Int3(K.kernelCount, ComputeHelper.IDivC(w, 2), ComputeHelper.IDivC(h, 2)), BigO(O.batch) * (1.0f / 2.25f), - // valid_: K.batch == 5 && K.height == 5 && (stride[0] == 1) && (stride[1] == 1) && (K.kernelCount < 64), - // devicePriority_: ComputeInfo.IsMobileGPU()))); - - return entries; - } - - private static List s_Conv2DTransEntries = new List(2); - internal static List Conv2DTrans(TensorShape X, TensorShape K, TensorShape O) - { - var entries = s_Conv2DTransEntries; - entries.Clear(); - - entries.Add(new Entry("Conv2DTrans_KernelCached_K5x5_T16x16", - dispatch_: Int3(K.kernelCount, O.width, O.height), bigO_: BigO(O.batch * O.channels * X.channels) / 3, - valid_: (X.channels <= 256 && K.kernelHeight <= 5 && K.kernelWidth <= 5))); - - entries.Add(new Entry("Conv2DTrans", - dispatch_: Int3(K.kernelCount, O.width, O.height), bigO_: BigO(O.batch * O.channels * X.channels))); - - return entries; - } - - private static List s_ActivationEntries = new List(3); - internal static List Activation(TensorShape X, TensorShape O, string kernelName) - { - var entries = s_ActivationEntries; - entries.Clear(); - - entries.Add(new Entry(s_StringCache.Lookup(kernelName, "_FlatStrict"), - dispatch_: Int3(O.length/2), - bigO_: 0.8f* BigO(1), - strictDims: StrictAnd(O.length % 128 == 0))); - - entries.Add( new Entry(s_StringCache.Lookup(kernelName, "_Flat"), - dispatch_: Int3(O.length), - bigO_: BigO(1))); - - entries.Add(new Entry(s_StringCache.Lookup(kernelName, "_Loop"), - dispatch_: Int3(O.length), - bigO_: BigO(2), - loopStride_: 256)); - - return entries; - } - - private static List s_PReluEntries = new List(3); - internal static List PRelu(TensorShape X, TensorShape O) - { - var entries = s_PReluEntries; - entries.Clear(); - - entries.Add(new Entry("PRelu_CNyx2", - Int3(O.channels, O.batch * O.height * O.width), 1.0f, ComputeInfo.channelsOrder==ComputeInfo.ChannelsOrder.NHWC)); - - entries.Add(new Entry("PRelu_Flat", - Int3(O.length))); - - entries.Add(new Entry("PRelu_Loop", - Int3(O.length), BigO(2), 256)); - - return entries; - } - - private static List s_ScaleBiasEntries = new List(3); - internal static List ScaleBias(TensorShape X, TensorShape O) - { - var entries = s_ScaleBiasEntries; - entries.Clear(); - - entries.Add(new Entry("ScaleBias_CNyx2", - Int3(O.channels, O.batch * O.height * O.width), 1.0f, ComputeInfo.channelsOrder==ComputeInfo.ChannelsOrder.NHWC)); - - entries.Add(new Entry("ScaleBias_Flat", - Int3(O.length))); - - entries.Add(new Entry("ScaleBias_Loop", - Int3(O.length), BigO(2), 256)); - - return entries; - } - - private static List s_Upsample2DEntries = new List(2); - internal static List Upsample2D(TensorShape X, TensorShape O, int[] scale, bool bilinear) - { - var entries = s_Upsample2DEntries; - entries.Clear(); - - if (bilinear) - { - entries.Add( - new Entry("UpsampleBilinear2D_2x2", - Int3(O.width, O.height, O.channels), BigO(O.batch) * 0.8f, - (scale[0] == 2 && scale[1] == 2))); - entries.Add( - new Entry("UpsampleBilinear2D", - Int3(O.channels, O.width, O.height), BigO(O.batch))); - } - else - { - entries.Add( - // NOTE: dispatched over X (not O) - new Entry("Upsample2D", - Int3(X.channels, X.width, X.height), BigO(X.batch))); - } - - return entries; - } - - private static List s_Pool2DReduceEntries = new List(1); - internal static List Pool2DReduce(TensorShape X, TensorShape O, string kernelName) - { - var entries = s_Pool2DReduceEntries; - entries.Clear(); - - entries.Add(new Entry(kernelName, - Int3(O.channels, ComputeHelper.IDivC(X.width, 2), ComputeHelper.IDivC(X.height, 2)), BigO(O.batch))); - - return entries; - } - - private static List s_Pool2DEntries = new List(1); - internal static List Pool2D(TensorShape X, TensorShape O, string kernelName) - { - var entries = s_Pool2DEntries; - entries.Clear(); - - entries.Add( - //new Entry(kernelName + "_16x4x4", - // Int3(O.channels, O.width, O.height), BigO(O.batch) - //), - new Entry(kernelName, - Int3(O.channels, O.width, O.height), BigO(O.batch))); - - return entries; - } - - private static List s_PoolAvgVar2DEntries = new List(1); - internal static List PoolAvgVar2D(TensorShape X, TensorShape O, string kernelName) - { - var entries = s_PoolAvgVar2DEntries; - entries.Clear(); - - entries.Add( - //new Entry(kernelName + "_16x4x4", - // Int3(O.channels, O.width, O.height), BigO(O.batch) - //), - new Entry(kernelName, - Int3(O.channels, ComputeHelper.IDivC(X.width, 2), ComputeHelper.IDivC(X.height, 2)), BigO(O.batch))); - - return entries; - } - - private static List s_GlobalPool2DEntries = new List(1); - internal static List GlobalPool2D(TensorShape X, TensorShape O, string kernelName) - { - var entries = s_GlobalPool2DEntries; - entries.Clear(); - - entries.Add(new Entry(kernelName, - Int3(O.channels), BigO(O.batch))); - - return entries; - } - - private static List s_PartialReduceEntries = new List(1); - internal static readonly Dictionary s_PartialReduceKernelNames = new Dictionary { - {Layer.Type.ReduceMax, "PartialReduceMax"}, {Layer.Type.ReduceMean, "PartialReduceMean"}, - {Layer.Type.ReduceMin, "PartialReduceMin"}, {Layer.Type.ReduceProd, "PartialReduceProd"}, - {Layer.Type.ReduceSum, "PartialReduceSum"}}; - internal static readonly Dictionary s_PartialReduceLoopKernelNames = new Dictionary { - {Layer.Type.ReduceMax, "PartialReduceMax_Loop"}, {Layer.Type.ReduceMean, "PartialReduceMean_Loop"}, - {Layer.Type.ReduceMin, "PartialReduceMin_Loop"}, {Layer.Type.ReduceProd, "PartialReduceProd_Loop"}, - {Layer.Type.ReduceSum, "PartialReduceSum_Loop"}}; - internal static List PartialReduce(Layer.Type kernelName, int flatHeight, int reducedDim, int flatWidth) - { - var entries = s_PartialReduceEntries; - entries.Clear(); - - reducedDim = ComputeHelper.IDivC(reducedDim, 4); - - var unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - var unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - entries.Add(new Entry(s_PartialReduceKernelNames[kernelName], - Int3(flatHeight, reducedDim, flatWidth), BigO((int)Mathf.Log((float)reducedDim)), valid_: (flatHeight < (int)ComputeFunc.SafeDispatchLimit) && (flatWidth < (int)ComputeFunc.SafeDispatchLimit))); - entries.Add(new Entry(s_PartialReduceLoopKernelNames[kernelName], - Int3(flatHeight / unrolledH, reducedDim, flatWidth / unrolledW), 1.2f*BigO(unrolledH * unrolledW * (int)Mathf.Log((float)reducedDim)))); - return entries; - } - - private static List s_PartialExpBiasReduceEntries = new List(1); - internal static List PartialExpBiasReduce(int flatHeight, int reducedDim, int flatWidth) - { - var entries = s_PartialExpBiasReduceEntries; - entries.Clear(); - - reducedDim = ComputeHelper.IDivC(reducedDim, 4); - - var unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - var unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - entries.Add(new Entry("PartialReduceExpBias", - Int3(flatHeight, reducedDim, flatWidth), BigO((int)Mathf.Log((float)reducedDim)), valid_: (flatHeight < (int)ComputeFunc.SafeDispatchLimit) && (flatWidth < (int)ComputeFunc.SafeDispatchLimit))); - entries.Add(new Entry("PartialReduceExpBias_Loop", - Int3(flatHeight / unrolledH, reducedDim, flatWidth / unrolledW), 1.2f*BigO(unrolledH * unrolledW * (int)Mathf.Log((float)reducedDim)))); - return entries; - } - - - private static List s_GlobalReduceEntries = new List(1); - internal static readonly Dictionary s_GlobalReduceKernelNames = new Dictionary { - {Layer.Type.ReduceMax, "GlobalReduceMax"}, {Layer.Type.ReduceMean, "GlobalReduceMean"}, - {Layer.Type.ReduceMin, "GlobalReduceMin"}, {Layer.Type.ReduceProd, "GlobalReduceProd"}, - {Layer.Type.ReduceSum, "GlobalReduceSum"}}; - internal static readonly Dictionary s_GlobalReduceLoopKernelNames = new Dictionary { - {Layer.Type.ReduceMax, "GlobalReduceMax_Loop"}, {Layer.Type.ReduceMean, "GlobalReduceMean_Loop"}, - {Layer.Type.ReduceMin, "GlobalReduceMin_Loop"}, {Layer.Type.ReduceProd, "GlobalReduceProd_Loop"}, - {Layer.Type.ReduceSum, "GlobalReduceSum_Loop"}}; - internal static List GlobalReduce(Layer.Type kernelName, int flatHeight, int reducedDim, int flatWidth) - { - var entries = s_GlobalReduceEntries; - entries.Clear(); - - var unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - var unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - entries.Add(new Entry(s_GlobalReduceKernelNames[kernelName], - Int3(flatHeight, 1, flatWidth), BigO((int)Mathf.Log((float)reducedDim)), valid_: (flatHeight < (int)ComputeFunc.SafeDispatchLimit) && (flatWidth < (int)ComputeFunc.SafeDispatchLimit))); - entries.Add(new Entry(s_GlobalReduceLoopKernelNames[kernelName], - Int3(flatHeight / unrolledH, 1, flatWidth / unrolledW), 1.2f*BigO(unrolledH * unrolledW * (int)Mathf.Log((float)reducedDim)))); - return entries; - } - - private static List s_GlobalExpBiasReduceEntries = new List(1); - internal static List GlobalExpBiasReduce(int flatHeight, int reducedDim, int flatWidth) - { - var entries = s_GlobalExpBiasReduceEntries; - entries.Clear(); - - var unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - var unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - entries.Add(new Entry("GlobalReduceExpBias", - Int3(flatHeight, 1, flatWidth), BigO((int)Mathf.Log((float)reducedDim)), valid_: (flatHeight < (int)ComputeFunc.SafeDispatchLimit) && (flatWidth < (int)ComputeFunc.SafeDispatchLimit))); - entries.Add(new Entry("GlobalReduceExpBias_Loop", - Int3(flatHeight / unrolledH, 1, flatWidth / unrolledW), 1.2f*BigO(unrolledH * unrolledW * (int)Mathf.Log((float)reducedDim)))); - return entries; - } - - - private static List s_NormalizationTailEntries = new List(3); - internal static List NormalizationTail(TensorShape X, TensorShape O) - { - var entries = s_NormalizationTailEntries; - entries.Clear(); - - entries.Add(new Entry("InstanceNormTail_CNyx2", - Int3(O.channels, O.batch * O.height * O.width), 1.0f, ComputeInfo.channelsOrder==ComputeInfo.ChannelsOrder.NHWC)); - - entries.Add(new Entry("InstanceNormTail_Flat", - Int3(O.length))); - - entries.Add(new Entry("InstanceNormTail_Loop", - Int3(O.length), BigO(2), 256)); - - return entries; - } - - private static List s_CopyEntries = new List(1); - internal static List Copy(TensorShape X, TensorShape O) - { - var entries = s_CopyEntries; - entries.Clear(); - - entries.Add( // NOTE: dispatched over X (not O) - new Entry("Copy", - Int3(X.channels, X.width, X.height), BigO(O.batch))); - - return entries; - } - - private static List s_TransposeToChannelFirst = new List(1); - internal static List TransposeToChannelFirst(TensorShape X, TensorShape O) - { - var entries = s_TransposeToChannelFirst; - entries.Clear(); - - entries.Add( // NOTE: dispatched over X (not O) - new Entry("TransposeToChannelFirst", - Int3(X.channels, X.width, X.height), BigO(O.batch))); - - return entries; - } - - private static List s_Transpose = new List(1); - internal static List Transpose(TensorShape X, TensorShape O) - { - var entries = s_Transpose; - entries.Clear(); - - entries.Add( // NOTE: dispatched over X (not O) - new Entry("Transpose", - Int3(X.channels, X.width, X.height), BigO(O.batch))); - - return entries; - } - - private static List s_Transpose8D = new List(1); - internal static List Transpose8D(TensorShape X, TensorShape O, ComputeInfo.ChannelsOrder cOrder) - { - var entries = s_Transpose8D; - entries.Clear(); - - if (cOrder == ComputeInfo.ChannelsOrder.NCHW) - entries.Add( // NOTE: dispatched over X (not O) - new Entry("Transpose8D", - Int3(X.width, X.height, X.depth), BigO(O.batch))); - else - entries.Add( // NOTE: dispatched over X (not O) - new Entry("Transpose8D", - Int3(X.channels, X.width, X.height), BigO(O.batch))); - - return entries; - } - - private static List s_Transpose2D = new List(1); - internal static List Transpose2D(TensorShape O) - { - var entries = s_Transpose2D; - entries.Clear(); - - entries.Add( - new Entry("Transpose2D", - Int3(O.flatWidth, O.flatHeight, 1), BigO(O.batch))); - - return entries; - } - - private static List s_ReshapeFromNHWCModelEntries = new List(2); - internal static List ReshapeFromNHWCModel(TensorShape O) - { - var entries = s_ReshapeFromNHWCModelEntries; - entries.Clear(); - - entries.Add( - new Entry("ReshapeFromNHWCModel_Flat", - Int3(O.channels, O.width, O.height))); - - entries.Add( - new Entry("ReshapeFromNHWCModel_Loop", - Int3(O.length), BigO(2), 256)); - - return entries; - } - - private static List s_PaddingEntries = new List(1); - internal static List Padding(TensorShape X, TensorShape O, string kernelName) - { - var entries = s_PaddingEntries; - entries.Clear(); - - entries.Add(new Entry(kernelName, - Int3(O.channels, O.width, O.height), BigO(O.batch))); - - return entries; - } - - private static List s_BroadcastEntries = new List(1); - internal static List Broadcast(TensorShape X, TensorShape O, string kernelName) - { - var entries = s_BroadcastEntries; - entries.Clear(); - - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NHWC) - entries.Add(new Entry(kernelName, Int3(O.channels, O.width, O.height), BigO(O.batch))); - else - entries.Add(new Entry(kernelName, Int3(O.width, O.height, O.channels), BigO(O.batch))); - return entries; - } - - static ValueTuple Int3(int x, int y = 1, int z = 1) { return ValueTuple.Create(x, y, z); } - static float BigO(int o) { return (float)o; } - internal struct StrictDimensions { public bool valid; } - static StrictDimensions StrictAnd(bool valid_) { return new StrictDimensions { valid = valid_ }; } - static StrictDimensions Strict() { return new StrictDimensions { valid = true }; } - - internal struct Entry - { - public readonly string name; - public readonly ValueTuple dispatch; - public readonly float bigO; - public readonly bool valid; - public readonly bool strict; - public readonly uint loopStride; // > 0 indicates looping kernel - public readonly bool devicePriority; - - public Entry(string name_, ValueTuple dispatch_, float bigO_ = 1.0f, bool valid_ = true, bool devicePriority_ = false) - { - name = name_; - dispatch = dispatch_; - bigO = bigO_; - valid = valid_; - strict = false; - loopStride = 0; - devicePriority = devicePriority_; - } - - public Entry(string name_, ValueTuple dispatch_, float bigO_, uint loopStride_) : - this(name_, dispatch_, bigO_) - { - loopStride = loopStride_; - } - - public Entry(string name_, ValueTuple dispatch_, float bigO_, StrictDimensions strictDims) : - this(name_, dispatch_, bigO_, strictDims.valid) - { - strict = true; - } - - public Entry(string name_, ValueTuple dispatch_, float bigO_, StrictDimensions strictDims, bool devicePriority_) : - this(name_, dispatch_, bigO_, strictDims.valid, devicePriority_) - { - strict = true; - } - } -} - -internal struct ComputeKernel -{ - readonly public ComputeFunc func; - readonly public ValueTuple dispatch; - public ComputeShader shader { get { return func.shader; } } - - public ComputeKernel(ComputeFunc func_, ValueTuple dispatch_) - { - func = func_; - dispatch = dispatch_; - } - - public void SetTensor(string name, TensorShape shape, ComputeBuffer buffer, Int64 dataOffset = 0) - { - func.SetTensor(name, shape, buffer, dataOffset); - } - public void SetTensor(ComputeFunc.TensorDecl tensorDecl, int dataPropId, TensorShape shape, ComputeBuffer buffer, Int64 dataOffset = 0) - { - func.SetTensor(tensorDecl, dataPropId, shape, buffer, dataOffset); - } - - public void SetTensorDecl(string name, TensorShape shape, Int64 dataOffset) - { - func.SetTensorDecl(name, shape, dataOffset); - } - public void SetTensorDecl(ComputeFunc.TensorDecl tensorDecl, TensorShape shape, Int64 dataOffset) - { - func.SetTensorDecl(tensorDecl, shape, dataOffset); - } - - public void SetTensorBuffer(string name, ComputeBuffer buffer) - { - func.SetTensorBuffer(name, buffer); - } - public void SetTensorBuffer(int propId, ComputeBuffer buffer) - { - func.SetTensorBuffer(propId, buffer); - } - - public void Dispatch() - { - func.Dispatch(dispatch); - } - - const long InvalidEntry = long.MaxValue; - internal static long CalculateEntryScore(ComputeShaderContext ctx, ComputeKernelLibrary.Entry entry, bool verbose, IModelExecutionsReporter reporter) - { - long work = InvalidEntry; - try - { - if (!entry.valid) - return InvalidEntry; - - // @TODO: @OPTIMIZE: cache threadGroupSize instead of creating ComputeFunc and querying every time - var fn = new ComputeFunc(ctx, entry.name, reporter); - - if (fn.threadGroupSizeX * fn.threadGroupSizeY * fn.threadGroupSizeZ > ComputeInfo.maxComputeWorkGroupSize) - return InvalidEntry; - - if (entry.strict) - { - if (entry.dispatch.Item1 % fn.threadGroupSizeX != 0 || - entry.dispatch.Item2 % fn.threadGroupSizeY != 0 || - entry.dispatch.Item3 % fn.threadGroupSizeZ != 0) - return InvalidEntry; - } - - var x = (long) ComputeFunc.IntDivCeil(entry.dispatch.Item1, (int) fn.threadGroupSizeX); - var y = (long) ComputeFunc.IntDivCeil(entry.dispatch.Item2, (int) fn.threadGroupSizeY); - var z = (long) ComputeFunc.IntDivCeil(entry.dispatch.Item3, (int) fn.threadGroupSizeZ); - - if (entry.loopStride == 0 && (x > 65535 || y > 65535 || z > 65535)) - { - if (verbose) - D.LogWarning($"Kernel {entry.name} dispatch arguments out of range (any [{x},{y},{z}] > 65535), skipping.."); - - return InvalidEntry; - } - - work = x * y * z; - - work *= (int) fn.threadGroupSize; - work = (long) (entry.bigO * work); - } - catch (ArgumentException) - { - if (verbose) - D.LogWarning($"Kernel processing failed, skipping {entry.name}"); - } - return work; - } - - internal static ComputeKernel BestKernel(ComputeShaderContext ctx, List entrees, bool verbose, IModelExecutionsReporter executionReporter) - { - var bestEntry = entrees[0]; - var bestScore = InvalidEntry; - bool foundKernelWithDevicePriority = false; - for (int i = 0; i < entrees.Count; i++) - { - var score = CalculateEntryScore(ctx, entrees[i], verbose, executionReporter); - bool entryDevicePriority = entrees[i].devicePriority; - - if (score == InvalidEntry) - continue; - - // first time we encounter a kernel with device priority - if (!foundKernelWithDevicePriority && entryDevicePriority) - { - bestScore = score; - bestEntry = entrees[i]; - } - // compute best entry: sort only on priority kernels (if some exist), else sort on non priority - else if ( (!foundKernelWithDevicePriority && !entryDevicePriority) || (foundKernelWithDevicePriority && entryDevicePriority)) - { - bestScore = (score <= bestScore) ? score : bestScore; - bestEntry = (score <= bestScore) ? entrees[i] : bestEntry; - } - - foundKernelWithDevicePriority = foundKernelWithDevicePriority || entryDevicePriority; - } - - if (verbose) - D.Log(bestEntry.name); - - var func = new ComputeFunc(ctx, bestEntry.name, executionReporter); - - if (bestEntry.loopStride > 0) - { - int preferedDispatch = (int)bestEntry.loopStride * (int)func.threadGroupSizeX; - var kernel = new ComputeKernel(func, (preferedDispatch, 1, 1)); - kernel.shader.SetInt("_LoopStride", preferedDispatch); - return kernel; - } - else - { - return new ComputeKernel(func, bestEntry.dispatch); - } - } - -} - -/// -/// GPU compute implementation of `IOps` -/// -public class ComputeOps : ReferenceComputeOps -{ - // --------------------------------------------------------------------------------- - private bool printKernels = false; - - // --------------------------------------------------------------------------------- - private bool m_Verbose; - - /// - /// Create `ComputeOps` - /// - /// allocator - /// verbose flag - public ComputeOps(ITensorAllocator allocator = null, bool verbose = false) - : base(allocator) - { - m_Verbose = verbose; - } - - // --------------------------------------------------------------------------------- - - internal ComputeKernel BestKernel(List entrees) - { - return ComputeKernel.BestKernel(ComputeShaderContext.Optimized, entrees, m_Verbose, GetModelExecutionsReporter()); - } - - internal ComputeKernel CompileKernel(ComputeKernelLibrary.Entry entry) - { - var func = new ComputeFunc(ComputeShaderContext.Optimized, entry.name, GetModelExecutionsReporter()); - if (entry.loopStride > 0) - { - int preferedDispatch = (int)entry.loopStride * (int)func.threadGroupSizeX; - var kernel = new ComputeKernel(func, (preferedDispatch, 1, 1)); - kernel.shader.SetInt("_LoopStride", preferedDispatch); - return kernel; - } - else - { - return new ComputeKernel(func, entry.dispatch); - } - } - - // --------------------------------------------------------------------------------- - - /// - public override Tensor MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - // MatMul implementation in terms of Dense - var A = (xTranspose) ? Transpose(X): X; - var B = (yTranspose) ? Transpose(Y): Y; - var Cshape = new TensorShape(1, B.flatWidth); // intialize bias with zeros - - ComputeBuffer buffer = new ComputeBuffer(B.shape.length + Cshape.length, sizeof(float)); - - var Bpacked = new Tensor(B.shape, new SharedComputeTensorData(buffer, B.shape, 0)); - var Cpacked = new Tensor(Cshape, new SharedComputeTensorData(buffer, Cshape, B.shape.length)); - - var fn_pack = new ComputeKernel(new ComputeFunc(ComputeShaderContext.Optimized, "MatMulPackB0Bias", GetModelExecutionsReporter()), (B.flatWidth, B.flatHeight, 1)); - fn_pack.SetTensor("X", B.shape, Pin(B).buffer); - fn_pack.SetTensor("O", Bpacked.shape, Pin(Bpacked).buffer); - - fn_pack.Dispatch(); - - var O = Dense(A, Bpacked, Cpacked, Layer.FusedActivation.None); - if (A != X) A.Dispose(); - if (B != Y) B.Dispose(); - - buffer.Dispose(); - - return O; - } - - /// - public override Tensor MatMul(Tensor X, int rankX, Tensor Y, int rankY) - { - if (!(rankX == 3 && rankY == 2)) - return base.MatMul(X, rankX, Y, rankY); - - var O = NewOutputTensor(X.dataType, new TensorShape(X.batch, 1, Y.channels, X.channels)); - - var fn = BestKernel(ComputeKernelLibrary.MultidimMatMul(X.shape, rankX, Y.shape, rankY, O.shape)); - - fn.SetTensor("A", X.shape, Pin(X).buffer); - fn.SetTensor("B", Y.shape, Pin(Y).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.Dispatch(); - - return O; - } - - /// - public override Tensor Dense3(Tensor X, Tensor W, Tensor B) - { - var O = NewOutputTensor(X.dataType, new TensorShape(X.batch, 1, W.channels, X.channels)); - - var fn = BestKernel(ComputeKernelLibrary.Dense3(X.shape, W.shape, O.shape)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("W", W.shape, Pin(W).offset); - fn.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(W).buffer, Pin(B).buffer); - fn.SetTensorBuffer("WBK", Pin(W).buffer); - - fn.Dispatch(); - - return O; - } - - /// - public override Tensor Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(W.dimensions <= 2); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(X.flatWidth, W.flatHeight); - - if (ShouldFlattenInputForDenseLayer(X.shape)) - X = Flatten(X); - - var O = NewTensorForFusedActivation(X.dataType, new TensorShape(X.flatHeight, W.flatWidth),fusedActivation); - - var itemSize = 4; // @TODO: itemSizeInBytes == 2 | float16 - var fn = BestKernel(ComputeKernelLibrary.Dense(X.shape, W.shape, O.shape, itemSize >> 2)); - - if (printKernels) - Debug.Log($"{fn.func.kernelName}: {O.shape} = {X.shape} * {W.shape}" ); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("W", W.shape, Pin(W).offset); - fn.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(W).buffer, Pin(B).buffer); - fn.SetTensorBuffer("WBK", Pin(W).buffer); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - Tensor Conv2DWinogradHelper(Tensor X, Tensor K, Tensor B, Tensor O, int[] stride, int[] pad, Layer.FusedActivation fusedActivation, ComputeKernel fn) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - // Winograd - // transform kernel - TensorShape Kws = new TensorShape(K.kernelHeight + 1, K.kernelWidth + 1, K.kernelDepth, K.kernelCount); - - ComputeBuffer buffer = new ComputeBuffer(Kws.length + B.shape.length, sizeof(float)); - var Ktransformed = new Tensor(Kws, new SharedComputeTensorData(buffer, Kws, 0)); - var Bpacked = new Tensor(B.shape, new SharedComputeTensorData(buffer, B.shape, Kws.length)); - - var fn_wk = new ComputeKernel(new ComputeFunc(ComputeShaderContext.Optimized, "KernelWinograd_3x3", GetModelExecutionsReporter()), (K.kernelCount, X.channels, B.length)); - - fn_wk.SetTensorDecl("K", K.shape, Pin(K).offset); - fn_wk.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn_wk.SetTensorBuffer("WBK", Pin(K).buffer); - fn_wk.SetTensor("O", Ktransformed.shape, Pin(Ktransformed, uploadCache: false).buffer); - fn_wk.Dispatch(); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("K", Ktransformed.shape, Pin(Ktransformed, uploadCache: false).offset); - fn.SetTensorDecl("B", Bpacked.shape, Pin(Bpacked, uploadCache: false).offset); - Assert.AreEqual(Pin(Ktransformed).buffer, Pin(Bpacked, uploadCache: false).buffer); - fn.SetTensorBuffer("WBK", Pin(Ktransformed, uploadCache: false).buffer); - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - fn.Dispatch(); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - buffer.Dispose(); - return O; - } - - /// - public override Tensor Conv3D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.IsNDHWC()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 3);//WHD - Assert.AreEqual(pad.Length, 6); - - var O = NewTensorForFusedActivation(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad), fusedActivation); - var fn = BestKernel(ComputeKernelLibrary.Conv3D(X.shape, K.shape, O.shape, stride, pad)); - - if (printKernels) - Debug.Log($"{fn.func.kernelName}: {O.shape} = {X.shape} # {K.shape} stride: {stride[0]},{stride[1]},,{stride[2]} pad:{pad[0]},{pad[1]}, ,{stride[2]}" ); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("K", K.shape, Pin(K).offset); - fn.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn.SetTensorBuffer("WBK", Pin(K).buffer); - - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewTensorForFusedActivation(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad), fusedActivation); - var fn = BestKernel(ComputeKernelLibrary.Conv2D(X.shape, K.shape, O.shape, stride, pad)); - - if (printKernels) - Debug.Log($"{fn.func.kernelName}: {O.shape} = {X.shape} # {K.shape} stride: {stride[0]},{stride[1]} pad:{pad[0]},{pad[1]}" ); - - if (fn.func.kernelName.StartsWith("Conv2DWinograd") || fn.func.kernelName.StartsWith("Conv2D_Winograd")) - { - return Conv2DWinogradHelper(X, K, B, O, stride, pad, fusedActivation, fn); - } - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("K", K.shape, Pin(K).offset); - fn.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn.SetTensorBuffer("WBK", Pin(K).buffer); - - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - Tensor DepthwiseConv2DWinogradHelper(Tensor X, Tensor K, Tensor B, Tensor O, int[] pad, Layer.FusedActivation fusedActivation, ComputeKernel fn) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(K.kernelDepth, 1); - Assert.AreEqual(K.kernelCount, X.channels); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(pad.Length, 4); - - // Winograd - // transform kernel - TensorShape Kws = new TensorShape(K.kernelHeight + 1, K.kernelWidth + 1, K.kernelDepth, K.kernelCount); - - ComputeBuffer buffer = new ComputeBuffer(Kws.length + B.shape.length, sizeof(float)); - var Ktransformed = new Tensor(Kws, new SharedComputeTensorData(buffer, Kws, 0)); - var Bpacked = new Tensor(B.shape, new SharedComputeTensorData(buffer, B.shape, Kws.length)); - - ComputeKernel fn_wk = new ComputeKernel(new ComputeFunc(ComputeShaderContext.Optimized, $"KernelWinograd_{K.batch}x{K.height}", GetModelExecutionsReporter()), (K.kernelCount, 1, B.length)); - - fn_wk.SetTensorDecl("K", K.shape, Pin(K).offset); - fn_wk.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn_wk.SetTensorBuffer("WBK", Pin(K).buffer); - fn_wk.SetTensor("O", Ktransformed.shape, Pin(Ktransformed, uploadCache: false).buffer); - fn_wk.Dispatch(); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("K", Ktransformed.shape, Pin(Ktransformed, uploadCache: false).offset); - fn.SetTensorDecl("B", Bpacked.shape, Pin(Bpacked, uploadCache: false).offset); - Assert.AreEqual(Pin(Ktransformed).buffer, Pin(Bpacked, uploadCache: false).buffer); - fn.SetTensorBuffer("WBK", Pin(Ktransformed, uploadCache: false).buffer); - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - fn.Dispatch(); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - buffer.Dispose(); - return O; - } - - /// - public override Tensor DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - if (K.kernelDepth != 1) - return base.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(K.kernelDepth, 1); - Assert.AreEqual(K.kernelCount, X.channels); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewTensorForFusedActivation(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad), fusedActivation); - var fn = BestKernel(ComputeKernelLibrary.DepthwiseConv2D(X.shape, K.shape, O.shape, stride)); - - if (fn.func.kernelName.StartsWith("DepthwiseConv2D_Winograd")) - { - return DepthwiseConv2DWinogradHelper(X, K, B, O, pad, fusedActivation, fn); - } - - if (printKernels) - Debug.Log($"{fn.func.kernelName}: {O.shape} = {X.shape} ∆ {K.shape} stride: {stride[0]},{stride[1]} pad:{pad[0]},{pad[1]}" ); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("K", K.shape, Pin(K).offset); - fn.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn.SetTensorBuffer("WBK", Pin(K).buffer); - - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - // unwrapp conv2d transpose as conv2d iff strides are low enough - // TODO: refactor this with an efficient conv2dtrans implementation - if(stride[0] * stride[1] <= 4) - { - return Conv2DTransAsConv2D(X, K, B, stride, pad, outputAdjustment, fusedActivation); - } - - var O = NewTensorForFusedActivation(X.dataType, X.shape.ApplyKernelInverse(K.shape, stride, pad, outputAdjustment), fusedActivation); - var fn = BestKernel(ComputeKernelLibrary.Conv2DTrans(X.shape, K.shape, O.shape)); - - pad = new int[] - { - K.kernelWidth - pad[0] - 1, K.kernelHeight - pad[1] - 1, - K.kernelWidth - pad[2] - 1, K.kernelHeight - pad[3] - 1 - }; - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("K", K.shape, Pin(K).offset); - fn.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn.SetTensorBuffer("WBK", Pin(K).buffer); - - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - private Tensor Conv2DTransAsConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - // conv2d trans as conv2d - pad = new int[] - { - K.kernelWidth - pad[0] - 1, K.kernelHeight - pad[1] - 1, - K.kernelWidth - pad[2] - 1, K.kernelHeight - pad[3] - 1 - }; - - // Unwrap ConvTrans as a call to Conv2D: - // https://arxiv.org/abs/1603.07285 - // Two pass algorithm: - // O-pad X, flip kernel and call Conv2D - - // 0-pad X accordingly: - // stride number of 0 between values of X - // outputAdjustment number of 0 at the end of X - // regular padding will be done in Conv2D - var XpaddedShape = new TensorShape(X.batch, stride[1] * (X.height - 1) + 1 + outputAdjustment[1], stride[0] * (X.width - 1) + 1 + outputAdjustment[0], X.channels); - var fn = new ComputeFunc(ComputeShaderContext.Optimized, "Conv2DTransPadFill", GetModelExecutionsReporter()); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", outputAdjustment); - fn.SetTensor("X", X.shape, Pin(X).buffer); - var Xpadded = Dispatch(fn, X.dataType, XpaddedShape, X.channels, X.width, X.height); - - // Flip kernel - // handle WBK case (K and B data share the same CB), copy B at the same time as flipping K - ComputeBuffer buffer = new ComputeBuffer(K.shape.length + B.shape.length, sizeof(float)); - - var Kflipped = new Tensor(K.shape, new SharedComputeTensorData(buffer, K.shape, 0)); - var Bpacked = new Tensor(B.shape, new SharedComputeTensorData(buffer, B.shape, K.shape.length)); - - var fn_flip = new ComputeKernel(new ComputeFunc(ComputeShaderContext.Optimized, "Conv2DTransFlipKernel", GetModelExecutionsReporter()), (K.kernelCount, X.channels, (K.kernelWidth*K.kernelHeight))); - fn_flip.SetTensorDecl("K", K.shape, Pin(K).offset); - fn_flip.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn_flip.SetTensorBuffer("WBK", Pin(K).buffer); - fn_flip.SetTensor("O", Kflipped.shape, Pin(Kflipped).buffer); - fn_flip.shader.SetInts("_Stride", stride); - fn_flip.shader.SetInts("_Pad", outputAdjustment); - - fn_flip.Dispatch(); - - var O = Conv2D(Xpadded, Kflipped, Bpacked, new int[] { 1, 1 }, pad, fusedActivation); - buffer.Dispose(); - return O; - } - - /// - public override Tensor Upsample2D(Tensor X, int[] scale, bool bilinear) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(scale.Length, 2); - - var O = NewOutputTensor(X.dataType, new TensorShape(X.batch, X.height*scale[1], X.width*scale[0], X.channels)); - var fn = BestKernel(ComputeKernelLibrary.Upsample2D(X.shape, O.shape, scale, bilinear)); - - if (printKernels) - D.Log($"{fn.func.kernelName}: {O.shape} = {X.shape} ^ size: {scale[0]},{scale[1]}" ); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts("_Pool", scale); - - - fn.Dispatch(); - return O; - } - - /// - protected override Tensor Pool2D(string kernelName, Tensor X, int[] pool, int[] stride, int[] pad) - { - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - - var O = NewOutputTensor(X.dataType, X.shape.ApplyPool(pool, stride, pad)); - var fn = BestKernel(ComputeKernelLibrary.Pool2D(X.shape, O.shape, kernelName)); - - if (printKernels) - D.Log($"{fn.func.kernelName}: {O.shape} = {X.shape} ^ pool: {pool[0]},{pool[1]} stride: {stride[0]},{stride[1]} pad:{pad[0]},{pad[1]}" ); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts("_Pool", pool); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor GlobalMaxPool2D(Tensor X) - { - return GlobalPool2D("MaxPool2DReduce", "GlobalMaxPool2D", X); - } - - /// - public override Tensor GlobalAvgPool2D(Tensor X) - { - return GlobalPool2D("AvgPool2DReduce", "GlobalAvgPool2D", X); - } - - Tuple GlobalAvgVariancePool2DReduceHelper(Tensor X, Tensor X2, bool isFirstDispatch) - { - var pool = new[] { 8, 8 }; - var stride = pool; - var pad = new[] { 0, 0, 0, 0 }; - string kernelName = "AvgVariancePool2DReduce"; - - var Oshape = X.shape.ApplyPool(pool, stride, pad, ceilMode: true); - var Otemp = NewTempTensor(X.dataType, new TensorShape(Oshape.batch, ComputeHelper.IDivC(Oshape.height, 2), ComputeHelper.IDivC(Oshape.width, 2), Oshape.channels)); - var O2temp = NewTempTensor(X.dataType, Otemp.shape); - - var fn = BestKernel(ComputeKernelLibrary.PoolAvgVar2D(X.shape, Otemp.shape, kernelName)); - - if (printKernels) - D.Log($"{fn.func.kernelName}: {Otemp.shape} = {X.shape} ^ pool: {pool[0]},{pool[1]} stride: {stride[0]},{stride[1]} pad:{pad[0]},{pad[1]}" ); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("X2", X2.shape, Pin(X2).buffer); - fn.SetTensor("O", Otemp.shape, Pin(Otemp, uploadCache: false).buffer); - fn.SetTensor("O2", O2temp.shape, Pin(O2temp, uploadCache: false).buffer); - - fn.shader.SetInts("_Pool", pool); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - fn.Dispatch(); - return new Tuple(Otemp,O2temp); - } - - /// - public override Tensor GlobalAvgVariancePool2D(Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - var inputDim = new [] {X.height, X.width}; - var X2 = X; // save a X^2 and do it in the first dispatch - bool isFirstDispatch = true; - // downsample with pyramid approach - while (X.height > 8*2 || X.width > 8*2) - { - var lastLength = X.length; - var XX2 = GlobalAvgVariancePool2DReduceHelper(X, X2, isFirstDispatch); - X = XX2.Item1; - X2 = XX2.Item2; - Assert.IsTrue(X.length < lastLength); - isFirstDispatch = false; - } - - var O = NewOutputTensor(X.dataType, new TensorShape(X.batch, 2, 1, X.channels)); - var fn = BestKernel(ComputeKernelLibrary.GlobalPool2D(X.shape, O.shape, "GlobalAvgVariancePool2D")); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("X2", X2.shape, Pin(X2).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.shader.SetInts("_Pool", inputDim); - fn.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - fn.Dispatch(); - return O; - } - - Tensor GlobalPool2DReduceHelper(string kernelName, Tensor X) - { - var pool = new[] { 8, 8 }; - var stride = pool; - var pad = new[] { 0, 0, 0, 0 }; - - var Oshape = X.shape.ApplyPool(pool, stride, pad, ceilMode: true); - var Otemp = NewTempTensor(X.dataType, new TensorShape(Oshape.batch, ComputeHelper.IDivC(Oshape.height, 2), ComputeHelper.IDivC(Oshape.width, 2), Oshape.channels)); - var fn = BestKernel(ComputeKernelLibrary.Pool2DReduce(X.shape, Otemp.shape, kernelName)); - - if (printKernels) - D.Log($"{fn.func.kernelName}: {Otemp.shape} = {X.shape} ^ pool: {pool[0]},{pool[1]} stride: {stride[0]},{stride[1]} pad:{pad[0]},{pad[1]}" ); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", Otemp.shape, Pin(Otemp, uploadCache: false).buffer); - - fn.shader.SetInts("_Pool", pool); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - - fn.Dispatch(); - return Otemp; - } - - internal static int[] s_GlobalPool2DInputDim = new int[2]; - - /// - /// Generic global 2D pooling - /// - /// small kernel name - /// global kernel name - /// input - /// output `Tensor` - protected virtual Tensor GlobalPool2D(string smallKernelName, string globalKernelName, Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - s_GlobalPool2DInputDim[0] = X.height; - s_GlobalPool2DInputDim[1] = X.width; - - // downsample with pyramid approach - while (X.height > 8*2 || X.width > 8*2) - { - var lastLength = X.length; - X = GlobalPool2DReduceHelper(smallKernelName, X); - Assert.IsTrue(X.length < lastLength); - } - - var O = NewOutputTensor(X.dataType, new TensorShape(X.batch, 1, 1, X.channels)); - var fn = BestKernel(ComputeKernelLibrary.GlobalPool2D(X.shape, O.shape, globalKernelName)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.shader.SetInts("_Pool", s_GlobalPool2DInputDim); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor ScaleBias(Tensor X, Tensor S, Tensor B) - { - if (!X.shape.Is4D()) - return base.ScaleBias(X, S, B); - - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - - var O = NewOutputTensor(X.dataType, X.shape); - var fn = BestKernel(ComputeKernelLibrary.ScaleBias(X.shape, O.shape)); - - if (printKernels) - D.Log(fn.func.kernelName); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl("W", S.shape, Pin(S).offset); - fn.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(S).buffer, Pin(B).buffer); - fn.SetTensorBuffer("WBK", Pin(S).buffer); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) - { - if (!X.shape.Is4D()) - throw new NotImplementedException(); - - if (axis != TensorShape.C && axis != -1) - return base.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); - - if (pool <= 0) - pool = X.batch; - - if (pool > 1) - throw new NotImplementedException(); // @TODO: support other types of Normalization at test time - // Currently supported only pool=1 (InstanceNormalization) - var meanVariance = GlobalAvgVariancePool2D(X); - - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - - var O = NewTensorForFusedActivation(X.dataType, X.shape, fusedActivation); - var fn = BestKernel(ComputeKernelLibrary.NormalizationTail(X.shape, O.shape)); - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensor("W", meanVariance.shape, Pin(meanVariance).buffer); - - - fn.SetTensorDecl("S", S.shape, Pin(S).offset); - fn.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(S).buffer, Pin(B).buffer); - fn.SetTensorBuffer("WBK", Pin(S).buffer); - fn.shader.SetFloat("_Epsilon", epsilon); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - internal static void ComputeReduceDispatchDim(TensorShape X, TensorShape O, int axis, out int flatHeight, out int reducedDim, out int flatWidth) - { - int[] OshapeLayoutSpecific = O.ToArray(); - - reducedDim = X[axis]; - - if(ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW) - { - OshapeLayoutSpecific[TensorShape.DataBatch + 1] = O[TensorShape.C]; - for(int i = TensorShape.DataBatch + 1; i < TensorShape.C; i++) - OshapeLayoutSpecific[i + 1] = O[i]; - - if(axis == TensorShape.C) - axis = TensorShape.DataBatch + 1; - else if (axis > TensorShape.DataBatch) - axis += 1; - } - - flatHeight = 1; - flatWidth = 1; - for (int i = 0; i < 8; i++) - { - if (i < axis) - flatHeight *= OshapeLayoutSpecific[i]; - if (i > axis) - flatWidth *= OshapeLayoutSpecific[i]; - } - } - - internal static int[] s_PartialReduceSumDimensions = new int[3]; - - Tensor ReducePartialHelper(Layer.Type kernelName, Tensor X, int axis) - { - var Oshape = X.shape; - Oshape[axis] = ComputeHelper.IDivC(ComputeHelper.IDivC(X.shape[axis], 64), 4); - - ComputeReduceDispatchDim(X.shape, Oshape, axis, out int flatHeight, out int reducedDim, out int flatWidth); - - s_PartialReduceSumDimensions[0] = flatHeight; - s_PartialReduceSumDimensions[1] = flatWidth; - s_PartialReduceSumDimensions[2] = reducedDim; - - var unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - var unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - var Otemp = NewTempTensor(X.dataType, Oshape); - var fn = BestKernel(ComputeKernelLibrary.PartialReduce(kernelName, flatHeight, reducedDim, flatWidth)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", Otemp.shape, Pin(Otemp, uploadCache: false).buffer); - fn.shader.SetInt("_UnrolledH", unrolledH); - fn.shader.SetInt("_UnrolledW", unrolledW); - fn.shader.SetInt("_ReducedDim", Oshape[axis]); - fn.shader.SetInts("_Pool", s_PartialReduceSumDimensions); - - fn.Dispatch(); - return Otemp; - } - - internal static int[] s_GlobalReduceSumDimensions = new int[3]; - - protected virtual Tensor ReduceHelper(Layer.Type kernelName, Tensor X, int axis, AllocScope outputScope) - { - axis = X.shape.Axis(axis); - int baseReducedDim = X.shape[axis]; - var Oshape = X.shape.Reduce(axis); - - while(X.shape[axis] > 64*4) - { - var lastLength = X.length; - X = ReducePartialHelper(kernelName, X, axis); - Assert.IsTrue(X.length < lastLength); - } - - ComputeReduceDispatchDim(X.shape, Oshape, axis, out int flatHeight, out int reducedDim, out int flatWidth); - - s_GlobalReduceSumDimensions[0] = flatHeight; - s_GlobalReduceSumDimensions[1] = flatWidth; - s_GlobalReduceSumDimensions[2] = baseReducedDim; - - - var unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - var unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - var O = NewTensor(X.dataType, Oshape, outputScope); - var fn = BestKernel(ComputeKernelLibrary.GlobalReduce(kernelName, flatHeight, reducedDim, flatWidth)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.shader.SetInt("_UnrolledH", unrolledH); - fn.shader.SetInt("_UnrolledW", unrolledW); - fn.shader.SetInt("_ReducedDim", reducedDim); - fn.shader.SetInts("_Pool", s_GlobalReduceSumDimensions); - - fn.Dispatch(); - return O; - } - - - // slow path for ArgMax/Min for now - private Tensor ReduceSlow(string kernelName, Tensor X, int axis) - { - axis = X.shape.Axis(axis); - - //TODO optimize when reducing not on channel. - bool needTranpose = axis != TensorShape.C; - FillReducePermute(axis); - - if (needTranpose) - X = TransposeHelper(X, s_ReducePermute, AllocScope.InternalToLayer); - - var oShape = X.shape.Reduce(TensorShape.C); - Assert.AreEqual(oShape.channels, 1); - - Tensor O; - if (needTranpose) - O = NewTempTensor(X.dataType, oShape); - else - O = NewOutputTensor(X.dataType, oShape); - - var fn = new ComputeKernel(new ComputeFunc(ComputeShaderContext.Optimized, kernelName, GetModelExecutionsReporter()), - (oShape.width, oShape.height, 1)); - - if (printKernels) - D.Log(fn.func.kernelName); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.Dispatch(); - - if (needTranpose) - { - X.Dispose(); - O = TransposeHelper(O, s_ReducePermute, AllocScope.LayerOutput); - } - - return O; - } - - /// - public override Tensor ArgMax(Tensor X, int axis) - { - return ReduceSlow("ArgMax", X, axis); - } - - /// - public override Tensor ArgMin(Tensor X, int axis) - { - return ReduceSlow("ArgMin", X, axis); - } - - /// - public override Tensor ReduceMin(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceMin, X, axis, AllocScope.LayerOutput); - } - - /// - public override Tensor ReduceMax(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceMax, X, axis, AllocScope.LayerOutput); - } - - /// - public override Tensor ReduceSum(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceSum, X, axis, AllocScope.LayerOutput); - } - - /// - public override Tensor ReduceMean(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceMean, X, axis, AllocScope.LayerOutput); - } - - /// - public override Tensor ReduceProd(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceProd, X, axis, AllocScope.LayerOutput); - } - - private Tensor ExpBiasReducePartialHelper(Tensor X, Tensor B, int axis, bool isFirstDispatch) - { - var Oshape = X.shape; - Oshape[axis] = ComputeHelper.IDivC(ComputeHelper.IDivC(X.shape[axis], 64), 4); - - ComputeReduceDispatchDim(X.shape, Oshape, axis, out int flatHeight, out int reducedDim, out int flatWidth); - - s_PartialReduceSumDimensions[0] = flatHeight; - s_PartialReduceSumDimensions[1] = flatWidth; - s_PartialReduceSumDimensions[2] = reducedDim; - - var unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - var unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - var Otemp = NewTempTensor(X.dataType, Oshape); - var fn = BestKernel(ComputeKernelLibrary.PartialExpBiasReduce(flatHeight, reducedDim, flatWidth)); - - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("B", B.shape, Pin(B).buffer); - fn.SetTensor("O", Otemp.shape, Pin(Otemp, uploadCache: false).buffer); - fn.shader.SetInt("_UnrolledH", unrolledH); - fn.shader.SetInt("_UnrolledW", unrolledW); - fn.shader.SetInt("_ReducedDim", Oshape[axis]); - fn.shader.SetInts("_Pool", s_PartialReduceSumDimensions); - fn.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - fn.Dispatch(); - return Otemp; - } - - private Tensor ExpBiasReduceHelper(Tensor X, Tensor B, int axis) - { - axis = X.shape.Axis(axis); - int baseReducedDim = X.shape[axis]; - var Oshape = X.shape.Reduce(axis); - - bool isFirstDispatch = true; - while(X.shape[axis] > 64*4) - { - var lastLength = X.length; - X = ExpBiasReducePartialHelper(X, B, axis, isFirstDispatch); - Assert.IsTrue(X.length < lastLength); - isFirstDispatch = false; - } - - ComputeReduceDispatchDim(X.shape, Oshape, axis, out int flatHeight, out int reducedDim, out int flatWidth); - - s_GlobalReduceSumDimensions[0] = flatHeight; - s_GlobalReduceSumDimensions[1] = flatWidth; - s_GlobalReduceSumDimensions[2] = baseReducedDim; - - var unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - var unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - var Otemp = NewTempTensor(X.dataType, Oshape); - var fn = BestKernel(ComputeKernelLibrary.GlobalExpBiasReduce(flatHeight, reducedDim, flatWidth)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("B", B.shape, Pin(B).buffer); - fn.SetTensor("O", Otemp.shape, Pin(Otemp, uploadCache: false).buffer); - fn.shader.SetInt("_UnrolledH", unrolledH); - fn.shader.SetInt("_UnrolledW", unrolledW); - fn.shader.SetInt("_ReducedDim", reducedDim); - fn.shader.SetInts("_Pool", s_GlobalReduceSumDimensions); - fn.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - fn.Dispatch(); - return Otemp; - } - - - /// - protected override Tensor Activation(string kernelName, Tensor X, float alpha = 0f, float beta = 0f) - { - if (!X.shape.Is4D()) - return base.Activation(kernelName, X, alpha, beta); - - var O = NewOutputTensor(X.dataType, X.shape); - var fn = BestKernel(ComputeKernelLibrary.Activation(X.shape, O.shape, kernelName)); - - if (printKernels) - D.Log(fn.func.kernelName); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetFloat("_Alpha", alpha); - fn.shader.SetFloat("_Beta", beta); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor PRelu(Tensor X, Tensor S) - { - if (!X.shape.Is4D() || !S.shape.Is4D()) - return base.PRelu(X, S); - - Assert.IsTrue((X.flatWidth == S.flatWidth) || (S.flatWidth == 1)); - - var O = NewOutputTensor(X.dataType, X.shape); - var fn = BestKernel(ComputeKernelLibrary.PRelu(X.shape, O.shape)); - - if (printKernels) - D.Log(fn.func.kernelName); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensor("W", S.shape, Pin(S).buffer); - - fn.Dispatch(); - return O; - } - - private Tensor DivExpSubHelper(Tensor X, Tensor B, Tensor S, AllocScope outputScope) - { - if(!X.shape.Is4D() || !B.shape.Is4D() || !S.shape.Is4D()) - return Div(new[] { Exp(Sub(new[] { X, B })), S }); - - Tensor O = NewTensorLike(new [] { X, B, S }, outputScope); - var fn = BestKernel(ComputeKernelLibrary.Broadcast(X.shape, O.shape, "BroadcastDivExpSub")); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensor("S", S.shape, Pin(S).buffer, Pin(S).offset); - fn.SetTensor("B", B.shape, Pin(B).buffer, Pin(B).offset); - - fn.shader.SetInts("_XStrides", GetInputTensorStridesOnDevice(X.shape, Pin(X).channelsOrder, s_XStrides)); - fn.shader.SetInts("_SStrides", GetInputTensorStridesOnDevice(S.shape, Pin(S).channelsOrder, s_SStrides)); - fn.shader.SetInts("_BStrides", GetInputTensorStridesOnDevice(B.shape, Pin(B).channelsOrder, s_BStrides)); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor Softmax(Tensor X, int axis) - { - axis = X.shape.Axis(axis); - - var XMax = ReduceHelper(Layer.Type.ReduceMax, X, axis, AllocScope.InternalToLayer); - var XExpSum = ExpBiasReduceHelper(X, XMax, axis); - - var O = DivExpSubHelper(X, XMax, XExpSum, AllocScope.LayerOutput); - XMax.Dispose(); - XExpSum.Dispose(); - return O; - } - - /// - public override Tensor LogSoftmax(Tensor X, int axis) - { - axis = X.shape.Axis(axis); - var XMax = ReduceHelper(Layer.Type.ReduceMax, X, axis, AllocScope.InternalToLayer); - var XExpSum = ExpBiasReduceHelper(X, XMax, axis); - - var O = LogSoftmaxEndHelper(X, XMax, XExpSum, AllocScope.LayerOutput); - XMax.Dispose(); - XExpSum.Dispose(); - return O; - } - - // @TODO: implement Dropout in terms of RandomUniform by preparing random values on CPU upfront and multiplying result on GPU later on - // public override Tensor Dropout(Tensor X, float alpha) - - /// - internal override Tensor TransposeToChannelFirstHelper(Tensor X) - { - var Otemp = NewTempTensor(X.dataType, X.shape); - var fn = BestKernel(ComputeKernelLibrary.TransposeToChannelFirst(X.shape, Otemp.shape)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", Otemp.shape, Pin(Otemp, uploadCache: false).buffer); - - fn.Dispatch(); - return Otemp; - } - - /// - public override Tensor Transpose(Tensor X) - { - Assert.IsTrue(X.dimensions <= 2); - - var O = NewOutputTensor(X.dataType, new TensorShape(X.flatWidth, X.flatHeight)); - var fn = BestKernel(ComputeKernelLibrary.Transpose2D(O.shape)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor Transpose(Tensor X, int[] permutations) - { - return TransposeHelper(X, permutations, AllocScope.LayerOutput); - } - - private Tensor TransposeHelper(Tensor X, int[] permutations, AllocScope outputScope) - { - if (!X.shape.Is4D() || permutations.Length != 4) - return Transpose8DHelper(X, permutations, outputScope); - - Assert.AreEqual(permutations.Length, 4); - - var O = NewTensor(X.dataType, X.shape.Permute(permutations), outputScope); - - var fn = BestKernel(ComputeKernelLibrary.Transpose(X.shape, O.shape)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.shader.SetInts("_Pool", permutations); - - fn.Dispatch(); - - return O; - } - - private Tensor Transpose8DHelper(Tensor X, int[] permutations, AllocScope outputScope) - { - permutations = TensorExtensions.Get8DPermutationsForNHWCPermutationsAndShape(X.shape, permutations); - - // See: Permute() in ONNXTensor.cs and https://stackoverflow.com/a/32034565 - var O = NewTensor(X.dataType, X.shape.Permute(permutations), outputScope); - - var OonDeviceShape = GetOnDeviceShape(O.shape); - var XonDeviceShape = GetOnDeviceShape(X.shape); - var onDevicePermutation = ConvertPermutationToDeviceLayout(permutations); - - // outTensor strides - var reversePermute = new int[permutations.Length]; - for (var i = 0; i < permutations.Length; ++i) - reversePermute[i] = Array.IndexOf(onDevicePermutation, i); - var tempOutStrides = new int[TensorShape.MaxRank+1]; - tempOutStrides[8] = 1; - for (int i = 7; i >= 0; --i) - tempOutStrides[i] = tempOutStrides[i+1] * OonDeviceShape[i]; - var outStride = new int[reversePermute.Length]; - for (var i = 0; i < reversePermute.Length; ++i) - outStride[i] = tempOutStrides[reversePermute[i] + 1]; - - var d0_3 = new[] {XonDeviceShape[0], XonDeviceShape[1],XonDeviceShape[2],XonDeviceShape[3]}; - var d4_7 = new[] {XonDeviceShape[4], XonDeviceShape[5],XonDeviceShape[6],XonDeviceShape[7]}; - var outStride0_3 = new[] {outStride[0],outStride[1],outStride[2],outStride[3]}; - var outStride4_7 = new[] {outStride[4],outStride[5],outStride[6],outStride[7]}; - - var fn = BestKernel(ComputeKernelLibrary.Transpose8D(X.shape, O.shape, ComputeInfo.channelsOrder)); - - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts("_Pad", d0_3); - fn.shader.SetInts("_Pool", d4_7); - fn.shader.SetInts("_Stride", outStride0_3); - fn.shader.SetInts("_ChannelWriteMask", outStride4_7); - - fn.Dispatch(); - - return O; - } - - /// - public override Tensor Concat(Tensor[] tensors, int axis) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || !TensorExtensions.Is8DAxisConvertibleTo4D(axis)) - return base.Concat(tensors, axis); - - var dataType = tensors.Length > 0 ? tensors[0].dataType : DataType.Float; - var O = NewOutputTensor(dataType, TensorExtensions.Concat(tensors, axis)); - - var offsets = s_ConcatOffsets; - Array.Clear(offsets, 0, offsets.Length); - axis = O.shape.Axis(axis); - var axisNHWC = TensorExtensions.Convert8DAxisTo4D(axis); - - foreach (var inputTensor in tensors) - { - // input can be constants, in that cases the internal layout does not match ComputeInfo.channelsOrder and will allways be NHWC - // => permute if there is a layout mismatch - var X = GetTensorInCurrentMemoryLayoutHelper(inputTensor); - - var fn = BestKernel(ComputeKernelLibrary.Copy(X.shape, O.shape)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts("_Pad", offsets); - - fn.Dispatch(); - - offsets[axisNHWC] += X.shape[axis]; - } - - return O; - } - - // Requires `output` to be allocated by the calling code to avoid unnecessary GC allocations - internal int[] GetInputTensorStridesOnDevice(TensorShape shape, ComputeInfo.ChannelsOrder channelOrder, int[] output) - { - Assert.IsNotNull(output); - Assert.AreEqual(4, output.Length); - - output[0] = (shape.batch == 1) ? 0 : shape.height * shape.width * shape.channels; - - if (channelOrder == ComputeInfo.ChannelsOrder.NHWC) - { - output[1] = (shape.height == 1) ? 0 : shape.width * shape.channels; - output[2] = (shape.width == 1) ? 0 : shape.channels; - output[3] = (shape.channels == 1) ? 0 : 1; - } - else - { - output[1] = (shape.height == 1) ? 0 : shape.width; - output[2] = (shape.width == 1) ? 0 : 1; - output[3] = (shape.channels == 1) ? 0 : shape.height * shape.width; - } - - return output; - } - - internal static int[] s_XStrides = new int[4]; - internal static int[] s_BStrides = new int[4]; - /// - protected override Tensor ElementwiseWithBroadcast(string kernelName, Tensor[] tensors) - { - Assert.IsTrue(tensors.Length > 0); - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors)) - return base.ElementwiseWithBroadcast(kernelName, tensors); - - var X = tensors[0]; - - Tensor outputTensor = NewOutputTensor(X.dataType, TensorExtensions.MaxShape(tensors)); - Tensor tempTensor = null; - if (tensors.Length > 2) - { - tempTensor = NewTempTensor(X.dataType, TensorExtensions.MaxShape(tensors)); - } - Tensor outputTensorOddIndex = (tensors.Length % 2 == 0) ? outputTensor : tempTensor; - Tensor outputTensorEvenIndex = (tensors.Length % 2 == 0) ? tempTensor : outputTensor; - - var fn = BestKernel(ComputeKernelLibrary.Broadcast(X.shape, outputTensor.shape, kernelName)); - - Tensor O = null; - bool isFirstDispatch = true; - for (int t = 1; t < tensors.Length; ++t) - { - var B = tensors[t]; - O = (t % 2 == 1) ? outputTensorOddIndex : outputTensorEvenIndex; - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensor("B", B.shape, Pin(B).buffer, Pin(B).offset); - fn.shader.SetFloat("_Alpha", 1.0f / (float)tensors.Length); - fn.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - fn.shader.SetInts("_XStrides", GetInputTensorStridesOnDevice(X.shape, Pin(X).channelsOrder, s_XStrides)); - fn.shader.SetInts("_BStrides", GetInputTensorStridesOnDevice(B.shape, Pin(B).channelsOrder, s_BStrides)); - - fn.Dispatch(); - - X = O; - isFirstDispatch = false; - } - - tempTensor?.Dispose(); - Assert.AreEqual(outputTensor, O); - return O; - } - - - internal static int[] s_ApplyPaddingCroppedSize = new int[3]; - /// - protected override Tensor ApplyPadding(Tensor X, int[] pad, string kernelName, float constant = 0.0f) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pad.Length, 6); - - var O = NewOutputTensor(X.dataType, X.shape.ApplyBorder(pad)); - var fn = BestKernel(ComputeKernelLibrary.Padding(X.shape, O.shape, kernelName)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts("_Pad", pad); - - if (kernelName == "Border2D") - { - // NOTE: negative "pad" variable will crop X tensor - int croppedWidth = X.width - Math.Max(0, -pad[3]); - int croppedHeight = X.height - Math.Max(0, -pad[4]); - int croppedChannels = X.channels - Math.Max(0, -pad[5]); - - s_ApplyPaddingCroppedSize[0] = croppedWidth; - s_ApplyPaddingCroppedSize[1] = croppedHeight; - s_ApplyPaddingCroppedSize[2] = croppedChannels; - - fn.shader.SetInts("_Pool", s_ApplyPaddingCroppedSize); - fn.shader.SetFloat("_Beta", constant); - } - - fn.Dispatch(); - return O; - } - - /// - public override Tensor LogicalNot(Tensor X) - { - var O = NewOutputTensor(X.dataType, X.shape); - var fn = BestKernel(ComputeKernelLibrary.Activation(X.shape, O.shape, "LogicalNot")); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor Sign(Tensor X) - { - var O = NewOutputTensor(X.dataType, X.shape); - var fn = BestKernel(ComputeKernelLibrary.Activation(X.shape, O.shape, "Sign")); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.Dispatch(); - return O; - } - - internal static int[] s_SStrides = new int[4]; - /// - public override Tensor Where(Tensor C, Tensor A, Tensor B) - { - if (!C.shape.Is4D() || !A.shape.Is4D() || !B.shape.Is4D()) - return base.Where(C, A, B); - - Tensor O = NewTensorLike(new [] { C, A, B }, AllocScope.LayerOutput); - var fn = BestKernel(ComputeKernelLibrary.Broadcast(C.shape, O.shape, "BroadcastWhere")); - - fn.SetTensor("X", C.shape, Pin(C).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensor("S", A.shape, Pin(A).buffer, Pin(A).offset); - fn.SetTensor("B", B.shape, Pin(B).buffer, Pin(B).offset); - - fn.shader.SetInts("_XStrides", GetInputTensorStridesOnDevice(C.shape, Pin(C).channelsOrder, s_XStrides)); - fn.shader.SetInts("_SStrides", GetInputTensorStridesOnDevice(A.shape, Pin(A).channelsOrder, s_SStrides)); - fn.shader.SetInts("_BStrides", GetInputTensorStridesOnDevice(B.shape, Pin(B).channelsOrder, s_BStrides)); - - fn.Dispatch(); - return O; - } - - private Tensor LogSoftmaxEndHelper(Tensor X, Tensor B, Tensor S, AllocScope outputScope) - { - if(!X.shape.Is4D() || !B.shape.Is4D() || !S.shape.Is4D()) - return Sub(new[] { Sub(new[] { X, B }), Log(S) }); - - Tensor O = NewTensorLike(new [] { X, B, S }, outputScope); - var fn = BestKernel(ComputeKernelLibrary.Broadcast(X.shape, O.shape, "LogSoftmaxEnd")); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensor("S", S.shape, Pin(S).buffer, Pin(S).offset); - fn.SetTensor("B", B.shape, Pin(B).buffer, Pin(B).offset); - - fn.shader.SetInts("_XStrides", GetInputTensorStridesOnDevice(X.shape, Pin(X).channelsOrder, s_XStrides)); - fn.shader.SetInts("_SStrides", GetInputTensorStridesOnDevice(S.shape, Pin(S).channelsOrder, s_SStrides)); - fn.shader.SetInts("_BStrides", GetInputTensorStridesOnDevice(B.shape, Pin(B).channelsOrder, s_BStrides)); - - fn.Dispatch(); - return O; - } - - /// - protected override Tensor CopyAndReshape_NCHW(Tensor X, TensorShape newShape) - { - //8D reshape only supported on reference backend. No optimized 8D version as - //the goal is rather to have a `channelFirst` model were reshape is a noop. - if (!X.shape.Is4D() || !newShape.Is4D()) - return base.CopyAndReshape_NCHW(X, newShape); - - Assert.AreEqual(X.length, newShape.length); - Assert.AreEqual(ComputeInfo.ChannelsOrder.NCHW, ComputeInfo.channelsOrder); - - var O = NewOutputTensor(X.dataType, newShape, "O"); - var fn = BestKernel(ComputeKernelLibrary.ReshapeFromNHWCModel(O.shape)); - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.Dispatch(); - return O; - } - - /// - protected override Tensor CopyAndReshape(Tensor X, TensorShape newShape) - { - //8D reshape only supported on reference backend atm. - if (!X.shape.Is4D() || !newShape.Is4D()) - return base.CopyAndReshape(X, newShape); - - var copyShape = X.shape; - Assert.AreEqual(copyShape.length, newShape.length); - if (X.shape != newShape) - { - //In CHW mode one should call CopyAndReshape_NCHW if shape is modified - Assert.AreEqual(ComputeInfo.ChannelsOrder.NHWC, ComputeInfo.channelsOrder); - } - - // NOTE: "Copy" kernel copies tensor data while preserving the shape - // However here in CopyAndReshape we want to both copy and change the shape, - // To be able to piggyback "Copy" kernel we specify new shape when allocating destination tensor, - // but use shape identical to source when copying. - - var O = NewOutputTensor(X.dataType, newShape); - var fn = BestKernel(ComputeKernelLibrary.Copy(copyShape, copyShape)); - - fn.SetTensor("X", copyShape, Pin(X).buffer); - fn.SetTensor("O", copyShape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts("_Pad", new int[] { 0,0,0,0 }); - - fn.Dispatch(); - return O; - } -} - -internal class ComputeVarsWithSharedModel : DefaultVars -{ - private Dictionary m_ModelBuffers = new Dictionary(); - private Dictionary m_OffsetsIntoModelWeights = new Dictionary(); - - public override void Dispose() - { - base.Dispose(); - - foreach (var key in m_ModelBuffers.Keys) - m_ModelBuffers[key].Dispose(); - m_ModelBuffers.Clear(); - m_OffsetsIntoModelWeights.Clear(); - } - - protected override Tensor[] PrepareLayerInputTensors(Model model, Layer layer, IOps ops) - { - var tensorIndex = 0; - var tensors = new Tensor[layer.inputs.Length + layer.datasets.Length]; - - foreach (var name in layer.inputs) - { - var tensor = new Tensor(1, 1, 1, 1, m_StringCache.Lookup(layer.name, "_dummy_in", tensorIndex)); - tensors[tensorIndex++] = tensor; - } - - Int64 offsetIntoModelWeights = m_OffsetsIntoModelWeights.ContainsKey(layer.name) ? - m_OffsetsIntoModelWeights[layer.name]: 0; - ComputeBuffer buffer = m_ModelBuffers.ContainsKey(layer.name) ? m_ModelBuffers[layer.name] : null; - - if (buffer == null) - { - buffer = CreateComputeBufferForModelTensors(layer, out offsetIntoModelWeights); - if (buffer != null) - { - m_ModelBuffers[layer.name] = buffer; - m_OffsetsIntoModelWeights[layer.name] = offsetIntoModelWeights; - } - } - - foreach (var arg in layer.datasets) - { - Assert.IsNotNull(buffer); - var offset = (int) (arg.offset - offsetIntoModelWeights); - var tensor = new Tensor(arg.shape, - new SharedComputeTensorData(buffer, arg.shape, offset), - m_StringCache.Lookup(layer.name, "_arg", tensorIndex)); - tensors[tensorIndex++] = tensor; - m_ModelTensors.Add(tensor); - } - - Assert.AreEqual(tensorIndex, tensors.Length); - return tensors; - } - - protected ComputeBuffer CreateComputeBufferForModelTensors(Layer layer, out Int64 offsetIntoModelWeights) - { - Int64 minOffset = layer.weights.LongLength; - Int64 maxOffset = 0; - foreach (var t in layer.datasets) - { - minOffset = Math.Min(minOffset, t.offset); - maxOffset = Math.Max(maxOffset, t.offset + t.length); - } - var length = Convert.ToInt32(maxOffset - minOffset); - if (length <= 0) - { - offsetIntoModelWeights = 0; - return null; - } - - var buffer = new ComputeBuffer(length, sizeof(float)); - // @WARN: looks like Unity ComputeBuffer.SetData API take "computeBufferStartIndex" and "length" arguments in floats, instead of buffer element size aka stride - // as would be expected per API documentation - // @TODO: bugreport documentation discrepancy! - offsetIntoModelWeights = minOffset; - - if (layer.weights.Type == DataType.Float) - { - layer.weights.UploadToComputeBuffer(buffer, Convert.ToInt32(offsetIntoModelWeights), 0, length); - } - else - { - //No support for half on GPU for now. Expand to fp32 when uploading to GFX mem. - BarracudaArray floatArray = new BarracudaArray(length, DataType.Float); - BarracudaArray.Copy(layer.weights, Convert.ToInt32(offsetIntoModelWeights), floatArray, 0, length); - floatArray.UploadToComputeBuffer(buffer, 0, 0, length); - } - - return buffer; - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaCompute.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaCompute.cs.meta deleted file mode 100644 index 4dec977..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaCompute.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: badd0d6a0383049eab2cb58e1d0d6fa9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaComputeDebugUtils.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaComputeDebugUtils.cs deleted file mode 100644 index 6920eb2..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaComputeDebugUtils.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System.Diagnostics; -using UnityEngine; -using System.Runtime.InteropServices; - -namespace Unity.Barracuda { - -internal class ComputeDebugUtils -{ - /// - /// DEBUG ONLY: `debugKernels` allow to track out of bound read/write and assertion in kernels. - /// When set to true be sure to define KERNEL_ASSERTS or FORCE_DEBUG in the particular kernel(s) - /// you want to debug (see in DebugUtils.cginc). - /// Production code should not set this to 'true' as this will significantly degrade performances. - /// - public static bool debugKernels = false; - - /// - /// DEBUG ONLY: if ComputeDebugUtils.debugKernels is true and debugger is attached, debugger will break when a kernel assertion is catch. - /// - public static bool breakOnAssertion = false; - - //Keep in sync with DebugUtils.cginc KERNEL_ASSERT_CONTEXT defines - private enum KernelAssertContext - { - ReadOnlyTensor_Read = 0, - ReadWriteTensor_Read = 1, - ReadWriteTensor_Write = 2, - SharedTensor_Read = 3, - Assertion = 4, - AssertionWithValue = 5 - } - - static ComputeDebugUtils() - { - string[] args = System.Environment.GetCommandLineArgs (); - for (int i = 0; i < args.Length; i++) { - if (args [i] == "-barracuda-debug-gpu-kernels") - { - debugKernels = true; - } - } - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct KernelAssertInfo - { - public KernelAssertInfo(uint[] data) - { - UnityEngine.Debug.Assert(numUintInKernelAssertInfo == data.Length); - UnityEngine.Debug.Assert(numUintInKernelAssertInfo == 8, - "Please change KernelAssertInfo constructor if altering the struct."); - lockValue = data[0]; - lineNumber = data[1]; - context = data[2]; - index = data[3]; - bufferSize = data[4]; - debugValue = data[5]; - padding1 = data[6]; - padding2 = data[7]; - } - - public readonly uint lockValue; - public readonly uint lineNumber; - public readonly uint context; - public readonly uint index; - public readonly uint bufferSize; - public readonly uint debugValue; - public readonly uint padding1; - public readonly uint padding2; - } - private static readonly int numUintInKernelAssertInfo = Marshal.SizeOf(typeof(KernelAssertInfo))/sizeof(uint); - - private static ComputeBuffer kernelDebugInfo = null; - - private static void LogAssertion(KernelAssertInfo info, string kernelName) - { - if (info.lockValue != 0) - { - string source; - switch (info.context) - { - case (int) KernelAssertContext.ReadOnlyTensor_Read: - source = $"Out of bound while Reading a ReadonlyTensor of length {info.bufferSize} at index {info.index} (at Tensor.cginc line {info.lineNumber})"; - break; - case (int) KernelAssertContext.ReadWriteTensor_Read: - source = $"Out of bound while Reading a ReadWriteTensor of length {info.bufferSize} at index {info.index} (at Tensor.cginc line {info.lineNumber})"; - break; - case (int) KernelAssertContext.ReadWriteTensor_Write: - source = $"Out of bound while Writing to a ReadWriteTensor of length {info.bufferSize} at index {info.index} (at Tensor.cginc line {info.lineNumber})"; - break; - case (int) KernelAssertContext.SharedTensor_Read: - source = $"Out of bound while Reading a SharedTensor of length {info.bufferSize} at index {info.index} (at Tensor.cginc line {info.lineNumber})"; - break; - case (int) KernelAssertContext.Assertion: - source = $"Assertion at line {info.lineNumber}"; - break; - case (int) KernelAssertContext.AssertionWithValue: - source = $"Assertion at line {info.lineNumber}, debug value is {info.debugValue}"; - break; - default: - source = "Unknown error"; - break; - } - - string message = $"{source} in kernel {kernelName}."; - D.LogError(message); - - if (breakOnAssertion) - { - Debugger.Break(); - } - } - } - - - public static void PrepareDispatch() - { - //Lazy alloc, will be released by GC. - if (debugKernels && kernelDebugInfo == null) - { - kernelDebugInfo = new ComputeBuffer(1, numUintInKernelAssertInfo*sizeof(uint)); - } - - if (debugKernels) - { - Shader.SetGlobalBuffer("KernelAssertInfoBuffer", kernelDebugInfo); - kernelDebugInfo.SetData(new uint[numUintInKernelAssertInfo]); //TODO use a kernel to zero out the buffer to avoid a extra sync. - } - } - - public static void VerifyDispatch(string kernelName) - { - if (debugKernels) - { - UnityEngine.Debug.Assert(kernelDebugInfo != null); - var data = new uint[numUintInKernelAssertInfo]; - kernelDebugInfo.GetData(data, 0, 0, numUintInKernelAssertInfo); - LogAssertion(new KernelAssertInfo(data), kernelName); - } - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaComputeDebugUtils.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaComputeDebugUtils.cs.meta deleted file mode 100644 index b2757bb..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaComputeDebugUtils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 72797c6856a1f9642a53f0b22d65e5dc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPixelShader.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPixelShader.cs deleted file mode 100644 index 9664d63..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPixelShader.cs +++ /dev/null @@ -1,1724 +0,0 @@ -//#define DEBUG_TRACK_ALLOCATIONS - -using UnityEngine; -using UnityEngine.Rendering; -using UnityEngine.Experimental.Rendering; // AsyncGPUReadback -using UnityEngine.Assertions; -using UnityEngine.Profiling; -using System; -using System.Linq; -using System.Runtime.CompilerServices; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Collections; -using Object = UnityEngine.Object; - -[assembly: InternalsVisibleTo("Barracuda.EditorTests")] - -namespace Unity.Barracuda { -public class TextureTensorData : UniqueResourceId, ITensorData -{ - private bool m_DisposeBufferAfterUse; - private TensorShape m_Shape; - private RenderTexture m_BufferAsTexture; - private bool m_tensorBatchTilled = false; - private bool m_tensorChannelTilled = false; - - public RenderTexture bufferAsTexture { get { return m_BufferAsTexture; } } - public bool tensorBatchTilled { get { return m_tensorBatchTilled; } } - public bool tensorChannelTilled { get { return m_tensorChannelTilled; } } - - public string name; - - /// - public virtual DataType dataType { get - { - return DataType.Float;//todo fp16 - } } - - public static int MaxTextureSize = 16384; - - public TextureTensorData(TensorShape shape, string buffername, bool clearOnInit = true) - { - name = buffername; - - int c4 = ComputeHelper.IDivC(shape.channels, 4); - int c4w = c4; - int c4h = 1; - - if (c4w * shape.width > MaxTextureSize) - { - c4w = Mathf.FloorToInt(MaxTextureSize / ((float)shape.width)); - c4h = ComputeHelper.IDivC(c4, c4w); - m_tensorChannelTilled = true; - } - - int bh = shape.batch; - int bw = 1; - - if (bh * c4h * shape.height > MaxTextureSize) - { - bh = Mathf.FloorToInt(MaxTextureSize / ((float)(c4h * shape.height))); - bw = ComputeHelper.IDivC(shape.batch, bh); - m_tensorBatchTilled = true; - } - - int h = bh * c4h * shape.height; - int w = bw * c4w * shape.width; - - m_BufferAsTexture = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBFloat); - m_BufferAsTexture.Create(); - - if (clearOnInit) - { - var previousActiveRT = RenderTexture.active; - RenderTexture.active = m_BufferAsTexture; - GL.Clear(true, true, Color.clear); - RenderTexture.active = previousActiveRT; - } - - m_Shape = shape; - m_DisposeBufferAfterUse = true; - } - internal TextureTensorData(RenderTexture bufferAsTexture, TensorShape shape, string buffername) - { - name = buffername; - m_BufferAsTexture = bufferAsTexture; - m_Shape = shape; - - m_DisposeBufferAfterUse = false; - } - - ~TextureTensorData() - { - if (m_BufferAsTexture == null) - return; - if (!m_DisposeBufferAfterUse) - return; - - D.LogWarning($"Found unreferenced, but undisposed Tensor data which might lead to GPU resource leak: {ToString()}"); - - Dispose(); - } - - public virtual void Dispose() - { - if (m_DisposeBufferAfterUse) - { - // In emergency shutdown situations active RenderTexture might be the one we are trying to release - if (RenderTexture.active == m_BufferAsTexture) - RenderTexture.active = null; - - m_BufferAsTexture.Release(); - m_BufferAsTexture = null; - } - m_DisposeBufferAfterUse = false; - } - - public virtual void Reserve(int count) - { - if (count > maxCapacity) - throw new ArgumentException("TextureTensorData buffer is too small to reserve " + count + " elements."); - } - - public virtual void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0) - { - var numItemToCopy = shape.length; - var numItemAvailableInData = data.Length - managedBufferStartIndex; - - Assert.IsTrue(managedBufferStartIndex >= 0); - Assert.IsTrue(numItemToCopy <= numItemAvailableInData); - - int w = Mathf.Min(shape.length, MaxTextureSize); - int h = Mathf.Max(1, ComputeHelper.IDivC(shape.length, w)); - - Texture2D texture = new Texture2D(w, h, TextureFormat.RFloat, false); - var textureData = texture.GetRawTextureData(); - unsafe - { - UnsafeUtility.MemSet(textureData.GetUnsafePtr(), 0, sizeof(float) * (textureData.Length)); - } - NativeArray.Copy(data, managedBufferStartIndex, textureData, 0, shape.length); - - texture.Apply(); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/BufferToTensor")); - - material.SetTexture("Xtex2D", texture); - - material.SetInt("_InputWidth", w); - material.SetInt("_InputHeight", h); - - material.SetVector("OdeclShape", new Vector4(shape.batch, shape.height, shape.width, shape.channels)); - - Graphics.Blit(null, m_BufferAsTexture, material); - - Object.DestroyImmediate(texture); - - m_AsyncDownloadSchedulingFrame = -1; - } - - public virtual bool ScheduleAsyncDownload(int count) - { - return WaitFor3Frames(); - } - - private int m_AsyncDownloadSchedulingFrame = -1; - private bool WaitFor3Frames() - { - if (m_AsyncDownloadSchedulingFrame < 0) - m_AsyncDownloadSchedulingFrame = Time.frameCount; - var framesPassed = Time.frameCount - m_AsyncDownloadSchedulingFrame; - return framesPassed > 3; - } - - public virtual float[] Download(TensorShape shape) - { - Assert.IsTrue(shape.Is4D()); - - var count = shape.length; - - Profiler.BeginSample("Barracuda.DownloadDataFromGPU"); - Assert.IsTrue(maxCapacity >= count); - count = Math.Min(maxCapacity, count); - - m_AsyncDownloadSchedulingFrame = -1; - - int w = Mathf.Min(shape.length, MaxTextureSize); - int h = Mathf.Max(1, ComputeHelper.IDivC(shape.length, w)); - - Texture2D texture = new Texture2D(w, h, TextureFormat.RFloat, false); - RenderTexture rttexture = new RenderTexture(w, h, 0, RenderTextureFormat.RFloat); - - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/TensorToBuffer")); - - - material.SetVector("XdeclShape", new Vector4(shape.batch, shape.height, shape.width, shape.channels)); - material.SetTexture("Xdata", bufferAsTexture); - material.SetInt("_OutputWidth", w); - material.SetInt("_OutputHeight", h); - - Graphics.Blit(null, rttexture, material); - - - var previousActiveRT = RenderTexture.active; - RenderTexture.active = rttexture; - Rect rectReadPicture = new Rect(0, 0, w, h); - texture.ReadPixels(rectReadPicture, 0, 0); - texture.Apply(); - - var data = new float[count]; - Buffer.BlockCopy(texture.GetRawTextureData(), 0, data, 0, count * sizeof(float)); - - RenderTexture.active = previousActiveRT; - - return data; - } - - public virtual BarracudaArray SharedAccess(out int offset) - { - offset = 0; - return new BarracudaArrayFromManagedArray(Download(new TensorShape(0, 0, 0, maxCapacity)));//TODO fp16 - } - - public virtual int maxCapacity { get - { - return m_Shape.length; - } } - - public virtual bool inUse { get - { - return true; - } } - - public virtual bool isGPUMem { get - { - return true; - } } - - public override string ToString() - { - try - { - // m_BufferAsTexture.ToString() might throw exception if called from non-main thread - return $"(GPU:{name}#{GetHashCode()} {m_Shape}) bufferAsTexture: {m_BufferAsTexture}"; - } - catch (Exception) - { - return $"(GPU:{name}#{GetHashCode()} {m_Shape})"; - } - - } -} - -public class PixelShaderOps : ReferenceCPUOps -{ - public PixelShaderOps(ITensorAllocator allocator = null) - : base(allocator) - { - } - - static private StringCache m_StringCache = new StringCache(); - - public TextureTensorData Pin(Tensor X, bool uploadCache = true) - { - X.FlushCache(uploadCache); - - var onDevice = X.tensorOnDevice as TextureTensorData; - if (onDevice == null) - { - var asTexture = X.tensorOnDevice as TextureAsTensorData; - if (asTexture != null) - X.AttachToDevice(TextureToTensorData(asTexture, X.name)); - else - { - if (uploadCache) - X.UploadToDevice(new TextureTensorData(X.shape, X.name)); // device is not compatible, create new array and upload - else - X.AllocateOnDevice(new TextureTensorData(X.shape, X.name)); // device is not compatible, create new array but do not upload nor 0-fill - } - } - - Assert.IsNotNull(X.tensorOnDevice as TextureTensorData); - Assert.IsNotNull((X.tensorOnDevice as TextureTensorData).bufferAsTexture); - - return X.tensorOnDevice as TextureTensorData; - } - - internal void SetTensor(Material material, string name, Tensor X) - { - var XonDevice = Pin(X); - // need to hide batch tilling due to perf regression on mobile - if (XonDevice.tensorBatchTilled) - material.EnableKeyword("BATCHTILLING_ON"); - - material.SetVector(m_StringCache.Lookup(name, "declShape"), new Vector4(X.batch, X.height, X.width, X.channels)); - material.SetTexture(m_StringCache.Lookup(name, "data"), XonDevice.bufferAsTexture); - } - - internal Tensor Dispatch(Material material, DataType dataType, TensorShape Oshape) - { - var O = NewTensor(dataType, Oshape, AllocScope.LayerOutput, "O"); - - var pinO = Pin(O); - material.SetVector("OdeclShape", new Vector4(Oshape.batch, O.height, O.width, O.channels)); - material.SetTexture("Odata", pinO.bufferAsTexture); - // need to hide batch tilling due to perf regression on mobile - if (pinO.tensorBatchTilled) - material.EnableKeyword("BATCHTILLING_ON"); - - Graphics.Blit(null, pinO.bufferAsTexture, material); - - return O; - } - - - // --------------------------------------------------------------------------------- - - internal ITensorData TextureToTensorData(TextureAsTensorData texData, string name) - { - var tensorData = new TextureTensorData(texData.shape, name, false); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/TextureToTensor")); - - material.SetVector("OdeclShape", new Vector4(texData.shape.batch, texData.shape.height, texData.shape.width, texData.shape.channels)); - - material.SetInt("_FlipY", texData.flip == TextureAsTensorData.Flip.Y ? 1 : 0); - material.SetVector("_Scale", texData.scale); - material.SetVector("_Bias", texData.bias); - - Vector4 offsets = Vector4.zero; - foreach (var tex in texData.textures) - { - var texArr = tex as Texture2DArray; - var rt = tex as RenderTexture; - - var texDepth = 1; - if (texArr) - texDepth = texArr.depth; - else if (rt) - texDepth = rt.volumeDepth; - - material.SetTexture("Xtex2D", tex); - material.SetVector("_Pool", new Vector2(tex.width, tex.height)); - material.SetVector("_Pad", offsets); - - var channelWriteMask = TextureFormatUtils.FormatToChannelMask(tex, texData.interpretPixelAsChannels); - var channelReadMap = TextureFormatUtils.FormatToChannelReadMap(tex, texData.interpretPixelAsChannels); - var channelWriteMap = Vector4.zero; - int c = 0; - for(int i = 0; i < 4; i++) - { - channelWriteMap[i] = c; - if (channelWriteMask[i] == 1) - c++; - } - material.SetVector("_ChannelWriteMask", new Vector4(channelWriteMask[0], channelWriteMask[1], channelWriteMask[2], channelWriteMask[3])); - material.SetVector("_ChannelWriteMap", new Vector4(channelWriteMap[0], channelWriteMap[1], channelWriteMap[2], channelWriteMap[3])); - material.SetVector("_ChannelReadMap", new Vector4(channelReadMap[0], channelReadMap[1], channelReadMap[2], channelReadMap[3])); - - Graphics.Blit(null, tensorData.bufferAsTexture, material); - - if (texData.interpretDepthAs == TextureAsTensorData.InterpretDepthAs.Batch) - offsets[0] += texDepth; - else if (texData.interpretDepthAs == TextureAsTensorData.InterpretDepthAs.Channels) - offsets[3] += texDepth * texData.interpretPixelAsChannels; - } - - return tensorData; - } - - /// - /// Check if `fusedActivation` is supported in-place - /// - /// fused activation type - /// `true` if supported in-place - protected override bool IsFusedActivationSupported(Layer.FusedActivation fusedActivation) - { - switch (fusedActivation) - { - case Layer.FusedActivation.Relu: - return true; - case Layer.FusedActivation.None: - return true; - default: - return false; - } - } - - /// - /// Copy `Tensor` data to `RenderTexture` - /// - /// source `Tensor` - /// target `RenderTexture` - /// batch - /// from channel - /// scale - /// bias - /// LUT table - /// flips the texture along the Y dimension (optional, default: true) - public void TensorToRenderTexture(Tensor X, RenderTexture target, int batch, int fromChannel, Vector4 scale, Vector4 bias, Texture3D lut, bool flipY = true) - { - if (!target.IsCreated()) - { - target.Release(); - target.Create(); - } - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/TensorToTexture")); - - SetTensor(material, "X", X); - material.SetVector("_Scale", scale); - material.SetVector("_Bias", bias); - material.SetVector("_Pad", new Vector4(batch, 0, 0, fromChannel)); - material.SetInt("_FlipY", flipY ? 1 : 0); - material.SetInt("_OutputHeight", target.height); - material.SetInt("_OutputWidth", target.width); - - Graphics.Blit(null, target, material); - } - - /// - public override Tensor Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2);//WH - Assert.AreEqual(pad.Length, 4); - - var Oshape = X.shape.ApplyKernel(K.shape, stride, pad); - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Conv2D")); - - SetTensor(material, "X", X); - SetTensor(material, "K", K); - SetTensor(material, "B", B); - - material.SetVector("_Stride", new Vector4(stride[0], stride[1], 0, 0)); - material.SetVector("_Pad", new Vector4(pad[0], pad[1], pad[2], pad[3])); - material.SetInt("_ActivationMode", (int)(fusedActivation)); - - var O = Dispatch(material, X.dataType, Oshape); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var Oshape = X.shape.ApplyKernelInverse(K.shape, stride, pad, outputAdjustment); - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Conv2DTrans")); - - // one pass version - pad = new int[] - { - K.kernelWidth - pad[0] - 1, K.kernelHeight - pad[1] - 1, - K.kernelWidth - pad[2] - 1, K.kernelHeight - pad[3] - 1 - }; - - SetTensor(material, "X", X); - SetTensor(material, "K", K); - SetTensor(material, "B", B); - - material.SetVector("_Stride", new Vector4(stride[0], stride[1], 0, 0)); - material.SetVector("_Pad", new Vector4(pad[0], pad[1], 0, 0)); - material.SetInt("_ActivationMode", (int)(fusedActivation)); - - var O = Dispatch(material, X.dataType, Oshape); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - if (K.kernelDepth != 1) - return base.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(K.kernelDepth, 1); - Assert.AreEqual(K.kernelCount, X.channels); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var Oshape = X.shape.ApplyKernel(K.shape, stride, pad); - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/DepthwiseConv2D")); - - SetTensor(material, "X", X); - SetTensor(material, "K", K); - SetTensor(material, "B", B); - - material.SetVector("_Stride", new Vector4(stride[0], stride[1], 0, 0)); - material.SetVector("_Pad", new Vector4(pad[0], pad[1], pad[2], pad[3])); - material.SetInt("_ActivationMode", (int)(fusedActivation)); - - var O = Dispatch(material, X.dataType, Oshape); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - var O = new TensorShape(X.flatHeight, Y.flatWidth); - if (xTranspose) - O = new TensorShape(X.flatWidth, O.flatWidth); - if (yTranspose) - O = new TensorShape(O.flatHeight, Y.flatHeight); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/MatMul")); - if (xTranspose) - material.EnableKeyword("xTranspose_ON"); - if (yTranspose) - material.EnableKeyword("yTranspose_ON"); - - SetTensor(material, "X", X); - SetTensor(material, "Y", Y); - - return Dispatch(material, X.dataType, O); - } - - /// - /// Check if `Flatten` is needed for `Dense` layer input - /// - /// input shape - /// `true` if `Flatten` is needed - protected bool ShouldFlattenInputForDenseLayer(TensorShape X) - { - //In CHW flatten is return a tensor with items linearized in memory in regards to HWC layout. - int flattenDimensions = (X.height > 1 ? 1 : 0) + - (X.width > 1 ? 1 : 0) + - (X.channels > 1 ? 1 : 0); - return flattenDimensions > 1; - } - - /// - public override Tensor Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(W.dimensions <= 2); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(X.flatWidth, W.flatHeight); - - if (ShouldFlattenInputForDenseLayer(X.shape)) - X = Flatten(X); - - var Oshape = new TensorShape(X.flatHeight, W.flatWidth); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Dense")); - - SetTensor(material, "X", X); - SetTensor(material, "W", W); - SetTensor(material, "B", B); - material.SetInt("_ActivationMode", (int)fusedActivation); - - var O = Dispatch(material, X.dataType, Oshape); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Dense3(Tensor X, Tensor W, Tensor B) - { - var Oshape = new TensorShape(X.batch, 1, W.channels, X.channels); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Dense3")); - - SetTensor(material, "X", X); - SetTensor(material, "W", W); - SetTensor(material, "B", B); - - return Dispatch(material, X.dataType, Oshape); - } - - private Tensor ReduceHelper(string kernelName, Tensor X, int axis) - { - axis = X.shape.Axis(axis); - - var O = X.shape.Reduce(axis); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Reduce")); - material.EnableKeyword(kernelName); - - if(axis == TensorShape.DataBatch) - material.EnableKeyword("ReduceN"); - if (axis == TensorShape.H) - material.EnableKeyword("ReduceH"); - if (axis == TensorShape.W) - material.EnableKeyword("ReduceW"); - if (axis == TensorShape.C) - material.EnableKeyword("ReduceC"); - - SetTensor(material, "X", X); - - return Dispatch(material, X.dataType, O); - } - - /// - public override Tensor ArgMax(Tensor X, int axis) - { - return ReduceHelper("ArgMax", X, axis); - } - - /// - public override Tensor ArgMin(Tensor X, int axis) - { - return ReduceHelper("ArgMin", X, axis); - } - - /// - public override Tensor ReduceMin(Tensor X, int axis) - { - return ReduceHelper("ReduceMin", X, axis); - } - - /// - public override Tensor ReduceMax(Tensor X, int axis) - { - return ReduceHelper("ReduceMax", X, axis); - } - - /// - public override Tensor ReduceSum(Tensor X, int axis) - { - return ReduceHelper("ReduceSum", X, axis); - } - - /// - public override Tensor ReduceMean(Tensor X, int axis) - { - return ReduceHelper("ReduceMean", X, axis); - } - - /// - public override Tensor ReduceProd(Tensor X, int axis) - { - return ReduceHelper("ReduceProd", X, axis); - } - - /// - /// Elementwise broadcast for specified kernel - /// - /// kernel name - /// input tensors - /// output `Tensor` - /// thrown if input `Tensor` is not compatible with 4D shape - protected virtual Tensor ElementwiseWithBroadcast(string kernelName, Tensor[] tensors) - { - var O = TensorExtensions.MaxShape(tensors); - - Assert.IsTrue(tensors.Length > 0); - var X = tensors[0]; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Broadcast")); - material.EnableKeyword(kernelName); - - bool isFirstDispatch = true; - for (int t = 1; t < tensors.Length; ++t) - { - var B = tensors[t]; - Assert.IsTrue(B.shape.Is4D()); - - SetTensor(material, "X", X); - SetTensor(material, "B", B); - - material.SetFloat("_Alpha", 1.0f/(float)tensors.Length); - material.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - X = Dispatch(material, X.dataType, O); - isFirstDispatch = false; - } - - return X; - } - - /// - public override Tensor Add(Tensor[] tensors) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Add(tensors); - - return ElementwiseWithBroadcast("Add", tensors); - } - - /// - - public override Tensor Sub(Tensor[] tensors) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Add(tensors); - - return ElementwiseWithBroadcast("Sub", tensors); - } - - /// - public override Tensor Mul(Tensor[] tensors) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Add(tensors); - - return ElementwiseWithBroadcast("Mul", tensors); - } - - /// - public override Tensor Div(Tensor[] tensors) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Div(tensors); - - return ElementwiseWithBroadcast("Div", tensors); - } - - /// - public override Tensor Pow(Tensor[] tensors) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Pow(tensors); - - return ElementwiseWithBroadcast("Pow", tensors); - } - - /// - public override Tensor Min(Tensor[] tensors) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Add(tensors); - - return ElementwiseWithBroadcast("Min", tensors); - } - - /// - public override Tensor Max(Tensor[] tensors) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Max(tensors); - - return ElementwiseWithBroadcast("Max", tensors); - } - - /// - public override Tensor Mean(Tensor[] tensors) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Mean(tensors); - - return ElementwiseWithBroadcast("Mean", tensors); - } - - internal static Tensor[] s_ElementwiseBroadcastTensors = new Tensor[2]; - - /// - public override Tensor Greater(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("Greater", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor GreaterEqual(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("GreaterEqual", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor Less(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("Less", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LessEqual(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("LessEqual", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor Equal(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("Equal", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LogicalOr(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("LogicalOr", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LogicalAnd(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("LogicalAnd", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LogicalXor(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("LogicalXor", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LogicalNot(Tensor X) - { - return Activation("LogicalNot", X); - } - - /// - public override Tensor Sign(Tensor X) - { - return Activation("Sign", X); - } - - /// - public override Tensor Where(Tensor C, Tensor A, Tensor B) - { - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/BroadcastWhere")); - - var O = TensorExtensions.MaxShape(new[] { C, A, B }); - - SetTensor(material, "X", C); - SetTensor(material, "W", A); - SetTensor(material, "K", B); - - return Dispatch(material, C.dataType, O); - } - - - /// - /// Generic pooling 2D - /// - /// kernel name - /// input - /// output `Tensor` - protected virtual Tensor GlobalPool2D(string kernelName, Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - var Oshape = new TensorShape(X.batch, 1, 1, X.channels); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader(kernelName)); - - SetTensor(material, "X", X); - - return Dispatch(material, X.dataType, Oshape); - } - - /// - public override Tensor GlobalMaxPool2D(Tensor X) - { - return GlobalPool2D("Barracuda/GlobalMaxPool2D", X); - } - - /// - public override Tensor GlobalAvgPool2D(Tensor X) - { - return GlobalPool2D("Barracuda/GlobalAvgPool2D", X); - } - - /// - public override Tensor GlobalAvgVariancePool2D(Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - var O = new TensorShape(X.batch, 2, 1, X.channels); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("GlobalAvgVariancePool2D")); - - SetTensor(material, "X", X); - - return Dispatch(material, X.dataType, O); - } - - /// - protected virtual Tensor Pool2D(string kernelName, Tensor X, int[] pool, int[] stride, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - - var Oshape = X.shape.ApplyPool(pool, stride, pad); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader(kernelName)); - - SetTensor(material, "X", X); - - material.SetVector("_Pool", new Vector4(pool[0], pool[1], 0, 0)); - material.SetVector("_Stride", new Vector4(stride[0], stride[1], 0, 0)); - material.SetVector("_Pad", new Vector4(pad[0], pad[1], pad[2], pad[3])); - - return Dispatch(material, X.dataType, Oshape); - } - - /// - public override Tensor MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - return Pool2D("Barracuda/MaxPool2D", X, pool, stride, pad); - } - - /// - public override Tensor AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - return Pool2D("Barracuda/AvgPool2D", X, pool, stride, pad); - } - - /// - public override Tensor Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) - { - if (!X.shape.Is4D()) - throw new NotImplementedException(); - - if (axis != TensorShape.C && axis != -1) - return base.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); - - if (pool == 1 && X.batch != 1) - return base.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); // @TODO: Instance Normalization with batch > 1 - - if (pool <= 0) - pool = X.batch; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/InstanceNorm")); - - material.SetFloat("_Epsilon", epsilon); - material.SetInt("_ActivationMode", (int)fusedActivation); - - SetTensor(material, "X", X); - SetTensor(material, "W", S); - SetTensor(material, "B", B); - - var O = Dispatch(material, X.dataType, X.shape); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor OneHot(Tensor X, int depth, float onValue, float offValue, int inputRank=-1) - { - if (inputRank == -1) - inputRank = X.dimensions; - - if (inputRank >= 4) - throw new NotImplementedException(); - - TensorShape O; - if (inputRank == 1) - O = new TensorShape(X.flatHeight, depth); - else if (inputRank == 2) - O = new TensorShape(X.flatHeight, 1, depth, X.channels); - else - O = new TensorShape(X.batch, X.width, depth, X.channels); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/OneHot")); - if (inputRank == 1) - material.EnableKeyword("Input1D"); - else if (inputRank == 2) - material.EnableKeyword("Input2D"); - else - material.EnableKeyword("Input3D"); - - SetTensor(material, "X", X); - material.SetFloat("_Alpha", onValue); - material.SetFloat("_Beta", offValue); - - return Dispatch(material, X.dataType, O); - } - - /// - public override Tensor LRN(Tensor X, float alpha, float beta, float bias, int size) - { - var O = X.shape; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/LRN")); - - SetTensor(material, "X", X); - material.SetFloat("_Alpha", alpha); - material.SetFloat("_Beta", beta); - material.SetFloat("_Epsilon", bias); - material.SetInt("_Axis", size); - - return Dispatch(material, X.dataType, O); - } - - /// - /// Apply padding - /// - /// input - /// padding - /// kernel name - /// constant - /// output `Tensor` - protected virtual Tensor ApplyPadding(Tensor X, int[] pad, string kernelName, float constant = 0.0f) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pad.Length, 6); - - Assert.AreEqual(pad[2], 0, "PixelShader.ApplyPadding: unsupported channel-padding"); - Assert.AreEqual(pad[5], 0, "PixelShader.ApplyPadding: unsupported channel-padding"); - - - var Oshape = X.shape.ApplyBorder(pad); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader(kernelName)); - - SetTensor(material, "X", X); - - // TODO support C-padding - material.SetVector("_Pad", new Vector4(pad[0], pad[1], pad[3], pad[4])); - - - if (kernelName.Contains("Border2D")) - { - // NOTE: negative "pad" variable will crop X tensor - int croppedWidth = X.width - Math.Max(0, -pad[3]); - int croppedHeight = X.height - Math.Max(0, -pad[4]); - var croppedSize = new int[] { 0, 0 }; - croppedSize[0] = croppedWidth; - croppedSize[1] = croppedHeight; - - material.SetVector("_Pool", new Vector4(croppedSize[0], croppedSize[1], 0, 0)); - material.SetFloat("_Beta", constant); - } - - return Dispatch(material, X.dataType, Oshape); - } - - /// - public override Tensor Border2D(Tensor X, int[] pad, float constant) - { - if (pad[2] != 0 || pad[5] != 0) - return base.Border2D(X, pad, constant); - - return ApplyPadding(X, pad, "Barracuda/Border2D", constant); - } - - /// - public override Tensor Pad2DReflect(Tensor X, int[] pad) - { - if (pad[2] != 0 || pad[5] != 0) - return base.Pad2DReflect(X, pad); - - return ApplyPadding(X, pad, "Barracuda/Pad2DReflect"); - } - - /// - public override Tensor Pad2DSymmetric(Tensor X, int[] pad) - { - if (pad[2] != 0 || pad[5] != 0) - return base.Pad2DSymmetric(X, pad); - - return ApplyPadding(X, pad, "Barracuda/Pad2DSymmetric"); - } - - /// - public override Tensor Pad2DEdge(Tensor X, int[] pad) - { - if (pad[2] != 0 || pad[5] != 0) - return base.Pad2DEdge(X, pad); - - return ApplyPadding(X, pad, "Barracuda/Pad2DEdge"); - } - - /// - /// Generic activation function - /// - /// kernel name - /// input - /// alpha - /// beta - /// output Tensor - protected virtual Tensor Activation(string kernelName, Tensor X, float alpha = 0f, float beta = 0f) - { - Assert.IsTrue(X.shape.Is4D()); - - var Oshape = X.shape; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Activation")); - material.EnableKeyword(kernelName); - - SetTensor(material, "X", X); - material.SetFloat("_Alpha", alpha); - material.SetFloat("_Beta", beta); - - return Dispatch(material, X.dataType, Oshape); - } - - /// - - public override Tensor Relu(Tensor X) - { - if (!X.shape.Is4D()) - return base.Relu(X); - return Activation("Relu", X); - } - - /// - public override Tensor PRelu(Tensor X, Tensor S) - { - if (!X.shape.Is4D() && !S.shape.Is4D()) - return base.PRelu(X, S); - - Assert.IsTrue((X.flatWidth == S.flatWidth) || (S.flatWidth == 1)); - - var O = X.shape; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/PRelu")); - - SetTensor(material, "X", X); - SetTensor(material, "W", S); - - return Dispatch(material, X.dataType, O); - } - - /// - public override Tensor Tanh(Tensor X) - { - if(!X.shape.Is4D()) - return base.Tanh(X); - return Activation("Tanh", X); - } - - /// - public override Tensor Softplus(Tensor X) - { - if(!X.shape.Is4D()) - return base.Softplus(X); - return Activation("Softplus", X); - } - - /// - public override Tensor Sigmoid(Tensor X) - { - if(!X.shape.Is4D()) - return base.Sigmoid(X); - return Activation("Sigmoid", X); - } - - /// - public override Tensor HardSigmoid(Tensor X, float alpha, float beta) - { - if(!X.shape.Is4D()) - return base.HardSigmoid(X, alpha, beta); - return Activation("HardSigmoid", X, alpha, beta); - } - - /// - public override Tensor Relu6(Tensor X) - { - if(!X.shape.Is4D()) - return base.Relu6(X); - return Activation("Relu6", X); - } - - /// - public override Tensor Elu(Tensor X, float alpha) - { - if(!X.shape.Is4D()) - return base.Elu(X, alpha); - return Activation("Elu", X, alpha); - } - - /// - public override Tensor LeakyRelu(Tensor X, float alpha) - { - if(!X.shape.Is4D()) - return base.LeakyRelu(X, alpha); - return Activation("LeakyRelu", X, alpha); - } - - /// - public override Tensor Selu(Tensor X, float alpha, float gamma) - { - if(!X.shape.Is4D()) - return base.Selu(X, alpha, gamma); - return Activation("Selu", X, alpha, gamma); - } - - /// - public override Tensor Swish(Tensor X) - { - if(!X.shape.Is4D()) - return base.Swish(X); - return Activation("Swish", X); - } - - /// - public override Tensor Abs(Tensor X) - { - if(!X.shape.Is4D()) - return base.Abs(X); - return Activation("Abs", X); - } - - /// - public override Tensor Neg(Tensor X) - { - if(!X.shape.Is4D()) - return base.Neg(X); - return Activation("Neg", X); - } - - /// - public override Tensor Ceil(Tensor X) - { - if(!X.shape.Is4D()) - return base.Ceil(X); - return Activation("Ceil", X); - } - - /// - public override Tensor Clip(Tensor X, float min, float max) - { - if(!X.shape.Is4D()) - return base.Clip(X, min, max); - return Activation("Clip", X, min, max); - } - - /// - public override Tensor Floor(Tensor X) - { - if(!X.shape.Is4D()) - return base.Floor(X); - return Activation("Floor", X); - } - - /// - public override Tensor Round(Tensor X) - { - if(!X.shape.Is4D()) - return base.Round(X); - return Activation("Round", X); - } - - /// - public override Tensor Reciprocal(Tensor X) - { - if(!X.shape.Is4D()) - return base.Reciprocal(X); - return Activation("Reciprocal", X); - } - - /// - public override Tensor Pow(Tensor X, float alpha) - { - if(!X.shape.Is4D()) - return base.Pow(X, alpha); - return Activation("Pow", X, alpha); - } - - /// - public override Tensor Exp(Tensor X) - { - if(!X.shape.Is4D()) - return base.Exp(X); - return Activation("Exp", X); - } - - /// - public override Tensor Log(Tensor X) - { - if(!X.shape.Is4D()) - return base.Log(X); - return Activation("Log", X); - } - - /// - public override Tensor Sqrt(Tensor X) - { - if(!X.shape.Is4D()) - return base.Sqrt(X); - return Activation("Sqrt", X); - } - - /// - public override Tensor Acos(Tensor X) - { - if(!X.shape.Is4D()) - return base.Acos(X); - return Activation("Acos", X); - } - - /// - public override Tensor Acosh(Tensor X) - { - if(!X.shape.Is4D()) - return base.Acosh(X); - return Activation("Acosh", X); - } - - /// - public override Tensor Asin(Tensor X) - { - if(!X.shape.Is4D()) - return base.Asin(X); - return Activation("Asin", X); - } - - /// - public override Tensor Asinh(Tensor X) - { - if(!X.shape.Is4D()) - return base.Asin(X); - return Activation("Asinh", X); - } - - /// - public override Tensor Atan(Tensor X) - { - if(!X.shape.Is4D()) - return base.Atan(X); - return Activation("Atan", X); - } - - /// - public override Tensor Atanh(Tensor X) - { - if(!X.shape.Is4D()) - return base.Atanh(X); - return Activation("Atanh", X); - } - - /// - public override Tensor Cos(Tensor X) - { - if(!X.shape.Is4D()) - return base.Cos(X); - return Activation("Cos", X); - } - - /// - public override Tensor Cosh(Tensor X) - { - if(!X.shape.Is4D()) - return base.Cosh(X); - return Activation("Cosh", X); - } - - /// - public override Tensor Sin(Tensor X) - { - if(!X.shape.Is4D()) - return base.Sin(X); - return Activation("Sin", X); - } - - /// - public override Tensor Sinh(Tensor X) - { - if(!X.shape.Is4D()) - return base.Sinh(X); - return Activation("Sinh", X); - } - - /// - public override Tensor Tan(Tensor X) - { - if(!X.shape.Is4D()) - return base.Tan(X); - return Activation("Tan", X); - } - - /// - public override Tensor Erf(Tensor X) - { - if(!X.shape.Is4D()) - return base.Erf(X); - return Activation("Erf", X); - } - - /// - public override Tensor Softmax(Tensor X, int axis) - { - if(!X.shape.Is4D()) - return base.Softmax(X, axis); - - axis = X.shape.Axis(axis); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Softmax")); - - if(axis == TensorShape.DataBatch) - material.EnableKeyword("ReduceN"); - if (axis == TensorShape.H) - material.EnableKeyword("ReduceH"); - if (axis == TensorShape.W) - material.EnableKeyword("ReduceW"); - if (axis == TensorShape.C) - material.EnableKeyword("ReduceC"); - - SetTensor(material, "X", X); - - return Dispatch(material, X.dataType, X.shape); - } - - /// - public override Tensor LogSoftmax(Tensor X, int axis) - { - if(!X.shape.Is4D()) - return base.LogSoftmax(X, axis); - - axis = X.shape.Axis(axis); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/LogSoftmax")); - - if(axis == TensorShape.DataBatch) - material.EnableKeyword("ReduceN"); - if (axis == TensorShape.H) - material.EnableKeyword("ReduceH"); - if (axis == TensorShape.W) - material.EnableKeyword("ReduceW"); - if (axis == TensorShape.C) - material.EnableKeyword("ReduceC"); - - SetTensor(material, "X", X); - - return Dispatch(material, X.dataType, X.shape); - } - - /// - public override Tensor Upsample2D(Tensor X, int[] scale, bool bilinear) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(scale.Length, 2); - - var Oshape = new TensorShape(X.batch, X.height*scale[1], X.width*scale[0], X.channels); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader(bilinear ? "Barracuda/UpsampleBilinear2D" : "Barracuda/Upsample2D")); - - SetTensor(material, "X", X); - - material.SetVector("_Pool", new Vector4(scale[0], scale[1], 0,0)); - - return Dispatch(material, X.dataType, Oshape); - } - - /// - public override Tensor Resample2D(Tensor X, int[] size, bool bilinear) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(size.Length, 2); - - var Oshape = new TensorShape(X.batch, size[1], size[0], X.channels); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader(bilinear ? "Barracuda/ResampleBilinear2D" : "Barracuda/Resample2D")); - - - SetTensor(material, "X", X); - - return Dispatch(material, X.dataType, Oshape); - } - - /// - public override Tensor DepthToSpace(Tensor X, int[] blocksize, Layer.DepthToSpaceMode mode) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(blocksize.Length, 2); - - var O = new TensorShape(X.batch, X.height * blocksize[1], X.width * blocksize[0], X.channels / (blocksize[0] * blocksize[1])); - - - Material material = new Material(PixelShaderSingleton.Instance.FindShader(m_StringCache.Lookup("Barracuda/DepthToSpace_", mode.ToString()))); - - SetTensor(material, "X", X); - - material.SetVector("_Pool", new Vector4(blocksize[0], blocksize[1], 0, 0)); - - return Dispatch(material, X.dataType, O); - } - - /// - public override Tensor SpaceToDepth(Tensor X, int[] blocksize) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(blocksize.Length, 2); - - var O = new TensorShape(X.batch, X.height / blocksize[1], X.width / blocksize[0], X.channels * (blocksize[0] * blocksize[1])); - - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/SpaceToDepth")); - - SetTensor(material, "X", X); - - material.SetVector("_Pool", new Vector4(blocksize[0], blocksize[1], 0, 0)); - - return Dispatch(material, X.dataType, O); - } - - /// - public override Tensor Concat(Tensor[] tensors, int axis) - { - if (tensors.Any(x => !x.shape.Is4D())) - return base.Concat(tensors, axis); - - var Oshape = TensorExtensions.Concat(tensors, axis); - axis = Oshape.Axis(axis); - var axisNCHW = TensorExtensions.Convert8DAxisTo4D(axis); - Vector4 offsets = Vector4.zero; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Concat")); - - var dataType = tensors.Length > 0 ? tensors[0].dataType : DataType.Float; - var O = NewTensor(dataType, Oshape, AllocScope.LayerOutput, "O"); - var Opred = NewTensor(dataType, Oshape, AllocScope.LayerOutput, "O"); - - bool pingPong = true; - bool isFirstPass = true; - foreach (var inputTensor in tensors) - { - Assert.IsTrue(inputTensor.shape.Is4D()); - - SetTensor(material, "X", inputTensor); - SetTensor(material, "OPred", pingPong ? O : Opred); - - material.SetVector("_Pad", offsets); - - material.SetInt("_IsFirstPass", isFirstPass ? 1 : 0); - - var pinO = pingPong ? Pin(Opred) : Pin(O); - material.SetVector("OdeclShape", new Vector4(O.batch, O.height, O.width, O.channels)); - - Graphics.Blit(null, pinO.bufferAsTexture, material); - - offsets[axisNCHW] += inputTensor.shape[axis]; - - isFirstPass = false; - pingPong = !pingPong; - } - - return pingPong ? O : Opred; - } - - /// - public override Tensor StridedSlice(Tensor X, int[] starts, int[] ends, int[] strides) - { - if (X.shape.Is4D()) - return base.StridedSlice(X, starts, ends, strides); - - var Oshape = X.shape.ApplyStridedSlice(starts, ends, strides); - - Vector4 starts4d = new Vector4(); - starts4d[0] = Math.Min(TensorExtensions.WrapIndex(starts[TensorShape.DataBatch], X.batch), X.batch - 1); - starts4d[1] = Math.Min(TensorExtensions.WrapIndex(starts[TensorShape.H], X.height), X.height - 1); - starts4d[2] = Math.Min(TensorExtensions.WrapIndex(starts[TensorShape.W], X.width), X.width - 1); - starts4d[3] = Math.Min(TensorExtensions.WrapIndex(starts[TensorShape.C], X.channels), X.channels - 1); - - Vector4 strides4d = new Vector4(); - strides4d[0] = strides[TensorShape.DataBatch]; - strides4d[1] = strides[TensorShape.H]; - strides4d[2] = strides[TensorShape.W]; - strides4d[3] = strides[TensorShape.C]; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/StridedSlice")); - - SetTensor(material, "X", X); - material.SetVector("_Stride", new Vector4(strides4d[0], strides4d[1], strides4d[2], strides4d[3])); - material.SetVector("_Starts", new Vector4(starts4d[0], starts4d[1], starts4d[2], starts4d[3])); - - return Dispatch(material, X.dataType, Oshape); - } - - /// - public override Tensor Tile(Tensor X, int[] repeats) - { - var O = X.shape.Scale(repeats); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Tile")); - - SetTensor(material, "X", X); - - return Dispatch(material, X.dataType, O); - } - - /// - public override Tensor Gather(Tensor[] tensors, int axis) - { - Tensor X = tensors[0]; - Tensor indices = tensors[1]; - - var O = X.shape; - O[axis] = indices.length; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Gather")); - SetTensor(material, "X", X); - SetTensor(material, "K", indices); - material.SetInt("_Axis", axis == TensorShape.DataBatch ? 0 : axis - 4); - - return Dispatch(material, X.dataType, O); - } - - /// - public override Tensor ScatterND(Tensor X, Tensor indices, Tensor updates, Layer.ScatterNDReductionMode reduction) - { - // only support for scattering on C for now - Assert.IsTrue(indices.batch == X.batch); - Assert.IsTrue(updates.width == X.width && updates.height == X.height); - var O = X.shape; - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/ScatterND")); - SetTensor(material, "X", X); - SetTensor(material, "K", indices); - SetTensor(material, "W", updates); - - if (reduction == Layer.ScatterNDReductionMode.None) - material.EnableKeyword("ReduceNone"); - else if (reduction == Layer.ScatterNDReductionMode.Add) - material.EnableKeyword("ReduceAdd"); - else if (reduction == Layer.ScatterNDReductionMode.Mul) - material.EnableKeyword("ReduceMul"); - - return Dispatch(material, X.dataType, O); - } - - /// - public override Tensor ScaleBias(Tensor X, Tensor S, Tensor B) - { - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/ScaleBias")); - - SetTensor(material, "X", X); - SetTensor(material, "W", S); - SetTensor(material, "B", B); - - - return Dispatch(material, X.dataType, X.shape); - } - - /// - public override Tensor Transpose(Tensor X, int[] permutations) - { - if (X.shape.Is4D()) - return base.Transpose(X, permutations); - - Material material = new Material(Shader.Find("Barracuda/Transpose")); - - SetTensor(material, "X", X); - - - material.SetVector("_Pool", new Vector4(Array.IndexOf(permutations, 0), Array.IndexOf(permutations, 1), Array.IndexOf(permutations, 2), Array.IndexOf(permutations, 3))); - - return Dispatch(material, X.dataType, X.shape.Permute(permutations)); - } - - /// - public override Tensor Reshape(Tensor X, TensorShape newShape) - { - if (X.shape == newShape) - return Copy(X); - - Material material = new Material(PixelShaderSingleton.Instance.FindShader("Barracuda/Copy")); - - SetTensor(material, "X", X); - - return Dispatch(material, X.dataType, newShape); - } - - /// - public override Tensor Flatten(Tensor X) - { - var newShape = X.shape.Flatten(); - if (X.shape == newShape) - return base.Flatten(X); - - return Reshape(X, newShape); - } - - /// - public override Tensor Copy(Tensor X) - { - var O = NewTensor(X.dataType, X.shape, AllocScope.LayerOutput, "O"); - Graphics.Blit(Pin(X).bufferAsTexture, Pin(O).bufferAsTexture); - - return O; - } - - /// - public override Tensor Prepare(Tensor X) - { - Pin(X); - return X; - } - - /// - public override Tensor PrepareNoAlloc(Tensor X) - { - Pin(X, uploadCache: false); - return X; - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPixelShader.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPixelShader.cs.meta deleted file mode 100644 index 793bf1e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPixelShader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1126b6ab4d825624a9135b0501f4d793 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPrecompiledCompute.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPrecompiledCompute.cs deleted file mode 100644 index ac5e7a0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPrecompiledCompute.cs +++ /dev/null @@ -1,1614 +0,0 @@ -using UnityEngine; -using UnityEngine.Assertions; -using System; -using System.Linq; -using System.Collections.Generic; -using Unity.Collections; - - -namespace Unity.Barracuda { - -/// -/// Precompiled GPU compute `IOps` implementation -/// -public class PrecompiledComputeOps : ComputeOps, IModelCompiler -{ - /// - /// Create `PrecompiledComputeOps` - /// - /// allocator - /// verbose flag - public PrecompiledComputeOps(ITensorAllocator allocator = null, bool verbose = false) - : base(allocator, verbose) - { - } - - // --------------------------------------------------------------------------------- - - static internal ComputeFunc.TensorDecl _DeclX = ComputeFunc.GetTensorDecl("X"); - static internal ComputeFunc.TensorDecl _DeclO = ComputeFunc.GetTensorDecl("O"); - static internal ComputeFunc.TensorDecl _DeclW = ComputeFunc.GetTensorDecl("W"); - static internal ComputeFunc.TensorDecl _DeclK = ComputeFunc.GetTensorDecl("K"); - static internal ComputeFunc.TensorDecl _DeclB = ComputeFunc.GetTensorDecl("B"); - static internal int _DataX = ComputeFunc.GetTensorData("X"); - static internal int _DataO = ComputeFunc.GetTensorData("O"); - static internal int _DataW = ComputeFunc.GetTensorData("W"); - static internal int _DataK = ComputeFunc.GetTensorData("K"); - static internal int _DataB = ComputeFunc.GetTensorData("B"); - static internal int _DataWBK = ComputeFunc.GetTensorData("WBK"); - static internal int _Stride = Shader.PropertyToID("_Stride"); - static internal int _Pad = Shader.PropertyToID("_Pad"); - static internal int _Pool = Shader.PropertyToID("_Pool"); - static internal int _Alpha = Shader.PropertyToID("_Alpha"); - static internal int _Beta = Shader.PropertyToID("_Beta"); - - private struct CompiledInstruction - { - public ComputeKernel kernel; - public Tensor[] tensors; - public TensorShape shape; - } - - private struct CompiledLayer - { - // output shape might not match instruction output shape - public TensorShape shape; - public CompiledInstruction[] instructions; - - // most layers are made up of 1 instruction - public ComputeKernel kernel { get { return (instructions == null) ? new ComputeKernel() : instructions[0].kernel; } } - } - - private int m_CachedModelHash; - private Dictionary m_CompiledLayers = new Dictionary(); - private CompiledLayer m_Compiled; - - private class GPUTempMemoryBlock - { -#if ENABLE_BARRACUDA_STATS - public TempMemoryStatistics stats { get; private set; } -#endif //ENABLE_BARRACUDA_STATS - public ComputeBuffer computeBuffer { get; private set; } - - public GPUTempMemoryBlock(string name, int count, int stride) - { - computeBuffer = new ComputeBuffer(count, stride); -#if ENABLE_BARRACUDA_STATS - stats = new TempMemoryStatistics(UniqueResourceId.GetUniqueId(), computeBuffer.count * computeBuffer.stride, true, name); -#endif //ENABLE_BARRACUDA_STATS - } - - public void SetComputeBuffer(ComputeBuffer buffer) - { - computeBuffer = buffer; -#if ENABLE_BARRACUDA_STATS - stats = new TempMemoryStatistics(UniqueResourceId.GetUniqueId(), buffer.count * buffer.stride, true, stats.name); -#endif //ENABLE_BARRACUDA_STATS - } - } - - private Dictionary m_CachedModelBuffers = new Dictionary(); - - private ComputeBuffer NewComputeBuffer(string name, int count, int stride) - { - if(!m_CachedModelBuffers.ContainsKey(name)) - m_CachedModelBuffers[name] = new GPUTempMemoryBlock(name, count, stride); - if(m_CachedModelBuffers[name].computeBuffer.count != count || m_CachedModelBuffers[name].computeBuffer.stride != stride) - { - m_CachedModelBuffers[name].computeBuffer.Dispose(); - m_CachedModelBuffers[name].SetComputeBuffer(new ComputeBuffer(count, stride)); - } - - return m_CachedModelBuffers[name].computeBuffer; - } - -#if ENABLE_BARRACUDA_STATS - public override IEnumerable GetTempMemoryStatistics() - { - return m_CachedModelBuffers.Values.Select(x => x.stats); - } -#endif //ENABLE_BARRACUDA_STATS - - private void ClearCachedModelBuffers() - { - foreach (var buf in m_CachedModelBuffers) - buf.Value.computeBuffer.Dispose(); - m_CachedModelBuffers.Clear(); - - foreach (var l in m_CompiledLayers) - foreach (var i in l.Value.instructions) - { - if (i.tensors == null) - continue; - foreach (var t in i.tensors) - t.Dispose(); - } - m_CompiledLayers.Clear(); - } - - /// - public override void ResetAllocator(bool keepCachedMemory = true) - { - if (!keepCachedMemory) - { - ClearCachedModelBuffers(); - } - - base.ResetAllocator(keepCachedMemory); - } - - private int CalcModelWithInputsHashCode(Model model, IDictionary inputShapes) - { - var hash = model.GetHashCode(); - foreach (var entry in inputShapes) - { - hash = (hash * 7) + entry.Key.GetHashCode(); - hash = (hash * 7) + entry.Value.GetHashCode(); - } - return hash; - } - - private void GetKBWeightsForLayer(Layer l, IVars vars, - out BarracudaArray kData, out int kOffset, - out BarracudaArray bData, out int bOffset) - { - if (l.weights != null) - { - //data still available on CPU mem, directly use it - kData = l.weights; - bData = l.weights; - kOffset = (int)l.datasets[0].offset; - bOffset = (int)l.datasets[1].offset; - } - else - { - //model memory ownership have been transfer to vars and wiped from CPU mem - //need to get data from Tensor to prepare model - var inputs = vars.PeekConstants(l.name); - kData = inputs[0].data.SharedAccess(out kOffset); - bData = inputs[1].data.SharedAccess(out bOffset); - } - } - - private Tensor[] PrepareConv2dWinograd2x2_3x3(Model model, Layer l, IVars vars) - { - var K = l.datasets[0]; - var Kshape = new TensorShape(K.shape.batch + 1, K.shape.height + 1, K.shape.width, K.shape.channels); - - var B = l.datasets[1]; - var Bshape = B.shape; - - var weights = new BarracudaArray(Kshape.length + Bshape.length, l.weights.Type); - - GetKBWeightsForLayer(l, vars, - out var kData, out var kOffset, - out var bData, out var bOffset); - - for (int c = 0; c < Kshape.kernelDepth; ++c) - for (int k = 0; k < Kshape.kernelCount; ++k) - { - float g00 = kData[kOffset + K.shape.Index(0, 0, c, k)]; - float g01 = kData[kOffset + K.shape.Index(0, 1, c, k)]; - float g02 = kData[kOffset + K.shape.Index(0, 2, c, k)]; - float g10 = kData[kOffset + K.shape.Index(1, 0, c, k)]; - float g11 = kData[kOffset + K.shape.Index(1, 1, c, k)]; - float g12 = kData[kOffset + K.shape.Index(1, 2, c, k)]; - float g20 = kData[kOffset + K.shape.Index(2, 0, c, k)]; - float g21 = kData[kOffset + K.shape.Index(2, 1, c, k)]; - float g22 = kData[kOffset + K.shape.Index(2, 2, c, k)]; - - // float4x3 Winograd_G = float4x3(float3(1, 0, 0), float3(0.5, 0.5, 0.5), float3(0.5, -0.5, 0.5), float3(0, 0, 1)); - // float3x4 Winograd_GT = transpose(Winograd_G); - // float4x4 v = mul(Winograd_G, mul(g, Winograd_GT)); - float w00 = g00; - float w01 = 0.5f * g00 + 0.5f * g01 + 0.5f * g02; - float w02 = 0.5f * g00 - 0.5f * g01 + 0.5f * g02; - float w03 = g02; - - float w10 = g10; - float w11 = 0.5f * g10 + 0.5f * g11 + 0.5f * g12; - float w12 = 0.5f * g10 - 0.5f * g11 + 0.5f * g12; - float w13 = g12; - - float w20 = g20; - float w21 = 0.5f * g20 + 0.5f * g21 + 0.5f * g22; - float w22 = 0.5f * g20 - 0.5f * g21 + 0.5f * g22; - float w23 = g22; - - float v00 = w00; - float v01 = w01; - float v02 = w02; - float v03 = w03; - - float v10 = 0.5f * w00 + 0.5f * w10 + 0.5f * w20; - float v11 = 0.5f * w01 + 0.5f * w11 + 0.5f * w21; - float v12 = 0.5f * w02 + 0.5f * w12 + 0.5f * w22; - float v13 = 0.5f * w03 + 0.5f * w13 + 0.5f * w23; - - float v20 = 0.5f * w00 - 0.5f * w10 + 0.5f * w20; - float v21 = 0.5f * w01 - 0.5f * w11 + 0.5f * w21; - float v22 = 0.5f * w02 - 0.5f * w12 + 0.5f * w22; - float v23 = 0.5f * w03 - 0.5f * w13 + 0.5f * w23; - - float v30 = w20; - float v31 = w21; - float v32 = w22; - float v33 = w23; - - weights[Kshape.Index(0, 0, c, k)] = v00; - weights[Kshape.Index(1, 0, c, k)] = v10; - weights[Kshape.Index(2, 0, c, k)] = v20; - weights[Kshape.Index(3, 0, c, k)] = v30; - weights[Kshape.Index(0, 1, c, k)] = v01; - weights[Kshape.Index(1, 1, c, k)] = v11; - weights[Kshape.Index(2, 1, c, k)] = v21; - weights[Kshape.Index(3, 1, c, k)] = v31; - weights[Kshape.Index(0, 2, c, k)] = v02; - weights[Kshape.Index(1, 2, c, k)] = v12; - weights[Kshape.Index(2, 2, c, k)] = v22; - weights[Kshape.Index(3, 2, c, k)] = v32; - weights[Kshape.Index(0, 3, c, k)] = v03; - weights[Kshape.Index(1, 3, c, k)] = v13; - weights[Kshape.Index(2, 3, c, k)] = v23; - weights[Kshape.Index(3, 3, c, k)] = v33; - } - - BarracudaArray.Copy(bData, (int)bOffset, weights, Kshape.length, B.length); - - ComputeBuffer buffer = NewComputeBuffer(l.name + "_precompiled", Kshape.length + Bshape.length, sizeof(float));//TODO fp16? - weights.UploadToComputeBuffer(buffer); - var Kw = new Tensor(Kshape, new SharedComputeTensorData(buffer, Kshape, 0)); - var Bw = new Tensor(Bshape, new SharedComputeTensorData(buffer, Bshape, Kshape.length)); - - return new Tensor[] { Kw, Bw }; - } - private Tensor[] PrepareConv2dWinograd2x2_5x5(Model model, Layer l, IVars vars) - { - var K = l.datasets[0]; - var Kshape = new TensorShape(K.shape.batch + 1, K.shape.height + 1, K.shape.width, K.shape.channels); - - var B = l.datasets[1]; - var Bshape = B.shape; - - var weights = new BarracudaArray(Kshape.length + Bshape.length, l.weights.Type); - - GetKBWeightsForLayer(l, vars, - out var kData, out var kOffset, - out var bData, out var bOffset); - - for (int c = 0; c < Kshape.kernelDepth; ++c) - for (int k = 0; k < Kshape.kernelCount; ++k) - { - float g00 = kData[kOffset + K.shape.Index(0, 0, c, k)]; - float g01 = kData[kOffset + K.shape.Index(0, 1, c, k)]; - float g02 = kData[kOffset + K.shape.Index(0, 2, c, k)]; - float g03 = kData[kOffset + K.shape.Index(0, 3, c, k)]; - float g04 = kData[kOffset + K.shape.Index(0, 4, c, k)]; - - float g10 = kData[kOffset + K.shape.Index(1, 0, c, k)]; - float g11 = kData[kOffset + K.shape.Index(1, 1, c, k)]; - float g12 = kData[kOffset + K.shape.Index(1, 2, c, k)]; - float g13 = kData[kOffset + K.shape.Index(1, 3, c, k)]; - float g14 = kData[kOffset + K.shape.Index(1, 4, c, k)]; - - float g20 = kData[kOffset + K.shape.Index(2, 0, c, k)]; - float g21 = kData[kOffset + K.shape.Index(2, 1, c, k)]; - float g22 = kData[kOffset + K.shape.Index(2, 2, c, k)]; - float g23 = kData[kOffset + K.shape.Index(2, 3, c, k)]; - float g24 = kData[kOffset + K.shape.Index(2, 4, c, k)]; - - float g30 = kData[kOffset + K.shape.Index(3, 0, c, k)]; - float g31 = kData[kOffset + K.shape.Index(3, 1, c, k)]; - float g32 = kData[kOffset + K.shape.Index(3, 2, c, k)]; - float g33 = kData[kOffset + K.shape.Index(3, 3, c, k)]; - float g34 = kData[kOffset + K.shape.Index(3, 4, c, k)]; - - float g40 = kData[kOffset + K.shape.Index(4, 0, c, k)]; - float g41 = kData[kOffset + K.shape.Index(4, 1, c, k)]; - float g42 = kData[kOffset + K.shape.Index(4, 2, c, k)]; - float g43 = kData[kOffset + K.shape.Index(4, 3, c, k)]; - float g44 = kData[kOffset + K.shape.Index(4, 4, c, k)]; - - // mul(Winograd_G, mul(g, Winograd_GT)); - //static const float5x6 Winograd_G = 1/24 * {{6, 0, 0, 0, 0}, {-4, -4, -4, -4, -4}, {-4, 4, -4, 4, -4⎥}, {1, 2, 4, 8, 16}, {1, -2, 4, -8, 16}, {0, 0, 0, 0, 24}} - //static const float6x5 Winograd_GT = 1/24 * {{6, -4, -4, 1, 1, 0}, {0, -4, 4, 2, -2, 0}, {0, -4, -4, 4, 4, 0}, {0, -4, 4, 8, -8, 0}, {0, -4, -4, 16, 16, 24}} - - float a00 = 6 * g00 / 24; - float a10 = 6 * g10 / 24; - float a20 = 6 * g20 / 24; - float a30 = 6 * g30 / 24; - float a40 = 6 * g40 / 24; - - float a01 = (-4 * g00 - 4 * g01 - 4 * g02 - 4 * g03 - 4 * g04) / 24; - float a11 = (-4 * g10 - 4 * g11 - 4 * g12 - 4 * g13 - 4 * g14) / 24; - float a21 = (-4 * g20 - 4 * g21 - 4 * g22 - 4 * g23 - 4 * g24) / 24; - float a31 = (-4 * g30 - 4 * g31 - 4 * g32 - 4 * g33 - 4 * g34) / 24; - float a41 = (-4 * g40 - 4 * g41 - 4 * g42 - 4 * g43 - 4 * g44) / 24; - - float a02 = (-4 * g00 + 4 * g01 - 4 * g02 + 4 * g03 - 4 * g04) / 24; - float a12 = (-4 * g10 + 4 * g11 - 4 * g12 + 4 * g13 - 4 * g14) / 24; - float a22 = (-4 * g20 + 4 * g21 - 4 * g22 + 4 * g23 - 4 * g24) / 24; - float a32 = (-4 * g30 + 4 * g31 - 4 * g32 + 4 * g33 - 4 * g34) / 24; - float a42 = (-4 * g40 + 4 * g41 - 4 * g42 + 4 * g43 - 4 * g44) / 24; - - float a03 = (g00 + 2 * g01 + 4 * g02 + 8 * g03 + 16 * g04) / 24; - float a13 = (g10 + 2 * g11 + 4 * g12 + 8 * g13 + 16 * g14) / 24; - float a23 = (g20 + 2 * g21 + 4 * g22 + 8 * g23 + 16 * g24) / 24; - float a33 = (g30 + 2 * g31 + 4 * g32 + 8 * g33 + 16 * g34) / 24; - float a43 = (g40 + 2 * g41 + 4 * g42 + 8 * g43 + 16 * g44) / 24; - - float a04 = (g00 - 2 * g01 + 4 * g02 - 8 * g03 + 16 * g04) / 24; - float a14 = (g10 - 2 * g11 + 4 * g12 - 8 * g13 + 16 * g14) / 24; - float a24 = (g20 - 2 * g21 + 4 * g22 - 8 * g23 + 16 * g24) / 24; - float a34 = (g30 - 2 * g31 + 4 * g32 - 8 * g33 + 16 * g34) / 24; - float a44 = (g40 - 2 * g41 + 4 * g42 - 8 * g43 + 16 * g44) / 24; - - float a05 = g04; - float a15 = g14; - float a25 = g24; - float a35 = g34; - float a45 = g44; - - weights[Kshape.Index(0, 0, c, k)] = 6 * a00 / 24; - weights[Kshape.Index(0, 1, c, k)] = 6 * a01 / 24; - weights[Kshape.Index(0, 2, c, k)] = 6 * a02 / 24; - weights[Kshape.Index(0, 3, c, k)] = 6 * a03 / 24; - weights[Kshape.Index(0, 4, c, k)] = 6 * a04 / 24; - weights[Kshape.Index(0, 5, c, k)] = 6 * a05 / 24; - - weights[Kshape.Index(1, 0, c, k)] = (-4 * a00 - 4 * a10 - 4 * a20 - 4 * a30 - 4 * a40) / 24; - weights[Kshape.Index(1, 1, c, k)] = (-4 * a01 - 4 * a11 - 4 * a21 - 4 * a31 - 4 * a41) / 24; - weights[Kshape.Index(1, 2, c, k)] = (-4 * a02 - 4 * a12 - 4 * a22 - 4 * a32 - 4 * a42) / 24; - weights[Kshape.Index(1, 3, c, k)] = (-4 * a03 - 4 * a13 - 4 * a23 - 4 * a33 - 4 * a43) / 24; - weights[Kshape.Index(1, 4, c, k)] = (-4 * a04 - 4 * a14 - 4 * a24 - 4 * a34 - 4 * a44) / 24; - weights[Kshape.Index(1, 5, c, k)] = (-4 * a05 - 4 * a15 - 4 * a25 - 4 * a35 - 4 * a45) / 24; - - weights[Kshape.Index(2, 0, c, k)] = (-4 * a00 + 4 * a10 -4 * a20 + 4 * a30 -4 * a40) / 24; - weights[Kshape.Index(2, 1, c, k)] = (-4 * a01 + 4 * a11 -4 * a21 + 4 * a31 -4 * a41) / 24; - weights[Kshape.Index(2, 2, c, k)] = (-4 * a02 + 4 * a12 -4 * a22 + 4 * a32 -4 * a42) / 24; - weights[Kshape.Index(2, 3, c, k)] = (-4 * a03 + 4 * a13 -4 * a23 + 4 * a33 -4 * a43) / 24; - weights[Kshape.Index(2, 4, c, k)] = (-4 * a04 + 4 * a14 -4 * a24 + 4 * a34 -4 * a44) / 24; - weights[Kshape.Index(2, 5, c, k)] = (-4 * a05 + 4 * a15 -4 * a25 + 4 * a35 -4 * a45) / 24; - - weights[Kshape.Index(3, 0, c, k)] = (a00 + 2 * a10 + 4 * a20 + 8 * a30 + 16 * a40) / 24; - weights[Kshape.Index(3, 1, c, k)] = (a01 + 2 * a11 + 4 * a21 + 8 * a31 + 16 * a41) / 24; - weights[Kshape.Index(3, 2, c, k)] = (a02 + 2 * a12 + 4 * a22 + 8 * a32 + 16 * a42) / 24; - weights[Kshape.Index(3, 3, c, k)] = (a03 + 2 * a13 + 4 * a23 + 8 * a33 + 16 * a43) / 24; - weights[Kshape.Index(3, 4, c, k)] = (a04 + 2 * a14 + 4 * a24 + 8 * a34 + 16 * a44) / 24; - weights[Kshape.Index(3, 5, c, k)] = (a05 + 2 * a15 + 4 * a25 + 8 * a35 + 16 * a45) / 24; - - weights[Kshape.Index(4, 0, c, k)] = (a00 - 2 * a10 + 4 * a20 - 8 * a30 + 16 * a40) / 24; - weights[Kshape.Index(4, 1, c, k)] = (a01 - 2 * a11 + 4 * a21 - 8 * a31 + 16 * a41) / 24; - weights[Kshape.Index(4, 2, c, k)] = (a02 - 2 * a12 + 4 * a22 - 8 * a32 + 16 * a42) / 24; - weights[Kshape.Index(4, 3, c, k)] = (a03 - 2 * a13 + 4 * a23 - 8 * a33 + 16 * a43) / 24; - weights[Kshape.Index(4, 4, c, k)] = (a04 - 2 * a14 + 4 * a24 - 8 * a34 + 16 * a44) / 24; - weights[Kshape.Index(4, 5, c, k)] = (a05 - 2 * a15 + 4 * a25 - 8 * a35 + 16 * a45) / 24; - - weights[Kshape.Index(5, 0, c, k)] = a40; - weights[Kshape.Index(5, 1, c, k)] = a41; - weights[Kshape.Index(5, 2, c, k)] = a42; - weights[Kshape.Index(5, 3, c, k)] = a43; - weights[Kshape.Index(5, 4, c, k)] = a44; - weights[Kshape.Index(5, 5, c, k)] = a45; - } - - BarracudaArray.Copy(bData, (int)bOffset, weights, Kshape.length, B.length); - - ComputeBuffer buffer = NewComputeBuffer(l.name + "_precompiled", Kshape.length + Bshape.length, sizeof(float));//TODO fp16? - weights.UploadToComputeBuffer(buffer); - var Kw = new Tensor(Kshape, new SharedComputeTensorData(buffer, Kshape, 0)); - var Bw = new Tensor(Bshape, new SharedComputeTensorData(buffer, Bshape, Kshape.length)); - - return new Tensor[] { Kw, Bw }; - } - - private Tensor[] PrepareConv2DTrans(Model model, Layer l, IVars vars) - { - var K = l.datasets[0]; - var B = l.datasets[1]; - - var weights = new BarracudaArray(K.length + B.length, l.weights.Type); - - GetKBWeightsForLayer(l, vars, - out var kData, out var kOffset, - out var bData, out var bOffset); - - for (int y = 0; y < K.shape.kernelHeight; ++y) - for (int x = 0; x < K.shape.kernelWidth; ++x) - for (int c = 0; c < K.shape.kernelDepth; ++c) - for (int k = 0; k < K.shape.kernelCount; ++k) - { - float v = kData[kOffset + K.shape.Index(K.shape.kernelHeight - 1 - y, K.shape.kernelWidth - 1 - x, c, k)]; - weights[K.shape.Index(y, x, c, k)] = v; - } - - BarracudaArray.Copy(bData, bOffset, weights, K.length, B.length); - - ComputeBuffer buffer = NewComputeBuffer(l.name + "_precompiled", K.length + B.length, sizeof(float));//TODO fp16? - weights.UploadToComputeBuffer(buffer); - var Kw = new Tensor(K.shape, new SharedComputeTensorData(buffer, K.shape, 0)); - var Bw = new Tensor(B.shape, new SharedComputeTensorData(buffer, B.shape, K.length)); - - return new Tensor[] { Kw, Bw }; - } - - /// - public virtual void PrepareModel(Model model, IDictionary inputShapes, IVars vars) - { - var modelHash = CalcModelWithInputsHashCode(model, inputShapes); - if (modelHash == m_CachedModelHash) - return; - m_CachedModelHash = modelHash; - - //Clear temporary buffers from previous model preparations - ClearCachedModelBuffers(); - - IDictionary shapesByName; - ModelAnalyzer.ListTemporaryTensorShapes(model, inputShapes, out shapesByName); - - foreach (var l in model.layers) - { - if (m_CompiledLayers.ContainsKey(l)) - continue; // already compiled - - if (l.inputs.Length == 0) - continue; // don't need to compile layers without inputs, so far all of them are CPU only - - if (!shapesByName.TryGetValue(l.inputs[0], out TensorShape? input0Shape) - || input0Shape == null - || !shapesByName.TryGetValue(l.name, out TensorShape? outputShape) - || outputShape == null) - continue; - - var X = shapesByName[l.inputs[0]].Value; - var O = shapesByName[l.name].Value; - - ComputeKernel kernel = new ComputeKernel(); - if (l.type == Layer.Type.Dense) - { - var instructions = new List(); - var itemSize = 4; // @TODO: itemSizeInBytes == 2 | float16 - kernel = BestKernel(ComputeKernelLibrary.Dense(X, l.datasets[0].shape, O, itemSize >> 2)); - instructions.Add(new CompiledInstruction {kernel = kernel, shape = O}); - - if (ShouldFlattenInputForDenseLayer(X)) - { - var flattenedShape = X.Flatten(); - var flattenKernel = BestKernel(ComputeKernelLibrary.ReshapeFromNHWCModel(flattenedShape)); - instructions.Add(new CompiledInstruction { kernel = flattenKernel, shape = flattenedShape}); - } - - // FusedActivation - var fusedActivation = (Layer.FusedActivation) l.activation; - if (!IsFusedActivationSupported(fusedActivation)) - { - var activationKernel = BestKernel(ComputeKernelLibrary.Activation(X, O, fusedActivation.ToString())); - instructions.Add(new CompiledInstruction { kernel = activationKernel, shape = O }); - } - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - continue; - } - else if (l.type == Layer.Type.Dense3) - { - var instructions = new List(); - kernel = BestKernel(ComputeKernelLibrary.Dense3(X, l.datasets[0].shape, O)); - instructions.Add(new CompiledInstruction {kernel = kernel, shape = O}); - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - continue; - } - else if ( - l.type == Layer.Type.Conv2D) - { - Assert.IsNotNull(l.stride); - Assert.IsNotNull(l.pad); - var instructions = new List(); - - // Conv2D - var kernelConv = BestKernel(ComputeKernelLibrary.Conv2D(X, l.datasets[0].shape, O, l.stride, l.pad)); - bool isConvWinograd = (kernelConv.func.kernelName.StartsWith("Conv2DWinograd")) || (kernelConv.func.kernelName.StartsWith("Conv2D_Winograd")); - - instructions.Add(new CompiledInstruction { kernel = kernelConv, shape = O, tensors = isConvWinograd ? PrepareConv2dWinograd2x2_3x3(model, l, vars) : null }); - - // FusedActivation - var fusedActivation = (Layer.FusedActivation) l.activation; - if (!IsFusedActivationSupported(fusedActivation)) - { - var activationKernel = BestKernel(ComputeKernelLibrary.Activation(X, O, fusedActivation.ToString())); - instructions.Add(new CompiledInstruction {kernel = activationKernel, shape = O}); - } - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - continue; - } - else if ( - l.type == Layer.Type.DepthwiseConv2D) - { - var instructions = new List(); - - var K = l.datasets[0].shape; - - // DepthwiseConv2D - var kernelDepthwiseConv = BestKernel(ComputeKernelLibrary.DepthwiseConv2D(X, K, O, l.stride)); - bool isConvWinograd = (kernelDepthwiseConv.func.kernelName.StartsWith("DepthwiseConv2D_Winograd")); - - if(!isConvWinograd) - instructions.Add(new CompiledInstruction { kernel = kernelDepthwiseConv, shape = O, tensors = null }); - else - { - instructions.Add(new CompiledInstruction { kernel = kernelDepthwiseConv, shape = O, tensors = (K.batch == 3 && K.height == 3) ? PrepareConv2dWinograd2x2_3x3(model, l, vars) : PrepareConv2dWinograd2x2_5x5(model, l, vars) }); - } - - // FusedActivation - var fusedActivation = (Layer.FusedActivation) l.activation; - if (!IsFusedActivationSupported(fusedActivation)) - { - var activationKernel = BestKernel(ComputeKernelLibrary.Activation(X, O, fusedActivation.ToString())); - instructions.Add(new CompiledInstruction {kernel = activationKernel, shape = O}); - } - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - continue; - } - else if ( - l.type == Layer.Type.Conv2DTrans) - { - var instructions = new List(); - - var outputAdjustment = l.pool; - var stride = l.stride; - - var K = l.datasets[0].shape; - var B = l.datasets[1].shape; - - var pad = new int[] - { - K.kernelWidth - l.pad[0] - 1, K.kernelHeight - l.pad[1] - 1, - K.kernelWidth - l.pad[2] - 1, K.kernelHeight - l.pad[3] - 1 - }; - - if (stride[0] * stride[1] <= 4) - { - var XpaddedShape = new TensorShape(X.batch, stride[1] * (X.height - 1) + 1 + outputAdjustment[1], stride[0] * (X.width - 1) + 1 + outputAdjustment[0], X.channels); - - var kernelFill = CompileKernel(new ComputeKernelLibrary.Entry("Conv2DTransPadFill", (X.channels, X.width, X.height), 1.0f, 0)); - - var kernelConv = BestKernel( - ComputeKernelLibrary.Conv2D(XpaddedShape, K, O, new int[] { 1, 1 }, pad)); - bool isConvWinograd = (kernelConv.func.kernelName.StartsWith("Conv2DWinograd")) || (kernelConv.func.kernelName.StartsWith("Conv2D_Winograd")); - - var KBTensors = PrepareConv2DTrans(model, l, vars); - - instructions.Add(new CompiledInstruction { kernel = kernelFill, shape = XpaddedShape }); - instructions.Add(new CompiledInstruction { shape = K, tensors = KBTensors }); - - if (isConvWinograd) - { - var layer = new Layer(l.name, l.type, l.activation); - layer.pad = l.pad; - layer.stride = l.stride; - - layer.pool = l.pool.ToArray(); - layer.axis = l.axis; - layer.alpha = l.alpha; - layer.beta = l.beta; - layer.inputs = l.inputs.ToArray(); - - var Kd = KBTensors[0]; - var Bd = KBTensors[1]; - - layer.datasets = new Layer.DataSet[2]; - layer.datasets[0].name = Kd.name; - layer.datasets[0].shape = Kd.shape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = Kd.length; - layer.datasets[0].offset = 0; - - layer.datasets[1].name = Bd.name; - layer.datasets[1].shape = Bd.shape; - layer.datasets[1].itemSizeInBytes = 4; - layer.datasets[1].length = Bd.length; - layer.datasets[1].offset = Kd.length; - - layer.weights = new BarracudaArray(Kd.length + Bd.length, l.weights.Type); - - BarracudaArray.Copy(Kd.ToReadOnlyArray(), 0, layer.weights, 0, Kd.length); - BarracudaArray.Copy(Bd.ToReadOnlyArray(), 0, layer.weights, Kd.length, Bd.length); - - instructions.Add(new CompiledInstruction { kernel = kernelConv, shape = O, tensors = PrepareConv2dWinograd2x2_3x3(model, layer, vars) }); - } - else - instructions.Add(new CompiledInstruction { kernel = kernelConv, shape = O, tensors = null }); - - // FusedActivation - var fusedActivation = (Layer.FusedActivation)l.activation; - if (!IsFusedActivationSupported(fusedActivation)) - { - var activationKernel = BestKernel(ComputeKernelLibrary.Activation(X, O, fusedActivation.ToString())); - instructions.Add(new CompiledInstruction { kernel = activationKernel, shape = O }); - } - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - } - else - { - var kernelConvTrans = BestKernel(ComputeKernelLibrary.Conv2DTrans(X, K, O)); - instructions.Add(new CompiledInstruction { kernel = kernelConvTrans, shape = O, tensors = null }); - - // FusedActivation - var fusedActivation = (Layer.FusedActivation)l.activation; - if (!IsFusedActivationSupported(fusedActivation)) - { - var activationKernel = BestKernel(ComputeKernelLibrary.Activation(X, O, fusedActivation.ToString())); - instructions.Add(new CompiledInstruction { kernel = activationKernel, shape = O }); - } - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - } - - continue; - } - else if (l.type == Layer.Type.Upsample2D) - { - // axis is treated as upsample point/bilinear flag - var bilinear = l.axis > 0; - kernel = BestKernel( - ComputeKernelLibrary.Upsample2D(X, O, l.pool, bilinear)); - } - else if ( - l.type == Layer.Type.MaxPool2D || - l.type == Layer.Type.AvgPool2D) - { - var kernelName = l.type.ToString(); - - Assert.IsNotNull(l.pool); - Assert.IsNotNull(l.stride); - Assert.IsNotNull(l.pad); - kernel = BestKernel( - ComputeKernelLibrary.Pool2D(X, O, kernelName)); - } - else if ( - l.type == Layer.Type.GlobalMaxPool2D || - l.type == Layer.Type.GlobalAvgPool2D) - { - var poolKernelName = l.type.ToString().Substring(6) + "Reduce"; - var globalKernelName = l.type.ToString(); - - var instructions = new List(); - var Xr = X; - while (Xr.height > 8*2 || Xr.width > 8*2) - { - var lastLength = Xr.length; - var pool = new[] { 8, 8 }; - var stride = pool; - var pad = new[] { 0, 0, 0, 0 }; - - var Oshape = Xr.ApplyPool(pool, stride, pad, ceilMode: true); - var Or = new TensorShape(Oshape.batch, ComputeHelper.IDivC(Oshape.height, 2), ComputeHelper.IDivC(Oshape.width, 2), Oshape.channels); - var poolKernel = BestKernel( - ComputeKernelLibrary.Pool2DReduce(Xr, Or, poolKernelName)); - - instructions.Add(new CompiledInstruction { kernel = poolKernel, shape = Or }); - - Xr = Or; - Assert.IsTrue(Xr.length < lastLength); - } - - var globalKernel = BestKernel( - ComputeKernelLibrary.GlobalPool2D(Xr, O, globalKernelName)); - - instructions.Add(new CompiledInstruction { kernel = globalKernel, shape = O }); - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - - continue; - } - else if ( - l.type == Layer.Type.ScaleBias) - { - kernel = BestKernel( - ComputeKernelLibrary.ScaleBias(X, O)); - } - else if ( - l.type == Layer.Type.Normalization) - { - // GlobalAvgVariancePool2D - var poolKernelName = "AvgVariancePool2DReduce"; - var globalKernelName = "GlobalAvgVariancePool2D"; - - var instructions = new List(); - var Xr = X; - while (Xr.height > 8*2 || Xr.width > 8*2) - { - var lastLength = Xr.length; - var pool = new[] { 8, 8 }; - var stride = pool; - var pad = new[] { 0, 0, 0, 0 }; - - var Oshape = Xr.ApplyPool(pool, stride, pad, ceilMode: true); - var Or = new TensorShape(Oshape.batch, ComputeHelper.IDivC(Oshape.height, 2), ComputeHelper.IDivC(Oshape.width, 2), Oshape.channels); - var poolKernel = BestKernel( - ComputeKernelLibrary.PoolAvgVar2D(Xr, Or, poolKernelName)); - - instructions.Add(new CompiledInstruction { kernel = poolKernel, shape = Or }); - - Xr = Or; - Assert.IsTrue(Xr.length < lastLength); - } - - var meanVariance = new TensorShape(Xr.batch, 2, 1, Xr.channels); - var globalKernel = BestKernel( - ComputeKernelLibrary.GlobalPool2D(Xr, meanVariance, globalKernelName)); - instructions.Add(new CompiledInstruction { kernel = globalKernel, shape = meanVariance }); - - // ScaleBias - var S = l.datasets[0].shape; - var B = l.datasets[1].shape; - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - var normlizationKernel = BestKernel(ComputeKernelLibrary.NormalizationTail(X, O)); - instructions.Add(new CompiledInstruction { kernel = normlizationKernel, shape = O }); - - // FusedActivation - var fusedActivation = (Layer.FusedActivation) l.activation; - if (!IsFusedActivationSupported(fusedActivation)) - { - var activationKernel = BestKernel(ComputeKernelLibrary.Activation(X, O, fusedActivation.ToString())); - instructions.Add(new CompiledInstruction { kernel = activationKernel, shape = O }); - } - else - { - instructions.Add(new CompiledInstruction { shape = O }); - } - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - continue; - } - else if ( - l.type == Layer.Type.Add || - l.type == Layer.Type.Sub || - l.type == Layer.Type.Mul || - l.type == Layer.Type.Div || - l.type == Layer.Type.Pow || - l.type == Layer.Type.Min || - l.type == Layer.Type.Max || - l.type == Layer.Type.Mean - ) - { - if (X.Is4D() && O.Is4D()) - { - var kernelName = "Broadcast" + l.type; - kernel = BestKernel( - ComputeKernelLibrary.Broadcast(X, O, kernelName)); - } - } - else if ( - l.type == Layer.Type.Concat) - { - var instructions = new List(); - - foreach (var input in l.inputs) - { - var I = shapesByName[input]; - - if (I == null) - { - instructions.Add(new CompiledInstruction {}); - continue; - } - var kernelI = BestKernel(ComputeKernelLibrary.Copy(I.Value, O)); - - instructions.Add(new CompiledInstruction { kernel = kernelI, shape = I.Value }); - } - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - continue; - } - else if (l.type == Layer.Type.ReduceMax || - l.type == Layer.Type.ReduceMean || - l.type == Layer.Type.ReduceMin || - l.type == Layer.Type.ReduceProd || - l.type == Layer.Type.ReduceSum) - { - Layer.Type kernelName = l.type; - - int axis = l.axis; - axis = X.Axis(axis); - int baseReducedDim = X[axis]; - - int flatHeight, reducedDim, flatWidth; - int unrolledH, unrolledW; - - var instructions = new List(); - var Xr = X; - while (Xr[axis] > 64*4) - { - var lastLength = Xr.length; - - var Or = Xr; - Or[axis] = ComputeHelper.IDivC(ComputeHelper.IDivC(Xr[axis], 64), 4); - - ComputeReduceDispatchDim(Xr, Or, axis, out flatHeight, out reducedDim, out flatWidth); - - unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - var poolKernel = BestKernel(ComputeKernelLibrary.PartialReduce(kernelName, flatHeight, reducedDim, flatWidth)); - - instructions.Add(new CompiledInstruction { kernel = poolKernel, shape = Or }); - - Xr = Or; - Assert.IsTrue(Xr.length < lastLength); - } - - ComputeReduceDispatchDim(Xr, O, axis, out flatHeight, out reducedDim, out flatWidth); - - - unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - var globalKernel = BestKernel( - ComputeKernelLibrary.GlobalReduce(kernelName, flatHeight, reducedDim, flatWidth)); - - instructions.Add(new CompiledInstruction { kernel = globalKernel, shape = O }); - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = instructions.ToArray(), shape = O }); - - continue; - } - // Activations - else if (l.type == Layer.Type.Activation) - { - if (!X.Is4D()) - //8D activation are not supported on compute path atm, will fallback. - continue; - - // LogSoftmax/Softmax implemented with ReduceSum/Max: TODO pre-allocate shaders - if (l.activation == Layer.Activation.PRelu) - { - kernel = BestKernel( - ComputeKernelLibrary.PRelu(X, O)); - } - else if (l.activation != Layer.Activation.None) - { - try - { - var kernelName = l.activation.ToString(); - kernel = BestKernel( - ComputeKernelLibrary.Activation(X, O, kernelName)); - } - catch (System.ArgumentException) - { - //Not all activation are supported on compute path, some will fallback. - continue; - } - } - } - - m_CompiledLayers.Add(l, new CompiledLayer { instructions = new CompiledInstruction[] - { - new CompiledInstruction { kernel = kernel, shape = O } - }, shape = O }); - } - } - - /// - public virtual void PreExecuteLayer(Layer layer, Tensor[] inputs) - { - m_Compiled = new CompiledLayer(); - m_CompiledLayers.TryGetValue(layer, out m_Compiled); - } - - // --------------------------------------------------------------------------------- - private Tensor ApplyUnsupportedFusedActivationIfNeeded(Layer.FusedActivation fusedActivation, Tensor O) - { - if (!IsFusedActivationSupported(fusedActivation)) - { - CompiledInstruction instructionActivation = m_Compiled.instructions[m_Compiled.instructions.Length - 1]; - Assert.IsNotNull(instructionActivation.kernel.shader); - - var fnActivation = instructionActivation.kernel; - var Oactivation = NewOutputTensor(O.dataType, O.shape); - - fnActivation.SetTensor("X", O.shape, Pin(O).buffer); - fnActivation.SetTensor("O", Oactivation.shape, Pin(Oactivation, uploadCache: false).buffer); - - fnActivation.shader.SetFloat(_Alpha, 0.0f); - fnActivation.shader.SetFloat(_Beta, 0.0f); - - fnActivation.Dispatch(); - return Oactivation; - } - - return O; - } - - /// - public override Tensor Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - if (m_Compiled.kernel.shader == null) - return base.Dense(X, W, B, fusedActivation); - - Assert.IsTrue(W.dimensions <= 2); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(X.flatWidth, W.flatHeight); - - if (ShouldFlattenInputForDenseLayer(X.shape)) - { - Assert.IsNotNull(m_Compiled.instructions[1].kernel.shader); - var flattenedX = NewTempTensor(X.dataType, m_Compiled.instructions[1].shape); - var flattenFn = m_Compiled.instructions[1].kernel; - - flattenFn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - flattenFn.SetTensor(_DeclO, _DataO, flattenedX.shape, Pin(flattenedX, uploadCache: false).buffer); - flattenFn.Dispatch(); - - X = flattenedX; - } - - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewTensorForFusedActivation(X.dataType, m_Compiled.shape, fusedActivation); - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl(_DeclW, W.shape, Pin(W).offset); - fn.SetTensorDecl(_DeclB, B.shape, Pin(B).offset); - Assert.AreEqual(Pin(W).buffer, Pin(B).buffer); - fn.SetTensorBuffer(_DataWBK, Pin(W).buffer); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - return ApplyUnsupportedFusedActivationIfNeeded(fusedActivation, O); - } - - /// - public override Tensor Dense3(Tensor X, Tensor W, Tensor B) - { - if (m_Compiled.kernel.shader == null) - return base.Dense3(X, W, B); - - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewOutputTensor(X.dataType, m_Compiled.shape); - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl(_DeclW, W.shape, Pin(W).offset); - fn.SetTensorDecl(_DeclB, B.shape, Pin(B).offset); - Assert.AreEqual(Pin(W).buffer, Pin(B).buffer); - fn.SetTensorBuffer(_DataWBK, Pin(W).buffer); - - fn.Dispatch(); - - return O; - } - - /// - public override Tensor Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - if (m_Compiled.kernel.shader == null) - return base.Conv2D(X, K, B, stride, pad, fusedActivation); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewTensorForFusedActivation(X.dataType, m_Compiled.shape, fusedActivation); - - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - - if (m_Compiled.instructions[0].tensors?.Length == 2) - { - K = m_Compiled.instructions[0].tensors[0]; - B = m_Compiled.instructions[0].tensors[1]; - } - - fn.SetTensorDecl(_DeclK, K.shape, Pin(K).offset); - fn.SetTensorDecl(_DeclB, B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn.SetTensorBuffer(_DataWBK, Pin(K).buffer); - - fn.shader.SetInts(_Pad, pad); - fn.shader.SetInts(_Stride, stride); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - return ApplyUnsupportedFusedActivationIfNeeded(fusedActivation, O); - } - - /// - public override Tensor DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - if (K.kernelDepth != 1 || m_Compiled.kernel.shader == null) - return base.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(K.kernelDepth, 1); - Assert.AreEqual(K.kernelCount, X.channels); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewTensorForFusedActivation(X.dataType, m_Compiled.shape, fusedActivation); - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - - if (m_Compiled.instructions[0].tensors?.Length == 2) - { - K = m_Compiled.instructions[0].tensors[0]; - B = m_Compiled.instructions[0].tensors[1]; - } - - fn.SetTensorDecl(_DeclK, K.shape, Pin(K).offset); - fn.SetTensorDecl(_DeclB, B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn.SetTensorBuffer(_DataWBK, Pin(K).buffer); - - fn.shader.SetInts(_Pad, pad); - fn.shader.SetInts(_Stride, stride); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - return ApplyUnsupportedFusedActivationIfNeeded(fusedActivation, O); - } - - /// - public override Tensor Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - if (m_Compiled.instructions == null) - return base.Conv2DTrans(X, K, B, stride, pad, outputAdjustment, fusedActivation); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - - if (m_Compiled.instructions.Length >= 3) // pad, kernel flip, conv, ? fusedActivation - { - Assert.IsTrue(stride[0] * stride[1] <= 4); - // refer to BarracudaCompute.cs for details - // 0-pad X - CompiledInstruction instruction0PadX = m_Compiled.instructions[0]; - Assert.IsNotNull(instruction0PadX.kernel.shader); - - var XpaddedShape = instruction0PadX.shape; - var Xpadded = NewTempTensor(X.dataType, XpaddedShape); - var fn0PadX = instruction0PadX.kernel; - - fn0PadX.SetTensor("X", X.shape, Pin(X).buffer); - fn0PadX.SetTensor("O", Xpadded.shape, Pin(Xpadded, uploadCache: false).buffer); - fn0PadX.shader.SetInts("_Stride", stride); - fn0PadX.shader.SetInts("_Pad", outputAdjustment); - fn0PadX.Dispatch(); - - // kernel flip - CompiledInstruction instructionKernelFlip = m_Compiled.instructions[1]; - Assert.IsTrue(instructionKernelFlip.tensors.Length >= 2); - var Kflipped = instructionKernelFlip.tensors[0]; - var Bpacked = instructionKernelFlip.tensors[1]; - - // convolution - CompiledInstruction instructionConv = m_Compiled.instructions[2]; - Assert.IsNotNull(instructionConv.kernel.shader); - var fnConv = instructionConv.kernel; - - var padTrans = new int[] - { - K.kernelWidth - pad[0] - 1, K.kernelHeight - pad[1] - 1, - K.kernelWidth - pad[2] - 1, K.kernelHeight - pad[3] - 1 - }; - var strideTrans = new int[] { 1, 1 }; - - if (fnConv.shader == null) - { - return base.Conv2D(Xpadded, Kflipped, Bpacked, strideTrans, padTrans, fusedActivation); - } - - Assert.IsNotNull(fnConv.shader); - - var O = NewTensorForFusedActivation(X.dataType, instructionConv.shape, fusedActivation); - - fnConv.SetTensor("X", Xpadded.shape, Pin(Xpadded, uploadCache: false).buffer); - fnConv.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - - if (instructionConv.tensors?.Length == 2) - { - Kflipped = instructionConv.tensors[0]; - Bpacked = instructionConv.tensors[1]; - } - - fnConv.SetTensorDecl(_DeclK, Kflipped.shape, Pin(Kflipped).offset); - fnConv.SetTensorDecl(_DeclB, Bpacked.shape, Pin(Bpacked).offset); - Assert.AreEqual(Pin(Kflipped).buffer, Pin(Bpacked).buffer); - fnConv.SetTensorBuffer(_DataWBK, Pin(Kflipped).buffer); - - fnConv.shader.SetInt("_ActivationMode", (int)fusedActivation); - fnConv.shader.SetInts(_Pad, padTrans); - fnConv.shader.SetInts(_Stride, strideTrans); - - fnConv.Dispatch(); - - Xpadded.Dispose(); - - return ApplyUnsupportedFusedActivationIfNeeded(fusedActivation, O); - } - else - { - Assert.IsTrue(stride[0] * stride[1] > 4); - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewTensorForFusedActivation(X.dataType, m_Compiled.shape, fusedActivation); - var fn = m_Compiled.kernel; - - var padTrans = new int[] - { - K.kernelWidth - pad[0] - 1, K.kernelHeight - pad[1] - 1, - K.kernelWidth - pad[2] - 1, K.kernelHeight - pad[3] - 1 - }; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - - fn.SetTensorDecl(_DeclK, K.shape, Pin(K).offset); - fn.SetTensorDecl(_DeclB, B.shape, Pin(B).offset); - Assert.AreEqual(Pin(K).buffer, Pin(B).buffer); - fn.SetTensorBuffer(_DataWBK, Pin(K).buffer); - - fn.shader.SetInts(_Pad, padTrans); - fn.shader.SetInts(_Stride, stride); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fn.Dispatch(); - - return ApplyUnsupportedFusedActivationIfNeeded(fusedActivation, O); - } - } - - /// - public override Tensor Upsample2D(Tensor X, int[] scale, bool bilinear) - { - if (m_Compiled.kernel.shader == null) - return base.Upsample2D(X, scale, bilinear); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(scale.Length, 2); - - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewOutputTensor(X.dataType, m_Compiled.shape); - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts(_Pool, scale); - - fn.Dispatch(); - return O; - } - - /// - protected override Tensor Pool2D(string kernelName, Tensor X, int[] pool, int[] stride, int[] pad) - { - if (m_Compiled.kernel.shader == null) - return base.Pool2D(kernelName, X, pool, stride, pad); - - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewOutputTensor(X.dataType, m_Compiled.shape); - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts(_Pool, pool); - fn.shader.SetInts(_Stride, stride); - fn.shader.SetInts(_Pad, pad); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor ScaleBias(Tensor X, Tensor S, Tensor B) - { - if (m_Compiled.kernel.shader == null || !X.shape.Is4D()) - return base.ScaleBias(X, S, B); - - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewOutputTensor(X.dataType, m_Compiled.shape); - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensorDecl(_DeclW, S.shape, Pin(S).offset); - fn.SetTensorDecl(_DeclB, B.shape, Pin(B).offset); - Assert.AreEqual(Pin(S).buffer, Pin(B).buffer); - fn.SetTensorBuffer(_DataWBK, Pin(S).buffer); - - fn.Dispatch(); - return O; - } - - - private Tensor GlobalPool2D(Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - s_GlobalPool2DInputDim[0] = X.height; - s_GlobalPool2DInputDim[1] = X.width; - for (var i = 0; i < m_Compiled.instructions.Length-1; ++i) - { - var pool = new[] { 8, 8 }; - var stride = pool; - var pad = new[] { 0, 0, 0, 0 }; - - CompiledInstruction instructionPool = m_Compiled.instructions[i]; - Assert.IsNotNull(instructionPool.kernel.shader); - - var Or = NewTempTensor(X.dataType, instructionPool.shape); - var fnPool = instructionPool.kernel; - - fnPool.SetTensor("X", X.shape, Pin(X).buffer); - fnPool.SetTensor("O", Or.shape, Pin(Or, uploadCache: false).buffer); - - fnPool.shader.SetInts("_Pool", pool); - fnPool.shader.SetInts("_Stride", stride); - fnPool.shader.SetInts("_Pad", pad); - - fnPool.Dispatch(); - X = Or; - } - - CompiledInstruction instructionGlobalPool = m_Compiled.instructions[m_Compiled.instructions.Length - 1]; - Assert.IsNotNull(instructionGlobalPool.kernel.shader); - - var O = NewOutputTensor(X.dataType, instructionGlobalPool.shape); - var fnGlobalPool = instructionGlobalPool.kernel; - - fnGlobalPool.SetTensor("X", X.shape, Pin(X).buffer); - fnGlobalPool.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fnGlobalPool.shader.SetInts("_Pool", s_GlobalPool2DInputDim); - - fnGlobalPool.Dispatch(); - return O; - } - - /// - public override Tensor GlobalMaxPool2D(Tensor X) - { - if (m_Compiled.instructions == null) - return base.GlobalMaxPool2D(X); - - return GlobalPool2D(X); - } - - /// - public override Tensor GlobalAvgPool2D(Tensor X) - { - if (m_Compiled.instructions == null) - return base.GlobalAvgPool2D(X); - - return GlobalPool2D(X); - } - - /// - public override Tensor Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) - { - if (!X.shape.Is4D()) - throw new NotImplementedException(); - - if (axis != TensorShape.C && axis != -1) - throw new NotImplementedException(); - - if (pool <= 0) - pool = X.batch; - - if (pool > 1) - throw new NotImplementedException(); // @TODO: support other types of Normalization at test time - // Currently supported only pool=1 (InstanceNormalization) - - // [0,N] : AvgVariancePool2DReduce - // N+1 : GlobalAvgVariancePool2D - // N+2: Normalize - // N+3 Activation - - var inputDim = new[] { X.height, X.width }; - - var Xr = X; - var X2r = X; - bool isFirstDispatch = true; - for (var i = 0; i < m_Compiled.instructions.Length - 3; ++i) - { - var poolReduce = new[] { 8, 8 }; - var stride = poolReduce; - var pad = new[] { 0, 0, 0, 0 }; - - CompiledInstruction instructionPool = m_Compiled.instructions[i]; - Assert.IsNotNull(instructionPool.kernel.shader); - - var Or = NewTempTensor(X.dataType, instructionPool.shape); - var O2r = NewTempTensor(X.dataType, instructionPool.shape); - var fnPool = instructionPool.kernel; - - fnPool.SetTensor("X", Xr.shape, Pin(Xr).buffer); - fnPool.SetTensor("X2", X2r.shape, Pin(X2r).buffer); - fnPool.SetTensor("O", Or.shape, Pin(Or, uploadCache: false).buffer); - fnPool.SetTensor("O2", O2r.shape, Pin(O2r, uploadCache: false).buffer); - - fnPool.shader.SetInts("_Pool", poolReduce); - fnPool.shader.SetInts("_Stride", stride); - fnPool.shader.SetInts("_Pad", pad); - fnPool.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - fnPool.Dispatch(); - - Xr = Or; - X2r = O2r; - isFirstDispatch = false; - } - - CompiledInstruction instructionGlobalPool = m_Compiled.instructions[m_Compiled.instructions.Length - 3]; - Assert.IsNotNull(instructionGlobalPool.kernel.shader); - - var meanVariance = NewTempTensor(X.dataType, instructionGlobalPool.shape); - var fnGlobalPool = instructionGlobalPool.kernel; - - fnGlobalPool.SetTensor("X", Xr.shape, Pin(Xr).buffer); - fnGlobalPool.SetTensor("X2", X2r.shape, Pin(X2r).buffer); - fnGlobalPool.SetTensor("O", meanVariance.shape, Pin(meanVariance, uploadCache: false).buffer); - fnGlobalPool.shader.SetInts("_Pool", inputDim); - fnGlobalPool.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - fnGlobalPool.Dispatch(); - - CompiledInstruction instructionNormalize = m_Compiled.instructions[m_Compiled.instructions.Length - 2]; - Assert.IsNotNull(instructionNormalize.kernel.shader); - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - - var O = NewTensorForFusedActivation(X.dataType, X.shape, fusedActivation); - var fnNormalize = instructionNormalize.kernel; - fnNormalize.SetTensor("X", X.shape, Pin(X).buffer); - fnNormalize.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fnNormalize.SetTensor("W", meanVariance.shape, Pin(meanVariance, uploadCache: false).buffer); - fnNormalize.SetTensorDecl("S", S.shape, Pin(S).offset); - fnNormalize.SetTensorDecl("B", B.shape, Pin(B).offset); - Assert.AreEqual(Pin(S).buffer, Pin(B).buffer); - fnNormalize.SetTensorBuffer("WBK", Pin(S).buffer); - fnNormalize.shader.SetFloat("_Epsilon", epsilon); - fnNormalize.shader.SetInt("_ActivationMode", (int)fusedActivation); - - fnNormalize.Dispatch(); - - return ApplyUnsupportedFusedActivationIfNeeded(fusedActivation, O); - } - - protected override Tensor ReduceHelper(Layer.Type kernelName, Tensor X, int axis, AllocScope outputScope) - { - if (m_Compiled.instructions == null) - return base.ReduceHelper(kernelName, X, axis, outputScope); - - axis = X.shape.Axis(axis); - int baseReducedDim = X.shape[axis]; - - int flatHeight, reducedDim, flatWidth; - int unrolledH, unrolledW; - - for (var i = 0; i < m_Compiled.instructions.Length-1; ++i) - { - CompiledInstruction instructionPool = m_Compiled.instructions[i]; - Assert.IsNotNull(instructionPool.kernel.shader); - - ComputeReduceDispatchDim(X.shape, instructionPool.shape, axis, out flatHeight, out reducedDim, out flatWidth); - - s_PartialReduceSumDimensions[0] = flatHeight; - s_PartialReduceSumDimensions[1] = flatWidth; - s_PartialReduceSumDimensions[2] = reducedDim; - - unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - var Or = NewTempTensor(X.dataType, instructionPool.shape); - var fnPool = instructionPool.kernel; - - fnPool.SetTensor("X", X.shape, Pin(X).buffer); - fnPool.SetTensor("O", Or.shape, Pin(Or, uploadCache: false).buffer); - fnPool.shader.SetInt("_UnrolledH", unrolledH); - fnPool.shader.SetInt("_UnrolledW", unrolledW); - fnPool.shader.SetInt("_ReducedDim", instructionPool.shape[axis]); - fnPool.shader.SetInts("_Pool", s_PartialReduceSumDimensions); - - fnPool.Dispatch(); - X = Or; - } - - CompiledInstruction instructionGlobalPool = m_Compiled.instructions[m_Compiled.instructions.Length - 1]; - Assert.IsNotNull(instructionGlobalPool.kernel.shader); - - ComputeReduceDispatchDim(X.shape, instructionGlobalPool.shape, axis, out flatHeight, out reducedDim, out flatWidth); - - - s_GlobalReduceSumDimensions[0] = flatHeight; - s_GlobalReduceSumDimensions[1] = flatWidth; - s_GlobalReduceSumDimensions[2] = baseReducedDim; - - - unrolledH = flatHeight / ((int)ComputeFunc.SafeDispatchLimit) + 1; - unrolledW = flatWidth / ((int)ComputeFunc.SafeDispatchLimit) + 1; - - var O = NewTensor(X.dataType, instructionGlobalPool.shape, outputScope); - var fnGlobalPool = instructionGlobalPool.kernel; - - fnGlobalPool.SetTensor("X", X.shape, Pin(X).buffer); - fnGlobalPool.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - fnGlobalPool.shader.SetInt("_UnrolledH", unrolledH); - fnGlobalPool.shader.SetInt("_UnrolledW", unrolledW); - fnGlobalPool.shader.SetInt("_ReducedDim", reducedDim); - fnGlobalPool.shader.SetInts("_Pool", s_GlobalReduceSumDimensions); - - fnGlobalPool.Dispatch(); - return O; - } - - - /// - protected override Tensor Activation(string kernelName, Tensor X, float alpha = 0f, float beta = 0f) - { - if (m_Compiled.kernel.shader == null) - return base.Activation(kernelName, X, alpha, beta); - - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewOutputTensor(X.dataType, m_Compiled.shape); - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetFloat(_Alpha, alpha); - fn.shader.SetFloat(_Beta, beta); - - fn.Dispatch(); - return O; - } - - /// - public override Tensor PRelu(Tensor X, Tensor S) - { - if (m_Compiled.kernel.shader == null) - return base.PRelu(X, S); - - Assert.IsTrue((X.flatWidth == S.flatWidth) || (S.flatWidth == 1)); - - Assert.IsNotNull(m_Compiled.kernel.shader); - var O = NewOutputTensor(X.dataType, m_Compiled.shape); - var fn = m_Compiled.kernel; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensor(_DeclW, _DataW, S.shape, Pin(S).buffer); - - fn.Dispatch(); - return O; - } - - /// - protected override Tensor ElementwiseWithBroadcast(string kernelName, Tensor[] tensors) - { - if (m_Compiled.kernel.shader == null) - return base.ElementwiseWithBroadcast(kernelName, tensors); - - Assert.IsNotNull(m_Compiled.kernel.shader); - var fn = m_Compiled.kernel; - - Assert.IsTrue(tensors.Length > 0); - var X = tensors[0]; - - Tensor outputTensor = NewOutputTensor(X.dataType, TensorExtensions.MaxShape(tensors)); - Tensor tempTensor = null; - if (tensors.Length > 2) - { - tempTensor = NewTempTensor(X.dataType, TensorExtensions.MaxShape(tensors)); - } - Tensor outputTensorOddIndex = (tensors.Length % 2 == 0) ? outputTensor : tempTensor; - Tensor outputTensorEvenIndex = (tensors.Length % 2 == 0) ? tempTensor : outputTensor; - - Tensor O = null; - bool isFirstDispatch = true; - for (int t = 1; t < tensors.Length; ++t) - { - var B = tensors[t]; - O = (t % 2 == 1) ? outputTensorOddIndex : outputTensorEvenIndex; - - fn.SetTensor(_DeclX, _DataX, X.shape, Pin(X).buffer); - fn.SetTensor(_DeclO, _DataO, O.shape, Pin(O, uploadCache: false).buffer); - fn.SetTensor(_DeclB, _DataB, B.shape, Pin(B).buffer, Pin(B).offset); - fn.shader.SetFloat("_Alpha", 1.0f/(float)tensors.Length); - fn.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - fn.shader.SetInts("_XStrides", GetInputTensorStridesOnDevice(X.shape, Pin(X).channelsOrder, s_XStrides)); - fn.shader.SetInts("_BStrides", GetInputTensorStridesOnDevice(B.shape, Pin(B).channelsOrder, s_BStrides)); - - fn.Dispatch(); - - X = O; - isFirstDispatch = false; - } - - tempTensor?.Dispose(); - Assert.AreEqual(outputTensor, O); - return O; - } - - /// - public override Tensor Concat(Tensor[] tensors, int axis) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || !TensorExtensions.Is8DAxisConvertibleTo4D(axis)) - return base.Concat(tensors, axis); - - if (m_Compiled.instructions == null) - return base.Concat(tensors, axis); - - bool canUsePrecompiledBackend = true; - foreach (var i in m_Compiled.instructions) - { - canUsePrecompiledBackend &= (i.kernel.shader != null); - } - foreach (var inputTensor in tensors) - { - //input tensor is not in current memory layout, we need an extra transpose/dispatch - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW && Pin(inputTensor).channelsOrder == ComputeInfo.ChannelsOrder.NHWC) - canUsePrecompiledBackend = false; - } - if (!canUsePrecompiledBackend) - return base.Concat(tensors, axis); - - var dataType = tensors.Length > 0 ? tensors[0].dataType : DataType.Float; - var O = NewOutputTensor(dataType, m_Compiled.shape); - - var offsets = s_ConcatOffsets; - Array.Clear(offsets, 0, offsets.Length); - axis = O.shape.Axis(axis); - var axisNCHW = TensorExtensions.Convert8DAxisTo4D(axis); - - Assert.AreEqual(tensors.Length, m_Compiled.instructions.Length); - for (int i = 0; i < tensors.Length; ++i) - { - var X = tensors[i]; - var instruction = m_Compiled.instructions[i]; - var fn = instruction.kernel; - - fn.SetTensor("X", X.shape, Pin(X).buffer); - fn.SetTensor("O", O.shape, Pin(O, uploadCache: false).buffer); - - fn.shader.SetInts("_Pad", offsets); - - fn.Dispatch(); - - offsets[axisNCHW] += X.shape[axis]; - } - - return O; - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPrecompiledCompute.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPrecompiledCompute.cs.meta deleted file mode 100644 index a876162..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaPrecompiledCompute.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5fea18c74a3be4c7680b4ee28cbe1a86 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCPU.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCPU.cs deleted file mode 100644 index 997abb5..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCPU.cs +++ /dev/null @@ -1,3833 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using Unity.Collections.LowLevel.Unsafe; -using UnityEngine; -using UnityEngine.Assertions; -using Random = UnityEngine.Random; - -namespace Unity.Barracuda { - -/// -/// Internal `Tensor` data backed by managed array -/// -public class ArrayTensorData : UniqueResourceId, ITensorData -{ - internal BarracudaArray m_Array; - - /// - /// Data storage array - /// - public BarracudaArray array { get { return m_Array; } } - - /// - /// Create `ArrayTensorData` and allocate storage for `count` elements - /// - /// number of elements to pre-allocate - public ArrayTensorData(int count, DataType dataType = DataType.Float) - { - m_Array = new BarracudaArray(count, dataType); - } - - /// - /// Create `ArrayTensorData` and allocate storage for `Tensor` described by `shape` - /// - /// shape - public ArrayTensorData(TensorShape shape, DataType dataType = DataType.Float) : this(shape.length, dataType) - { - } - - /// - /// Finalizer - /// - ~ArrayTensorData() - { - Dispose(); - } - - /// - /// Dispose storage - /// - public virtual void Dispose() - { - m_Array = null; - } - - /// - public virtual void Reserve(int count) - { - if (count > m_Array.Length) - m_Array = new BarracudaArray(count, m_Array.Type); - } - - /// - public virtual void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0) - { - var numItemToCopy = shape.length; - var numItemAvailableInData = data.Length - managedBufferStartIndex; - - Assert.IsTrue(managedBufferStartIndex >= 0); - Assert.IsTrue(numItemToCopy <= numItemAvailableInData); - - Reserve(numItemToCopy); - BarracudaArray.Copy(data, managedBufferStartIndex, m_Array, 0, numItemToCopy); - } - - /// - public virtual bool ScheduleAsyncDownload(int count) - { - return true; - } - - /// - public virtual float[] Download(TensorShape shape) - { - //;;D.logStackTraceEnabled = true; - //;;D.Log("Download ArrayTensorData " + count + " from " + m_Array.Length + " @ " + ToString()); - //;;D.logStackTraceEnabled = false; - - var count = shape.length; - Assert.IsTrue(m_Array.Length >= count); - - var dest = new float[count]; - BarracudaArray.Copy(m_Array, 0, dest, 0, count); - return dest; - } - - /// - public virtual BarracudaArray SharedAccess(out int offset) - { - offset = 0; - return m_Array; - } - - /// - public virtual int maxCapacity { get - { - return m_Array.Length; - } } - - /// - public virtual DataType dataType { get - { - return m_Array.Type; - } } - - /// - public virtual bool inUse { get - { - return true; - } } - - /// - public virtual bool isGPUMem { get - { - return false; - } } - - /// - /// Storage summary as string - /// - /// storage summary as string - public override string ToString() - { - return string.Format("(CPU array: {0} max: {1})", - GetHashCode(), m_Array?.Length); - } -} - -/// -/// Base class to track unique resource by an id. -/// -public class UniqueResourceId: IUniqueResource -{ - class UniqueResourceHelper { - public int lastIdRequested; - } - static UniqueResourceHelper SpinLock = new UniqueResourceHelper(); - - /// - public int uniqueId { get; internal set; } - - public UniqueResourceId() - { - uniqueId = GetUniqueId(); - } - - public static int GetUniqueId() - { - lock(SpinLock) - { - return SpinLock.lastIdRequested++; - } - } -} - -/// -/// Internal `Tensor` data backed by managed array that is shared between multiple tensors -/// -public class SharedArrayTensorData : UniqueResourceId, ITensorData -{ - internal BarracudaArray m_Array; - internal int m_Offset; - internal int m_Count; - - /// - /// Data storage array - /// - public BarracudaArray array { get { return m_Array; } } - - /// - /// Offset in storage array - /// - public int offset { get { return m_Offset; } } - - /// - /// Data element count - /// - public int count { get { return m_Count; } } - - /// - /// Create `SharedArrayTensorData` with supplied shared `data` - /// - /// shared array - public SharedArrayTensorData(float[] data) : this(new BarracudaArrayFromManagedArray(data), 0, data.Length) - { - } - - /// - /// Create `SharedArrayTensorData` with supplied shared `data` - /// - /// shared array - public SharedArrayTensorData(BarracudaArray data) : this(data, 0, data.Length) - { - } - - internal SharedArrayTensorData(BarracudaArray data, TensorShape shape, int offset) : this(data, offset, shape.length) - { - } - - internal SharedArrayTensorData(float[] data, int offset, int count) : this(new BarracudaArrayFromManagedArray(data), offset, count) - { - } - - internal SharedArrayTensorData(BarracudaArray data, int offset, int count) - { - Assert.IsTrue(offset >= 0); - m_Array = data; - m_Offset = offset; - Assert.IsTrue(count >= 0); - Assert.IsTrue(offset + count <= m_Array.Length); - m_Count = count; - } - - /// - /// Finalize - /// - ~SharedArrayTensorData() - { - Dispose(); - } - - /// - /// Dispose storage - /// - public virtual void Dispose() - { - } - - /// - public virtual void Reserve(int count) - { - // currently always readonly - throw new InvalidOperationException("SharedArrayTensorData is readonly!"); - } - - /// - public virtual void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0) - { - // currently always readonly - throw new InvalidOperationException("SharedArrayTensorData is readonly!"); - } - - /// - public virtual bool ScheduleAsyncDownload(int count) - { - return true; - } - - /// - public virtual float[] Download(TensorShape shape) - { - //;;D.logStackTraceEnabled = true; - //;;D.Log("Download SharedArrayTensorData " + count + " from " + m_Count + " @ " + ToString()); - //;;D.logStackTraceEnabled = false; - - var count = shape.length; - Assert.IsTrue(m_Count >= count); - - var dest = new float[count]; - BarracudaArray.Copy(m_Array, m_Offset, dest, 0, count); - return dest; - } - - /// - public virtual BarracudaArray SharedAccess(out int offset) - { - offset = m_Offset; - return m_Array; - } - - /// - public virtual int maxCapacity { get - { - return m_Count; - } } - - /// - public virtual DataType dataType { get - { - return m_Array.Type; - } } - - /// - public virtual bool inUse { get - { - return true; - } } - - /// - public virtual bool isGPUMem { get - { - return false; - } } - - - /// - /// Storage summary as string - /// - /// storage summary as string - public override string ToString() - { - return string.Format("(CPU shared: {0} max: {1} offset: {2} count: {3})", - GetHashCode(), m_Array.Length, m_Offset, m_Count); - } -} - -/// -/// Reference CPU implementation of `IOps` -/// -public class ReferenceCPUOps : IOps -{ - private IModelExecutionsReporter m_ModelExecutionsReporter; - private ITensorAllocator m_Allocator; - private StringCache m_StringCache = new StringCache(); - - /// - public virtual void PostLayerCleanup() - { - m_Allocator.PostLayerCleanup(); - } - - /// - /// Create `ReferenceCPUOps` - /// - /// allocator - public ReferenceCPUOps(ITensorAllocator allocator = null) - { - if (allocator == null) - allocator = new TensorCachingAllocator(); - m_Allocator = allocator; - } - - #region Tensor creation helpers (for reference implementation only) - /// - /// Allocate new `Tensor` via allocator using LayerOutput allocation scope. - /// Should only be used on reference backend, production backends should use explicit - /// allocation scope for better peak mem usage. - /// - /// data type - /// shape - /// tensor lifetime scope - /// name - /// new `Tensor` - private Tensor NewTensor(DataType dataType, TensorShape s) - { - return NewTensor(dataType, s, AllocScope.LayerOutput); - } - - /// - /// Allocate new `Tensor` via allocator using LayerOutput allocation scope. - /// Should only be used on reference backend, production backends should use explicit - /// allocation scope for better peak mem usage. - /// - /// `Tensor` - /// new `Tensor` - private Tensor NewTensorLike(Tensor t) - { - return NewTensorLike(t, AllocScope.LayerOutput); - } - - /// - /// Allocate new `Tensor` via allocator using LayerOutput allocation scope. - /// Should only be used on reference backend, production backends should use explicit - /// allocation scope for better peak mem usage. - /// - /// data type - /// batch - /// channels - /// name - /// new `Tensor` - private Tensor NewTensor(DataType dataType, int b, int ch, string name = "") - { - return NewTensor(dataType, new TensorShape(b, ch), AllocScope.LayerOutput, name); - } - - /// - /// Allocate new `Tensor` via allocator using LayerOutput allocation scope. - /// Should only be used on reference backend, production backends should use explicit - /// allocation scope for better peak mem usage. - /// - /// data type - /// batch - /// height - /// width - /// channels - /// name - /// new `Tensor` - private Tensor NewTensor(DataType dataType, int b, int h, int w, int ch, string name = "") - { - return NewTensor(dataType, new TensorShape(b, h, w, ch), AllocScope.LayerOutput, name); - } - - #endregion - - /// - /// Allocate new `Tensor` via allocator - /// - /// data type - /// shape - /// tensor lifetime scope - /// name - /// new `Tensor` - protected Tensor NewTensor(DataType dataType, TensorShape s, AllocScope scope, string name = "") - { - if (name == "") - name = (scope == AllocScope.LayerOutput ? "LayerOutput" : "InternalToLayer"); - - var tensor = m_Allocator.Alloc(s, scope, dataType); - tensor.name = name; - - return tensor; - } - - /// - /// Allocate new `Tensor` similar to specified `Tensor` `t` - /// - /// `Tensor` - /// tensor lifetime scope - /// new `Tensor` - protected Tensor NewTensorLike(Tensor t, AllocScope scope) - { - return NewTensor(t.dataType, t.shape, scope); - } - - /// - /// Allocate new `Tensor` corresponding to max shape of specified `tensors` - /// - /// tensors - /// tensor lifetime scope - /// should this method validate that all tensors are the same type - /// new `Tensor` - protected Tensor NewTensorLike(Tensor[] tensors, AllocScope scope, bool validateType = true) - { - Assert.IsTrue(tensors.Length > 0); - - var O = NewTensor(tensors[0].dataType, TensorExtensions.MaxShape(tensors), scope); - foreach (var t in tensors) - { - if (validateType) - Assert.AreEqual(O.dataType, t.dataType); - for (int i = 0; i < TensorShape.MaxRank; ++i) - { - Assert.IsTrue((t.shape[i] == 1) || (t.shape[i] == O.shape[i])); - } - } - - return O; - } - - /// - /// Check if `fusedActivation` is supported in-place - /// - /// fused activation type - /// `true` if supported in-place - protected virtual bool IsFusedActivationSupported(Layer.FusedActivation fusedActivation) - { - switch (fusedActivation) - { - case Layer.FusedActivation.None: - return true; - default: - return false; - } - } - - /// - /// Allocate new `Tensor` via allocator - /// tensor lifetime will be OutputLayer if activation is supported in place, InternalToLayer otherwise. - /// - /// data type - /// shape of the tensor to be created - /// fused activation type - /// new `Tensor` - protected Tensor NewTensorForFusedActivation(DataType dataType, TensorShape shape, Layer.FusedActivation fusedActivation) - { - if (IsFusedActivationSupported(fusedActivation)) - return NewOutputTensor(dataType, shape); - else - return NewTempTensor(dataType, shape); - } - - /// - /// Allocate new `Tensor` via allocator using AllocScope.LayerOutput scope - /// - /// data type - /// shape of the tensor to be created - /// tensor name - /// new `Tensor` - protected Tensor NewOutputTensor(DataType type, TensorShape s, string name = "") - { - return NewTensor(type, s, AllocScope.LayerOutput, name); - } - - /// - /// Allocate new `Tensor` via allocator using AllocScope.InternalToLayer scope - /// - /// data type - /// shape of the tensor to be created - /// tensor name - /// new `Tensor` - protected Tensor NewTempTensor(DataType type, TensorShape s, string name = "") - { - return NewTensor(type, s, AllocScope.InternalToLayer, name); - } - -#if ENABLE_BARRACUDA_STATS - /// - public virtual IEnumerable GetTempMemoryStatistics() - { - return Enumerable.Empty(); - } -#endif //ENABLE_BARRACUDA_STATS - - /// - public virtual void ResetAllocator(bool keepCachedMemory = true) - { - m_Allocator.Reset(keepCachedMemory); - } - - /// - public void SetModelExecutionsReporter(IModelExecutionsReporter executionsReporter) - { - m_ModelExecutionsReporter = executionsReporter; - } - - /// - public IModelExecutionsReporter GetModelExecutionsReporter() - { - return m_ModelExecutionsReporter; - } - - private float ApplyFusedActivation(float v, Layer.FusedActivation fusedActivation) - { - switch (fusedActivation) - { - case Layer.FusedActivation.None: - break; - case Layer.FusedActivation.Relu: - v = Mathf.Max(v, 0.0f); - break; - case Layer.FusedActivation.Tanh: - v = MathfEx.Tanh(v); - break; - case Layer.FusedActivation.Softplus: - v = Mathf.Log(Mathf.Exp(v) + 1f); - break; - case Layer.FusedActivation.Sigmoid: - v = 1f / (1f + Mathf.Exp(-v)); - break; - case Layer.FusedActivation.Relu6: - v = Mathf.Min(Mathf.Max(0f, v), 6f); - break; - case Layer.FusedActivation.Swish: - v = v / (1f + Mathf.Exp(-v)); - break; - case Layer.FusedActivation.Neg: - v = -v; - break; - case Layer.FusedActivation.Sqrt: - v = Mathf.Sqrt(v); - break; - case Layer.FusedActivation.Exp: - v = Mathf.Exp(v); - break; - case Layer.FusedActivation.Log: - v = Mathf.Log(v); - break; - case Layer.FusedActivation.Acos: - v = Mathf.Acos(v); - break; - case Layer.FusedActivation.Acosh: - v = Mathf.Log(v + Mathf.Sqrt(v * v - 1.0f)); - break; - case Layer.FusedActivation.Asin: - v = Mathf.Asin(v); - break; - case Layer.FusedActivation.Asinh: - v = Mathf.Log(v + Mathf.Sqrt(v * v + 1.0f)); - break; - case Layer.FusedActivation.Atan: - v = Mathf.Atan(v); - break; - case Layer.FusedActivation.Atanh: - v = 0.5f * Mathf.Log((1.0f + v) / (1.0f - v)); - break; - case Layer.FusedActivation.Cos: - v = Mathf.Cos(v); - break; - case Layer.FusedActivation.Cosh: - v = 0.5f * (Mathf.Exp(v) + Mathf.Exp(-v)); - break; - case Layer.FusedActivation.Sin: - v = Mathf.Sin(v); - break; - case Layer.FusedActivation.Sinh: - v = 0.5f * (Mathf.Exp(v) - Mathf.Exp(-v)); - break; - case Layer.FusedActivation.Tan: - v = Mathf.Tan(v); - break; - case Layer.FusedActivation.Erf: - { - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x = Mathf.Abs(v); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t = 1 / (1 + p * x); - float t2 = t * t; - float t3 = t2 * t; - float t4 = t3 * t; - float t5 = t4 * t; - - v = Mathf.Sign(v)*(1 - (a1*t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5)*Mathf.Exp(-x * x)); - break; - } - default: - throw new NotImplementedException(); - } - return v; - } - - /// - public virtual Tensor Dense3(Tensor X, Tensor W, Tensor B) - { - return Add(new[] { MatMul(X, 3, W, 2), Reshape(B, new TensorShape(1, 1, B.length, 1)) }); - } - - // --------------------------------------------------------------------------------- - /// - public virtual Tensor MatMul(Tensor X, int rankX, Tensor Y, int rankY) - { - // Barracuda Tensor layout is not broadcast friendly: - // rank4: NHWC - // rank3: N_WC - // rank2: N__C - // rank1: N___ - // on top of things, ONNX does not transpose layout like it does for conv. - // => so to get broadcast correctly we need to convert our Barracuda Tensor to an ONNX-broadcastable layout - // rank4: NCHW - // rank3: _NCW - // rank2: __NC - // rank1: ___N - // and then perform the broadcast MatMul - // the input tensor ranks are computed at import time and stored in the layer (TODO: keep track of it in the Tensor itself) - - // support for legacy case where rank needs to be inferred at runtime - if (rankX < 0 || rankY < 0) - ModelAnalyzer.LegacyGetXYRanks(X.shape, Y.shape, out rankX, out rankY); - - var onnxXshape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToOnnxLayout(X.shape, rankX); - var onnxYshape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToOnnxLayout(Y.shape, rankY); - - int rankO = Math.Max(rankX, rankY); - - if (rankO <= 2) - return MatMul(X, false, Y, false); - - // pad 1 on front of shape to both be rankO shape - for (int i = rankX; i < rankO; i++) - onnxXshape.Insert(0, 1); - - for (int i = rankY; i < rankO; i++) - onnxYshape.Insert(0, 1); - - // Max values for X, Y from ONNX shape (needed for modulo later) - int xN = 1; - int yN = 1; - int xC = 1; - int yC = 1; - - int matN = 1; - int matC = 1; - int matH = 1; - int matW = 1; - Tensor O; - if (rankO == 3) - { - xC = onnxXshape[0]; - yC = onnxYshape[0]; - matC = Math.Max(xC, yC); - matH = onnxXshape[1]; - matW = onnxYshape[2]; - O = NewTensor(X.dataType, new TensorShape(matC, 1, matW, matH)); - } - else - { - xN = onnxXshape[0]; - yN = onnxYshape[0]; - - xC = onnxXshape[1]; - yC = onnxYshape[1]; - - matN = Math.Max(xN, yN); - matC = Math.Max(xC, yC); - matH = onnxXshape[2]; - matW = onnxYshape[3]; - O = NewTensor(X.dataType, new TensorShape(matN, matH, matW, matC)); - } - - var Xt = Transpose(X, new[] { 0, 3, 1, 2 }); - var Yt = Transpose(Y, new[] { 0, 3, 1, 2 }); - if(rankX == 2) - Xt = Reshape(Xt, new TensorShape(1, 1, Xt.batch, Xt.height)); - else if (rankX == 3) - Xt = Reshape(Xt, new TensorShape(1, Xt.batch, Xt.height, Xt.channels)); - if (rankY == 2) - Yt = Reshape(Yt, new TensorShape(1, 1, Yt.batch, Yt.height)); - else if (rankY == 3) - Yt = Reshape(Yt, new TensorShape(1, Yt.batch, Yt.height, Yt.channels)); - - var startsX = new[] { 0, 0, 0, 0 }; - var startsY = new[] { 0, 0, 0, 0 }; - - var endsX = new[] { 1, 1, Xt.width, Xt.channels}; - var endsY = new[] { 1, 1, Yt.width, Yt.channels}; - var strides = new[] { 1, 1, 1, 1 }; - - for (int b = 0; b < matN; b++) - { - Tensor Ob = NewTensorLike(O); - - if (rankX == 4) - { - startsX[0] = b % xN; - endsX[0] = b % xN + 1; - } - if (rankY == 4) - { - startsY[0] = b % yN; - endsY[0] = b % yN + 1; - } - - for (int c = 0; c < matC; c++) - { - if (rankX >= 3) - { - startsX[1] = c % xC; - endsX[1] = c % xC + 1; - } - if (rankY >= 3) - { - startsY[1] = c % yC; - endsY[1] = c % yC + 1; - } - - // __NC -> N__C - Tensor Xs = StridedSlice(Xt, startsX, endsX, strides); Xs = Reshape(Xs, new TensorShape(Xt.width, Xt.channels)); - Tensor Ys = StridedSlice(Yt, startsY, endsY, strides); Ys = Reshape(Ys, new TensorShape(Yt.width, Yt.channels)); - Tensor Oc = MatMul(Xs, false, Ys, false); - if(rankO == 2) - { - Ob = Oc; - } - if (rankO == 3) - { - Oc = Transpose(Oc, new[] { 1, 2, 3, 0 }); // N__C -> _1,C,N - if (c == 0) - Ob = Oc; - else - Ob = Concat(new[] { Ob, Oc }, TensorShape.DataBatch); - } - else if (rankO == 4) - { - Oc = Reshape(Oc, new TensorShape(1, Oc.batch, Oc.channels, 1)); // N__C -> _,N,C,_ - if (c == 0) - Ob = Oc; - else - Ob = Concat(new[] { Ob, Oc }, TensorShape.C); - } - } - if (b == 0) - O = Ob; - else - O = Concat(new[] { O, Ob }, TensorShape.DataBatch); - } - return O; - } - - /// - /// Simple 2D matrix multiplication O = `X` ⨯ `Y` - /// - /// left Tensor - /// `X` transposed data flag - /// right Tensor - /// `Y` transposed data flag - /// output Tensor - public virtual Tensor MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - Assert.IsTrue(X.dimensions <= 2); - Assert.IsTrue(Y.dimensions <= 2); - X = Flatten(X); - Y = Flatten(Y); - - if (xTranspose) - X = Transpose(X); - if (yTranspose) - Y = Transpose(Y); - - Assert.AreEqual(X.flatWidth, Y.flatHeight); - var O = NewTensor(X.dataType, X.flatHeight, Y.flatWidth); - - for (int y = 0; y < O.flatHeight; ++y) - for (int x = 0; x < O.flatWidth; ++x) - { - float v = 0; - for (int i = 0; i < X.flatWidth; ++i) - { - v += X[y, i] * Y[i, x]; - } - O[y, x] = v; - } - return O; - } - - /// - public virtual Tensor Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(W.dimensions <= 2); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(X.flatWidth, W.flatHeight); - - var O = NewTensor(X.dataType, X.flatHeight, W.flatWidth); - - for (int y = 0; y < O.flatHeight; ++y) - for (int x = 0; x < O.flatWidth; ++x) - { - float v = B[x]; - for (int i = 0; i < X.flatWidth; ++i) - { - v += X[y, i] * W[i, x]; - } - O[y, x] = ApplyFusedActivation(v, fusedActivation); - } - return O; - } - - /// - public virtual Tensor Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewTensor(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad)); - - for (var n = 0; n < O.batch; ++n) - for (var y = 0; y < O.height; ++y) - for (var x = 0; x < O.width; ++x) - for (var k = 0; k < K.kernelCount; ++k) - { - float v = B[k]; - for (int dy = 0; dy < K.kernelHeight; ++dy) - { - for (int dx = 0; dx < K.kernelWidth; ++dx) - { - int oy = y * stride[1] + dy - pad[1]; - int ox = x * stride[0] + dx - pad[0]; - - if (oy < 0) continue; - if (oy >= X.height) continue; - if (ox < 0) continue; - if (ox >= X.width) continue; - - for (var c = 0; c < X.channels; ++c) - { - float xv = X[n, oy, ox, c]; - float kv = K[dy, dx, c, k]; - - v += xv * kv; - } - } - } - O[n, y, x, k] = ApplyFusedActivation(v, fusedActivation); - } - return O; - } - - /// - public virtual Tensor Conv3D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.IsNDHWC()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 3);//WHD - Assert.AreEqual(pad.Length, 6); - - var O = NewTensor(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad)); - - for (var n = 0; n < O.batch; ++n) - for (var d = 0; d < O.depth; ++d) - for (var y = 0; y < O.height; ++y) - for (var x = 0; x < O.width; ++x) - for (var k = 0; k < K.kernelCount; ++k) - { - float v = B[k]; - for (int dd = 0; dd < K.kernelSpatialDepth; ++dd) - { - for (int dy = 0; dy < K.kernelHeight; ++dy) - { - for (int dx = 0; dx < K.kernelWidth; ++dx) - { - int od = d * stride[2] + dd - pad[2]; - int oy = y * stride[1] + dy - pad[1]; - int ox = x * stride[0] + dx - pad[0]; - - if (od < 0) continue; - if (od >= X.depth) continue; - if (oy < 0) continue; - if (oy >= X.height) continue; - if (ox < 0) continue; - if (ox >= X.width) continue; - - for (var c = 0; c < X.channels; ++c) - { - float xv = X[ n, od, oy, ox, c]; - float kv = K[ 0, dd, dy, 0, 0, dx, c, k]; - v += xv * kv; - } - } - } - } - O[ n, d, y, x, k] = ApplyFusedActivation(v, fusedActivation); - } - return O; - } - - /// - public virtual Tensor DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - if (K.kernelDepth != 1) - throw new NotImplementedException("DepthwiseConv2D only support number of groups == number of input channels at the moment."); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(K.kernelDepth, 1); - Assert.AreEqual(K.kernelCount, X.channels); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2);//WH - Assert.AreEqual(pad.Length, 4); - - // ONNX: (M x C/group x kH x kW) - // TF: [H, W, in_channels, channel_multiplier] - - // TF pseudocode: - // output[b, i, j, k * channel_multiplier + q] = - // sum_{di, dj} - // input [b, i + di, j + dj, k] * - // filter[di, dj, k, q] * - - var O = NewTensor(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad)); - - for (var n = 0; n < O.batch; ++n) - for (var y = 0; y < O.height; ++y) - for (var x = 0; x < O.width; ++x) - for (var k = 0; k < K.kernelCount; ++k) - { - float v = B[k]; - for (int dy = 0; dy < K.kernelHeight; ++dy) - for (int dx = 0; dx < K.kernelWidth; ++dx) - { - int oy = y * stride[1] + dy - pad[1]; - int ox = x * stride[0] + dx - pad[0]; - - if (oy < 0) continue; - if (oy >= X.height) continue; - if (ox < 0) continue; - if (ox >= X.width) continue; - - float xv = X[n, oy, ox, k]; - float kv = K[dy, dx, 0, k]; - v += xv * kv; - } - O[n, y, x, k] = ApplyFusedActivation(v, fusedActivation); - } - return O; - } - - /// - public virtual Tensor Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - Assert.AreEqual(pad[0],pad[2]); - Assert.AreEqual(pad[1],pad[3]); - - var O = NewTensor(X.dataType, X.shape.ApplyKernelInverse(K.shape, stride, pad, outputAdjustment)); - int prePadW = K.kernelWidth - pad[0] - 1; - int prePadH = K.kernelHeight - pad[1] - 1; - int strideH = 1; - int strideW = 1; - - for (var n = 0; n < O.batch; ++n) - for (var y = 0; y < O.height; ++y) - for (var x = 0; x < O.width; ++x) - for (var k = 0; k < K.kernelCount; ++k) - { - float v = B[k]; - for (int dy = 0; dy < K.kernelHeight; dy += strideH) - for (int dx = 0; dx < K.kernelWidth; dx += strideW) - { - int readX = (x + dx - prePadW) / stride[0]; - int readY = (y + dy - prePadH) / stride[1]; - - if ((x + dx - prePadW) % stride[0] != 0) continue; - if ((y + dy - prePadH) % stride[0] != 0) continue; - if (readX < 0) continue; - if (readX >= X.width) continue; - if (readY < 0) continue; - if (readY >= X.height) continue; - - for (var c = 0; c < X.channels; ++c) - { - float xv = X[n, readY, readX, c]; - float kv = K[K.kernelHeight - 1 - dy, - K.kernelWidth - 1 - dx, c, k]; - v += xv * kv; - } - } - - O[n, y, x, k] = ApplyFusedActivation(v, fusedActivation); - } - return O; - } - - private static float BilinearInterpolation(float fracSrcPosX, float fracSrcPosY, float p00, float p01, float p10, float p11) - { - float v = - p00 * (1-fracSrcPosX) * (1-fracSrcPosY) + - p01 * (1-fracSrcPosX) * fracSrcPosY + - p10 * fracSrcPosX * (1-fracSrcPosY) + - p11 * fracSrcPosX * fracSrcPosY; - return v; - } - - /// - public virtual Tensor Upsample3D(Tensor X, int[] scale, bool trilinear) - { - Assert.IsTrue(X.shape.IsNDHWC()); - Assert.AreEqual(scale.Length, 3); - float scaleX = (float)scale[0]; - float scaleY = (float)scale[1]; - float scaleD = (float)scale[2]; - - var O = NewTensor(X.dataType, new TensorShape(1, 1,X.batch, 1, X.depth*scale[2], X.height*scale[1], X.width*scale[0], X.channels)); - - for (int b = 0; b < O.batch; ++b) - for (int d = 0; d < O.depth; ++d) - for (int y = 0; y < O.height; ++y) - for (int x = 0; x < O.width; ++x) - for (int c = 0; c < O.channels; ++c) - { - if (trilinear) - { - float srcPosD = (d + 0.5f) / scaleD - 0.5f; - float srcPosX = (x + 0.5f) / scaleX - 0.5f; - float srcPosY = (y + 0.5f) / scaleY - 0.5f; - float floorSrcPosD = Mathf.Floor(srcPosD); - float floorSrcPosX = Mathf.Floor(srcPosX); - float floorSrcPosY = Mathf.Floor(srcPosY); - float fracSrcPosD = srcPosD - floorSrcPosD; - float fracSrcPosX = srcPosX - floorSrcPosX; - float fracSrcPosY = srcPosY - floorSrcPosY; - - //from https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/interpolation/trilinear-interpolation - float p000 = X[X.IndexWithClamp(b, (int)floorSrcPosD + 0, (int)floorSrcPosY + 0, (int)floorSrcPosX + 0, c)]; - float p100 = X[X.IndexWithClamp(b, (int)floorSrcPosD + 1, (int)floorSrcPosY + 0, (int)floorSrcPosX + 0, c)]; - float p010 = X[X.IndexWithClamp(b, (int)floorSrcPosD + 0, (int)floorSrcPosY + 1, (int)floorSrcPosX + 0, c)]; - float p110 = X[X.IndexWithClamp(b, (int)floorSrcPosD + 1, (int)floorSrcPosY + 1, (int)floorSrcPosX + 0, c)]; - float p001 = X[X.IndexWithClamp(b, (int)floorSrcPosD + 0, (int)floorSrcPosY + 0, (int)floorSrcPosX + 1, c)]; - float p101 = X[X.IndexWithClamp(b, (int)floorSrcPosD + 1, (int)floorSrcPosY + 0, (int)floorSrcPosX + 1, c)]; - float p011 = X[X.IndexWithClamp(b, (int)floorSrcPosD + 0, (int)floorSrcPosY + 1, (int)floorSrcPosX + 1, c)]; - float p111 = X[X.IndexWithClamp(b, (int)floorSrcPosD + 1, (int)floorSrcPosY + 1, (int)floorSrcPosX + 1, c)]; - float e = BilinearInterpolation(fracSrcPosX, fracSrcPosY, p000, p100, p010, p110); - float f = BilinearInterpolation(fracSrcPosX, fracSrcPosY, p001, p101, p011, p111); - float v = e * ( 1 - fracSrcPosD) + f * fracSrcPosD; - O[b, d, y, x, c] = v; - } - else - { - int od = d / scale[2]; - int oy = y / scale[1]; - int ox = x / scale[0]; - O[b, d, y, x, c] = X[b, od, oy, ox, c]; - } - } - return O; - } - - /// - public virtual Tensor Upsample2D(Tensor X, int[] scale, bool bilinear) - { - Assert.AreEqual(scale.Length, 2); - float scaleX = (float)scale[0]; - float scaleY = (float)scale[1]; - - Assert.IsTrue(X.shape.Is4D()); - var O = NewTensor(X.dataType, X.batch, X.height*scale[1], X.width*scale[0], X.channels); - - for (int b = 0; b < O.batch; ++b) - for (int y = 0; y < O.height; ++y) - for (int x = 0; x < O.width; ++x) - for (int c = 0; c < O.channels; ++c) - { - if (bilinear) - { - float srcPosX = (x + 0.5f) / scaleX - 0.5f; - float srcPosY = (y + 0.5f) / scaleY - 0.5f; - float floorSrcPosX = Mathf.Floor(srcPosX); - float floorSrcPosY = Mathf.Floor(srcPosY); - float fracSrcPosX = srcPosX - floorSrcPosX; - float fracSrcPosY = srcPosY - floorSrcPosY; - - float p00 = X[X.IndexWithClamp(b, (int)floorSrcPosY + 0, (int)floorSrcPosX + 0, c)]; - float p01 = X[X.IndexWithClamp(b, (int)floorSrcPosY + 1, (int)floorSrcPosX + 0, c)]; - float p10 = X[X.IndexWithClamp(b, (int)floorSrcPosY + 0, (int)floorSrcPosX + 1, c)]; - float p11 = X[X.IndexWithClamp(b, (int)floorSrcPosY + 1, (int)floorSrcPosX + 1, c)]; - O[b, y, x, c] = BilinearInterpolation(fracSrcPosX, fracSrcPosY, p00, p01, p10, p11); - } - else - { - int oy = y / scale[1]; - int ox = x / scale[0]; - O[b, y, x, c] = X[b, oy, ox, c]; - } - - } - return O; - } - - /// - public virtual Tensor Resample2D(Tensor X, int[] size, bool bilinear) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(size.Length, 2); - var O = NewTensor(X.dataType, X.batch, size[1], size[0], X.channels); - - float scaleX = O.width / (float) X.width; - float scaleY = O.height / (float) X.height; - - for (int b = 0; b < O.batch; ++b) - for (int y = 0; y < O.height; ++y) - for (int x = 0; x < O.width; ++x) - for (int c = 0; c < O.channels; ++c) - { - if (bilinear) - { - float srcPosX = (x + 0.5f) / scaleX - 0.5f; - float srcPosY = (y + 0.5f) / scaleY - 0.5f; - float floorSrcPosX = Mathf.Floor(srcPosX); - float floorSrcPosY = Mathf.Floor(srcPosY); - float fracSrcPosX = srcPosX - floorSrcPosX; - float fracSrcPosY = srcPosY - floorSrcPosY; - - float p00 = X[X.IndexWithClamp(b, (int)floorSrcPosY + 0, (int)floorSrcPosX + 0, c)]; - float p01 = X[X.IndexWithClamp(b, (int)floorSrcPosY + 1, (int)floorSrcPosX + 0, c)]; - float p10 = X[X.IndexWithClamp(b, (int)floorSrcPosY + 0, (int)floorSrcPosX + 1, c)]; - float p11 = X[X.IndexWithClamp(b, (int)floorSrcPosY + 1, (int)floorSrcPosX + 1, c)]; - float v = - p00 * (1 - fracSrcPosX) * (1 - fracSrcPosY) + - p01 * (1 - fracSrcPosX) * fracSrcPosY + - p10 * fracSrcPosX * (1 - fracSrcPosY) + - p11 * fracSrcPosX * fracSrcPosY; - O[b, y, x, c] = v; - } - else - { - var srcY = Mathf.FloorToInt(y / scaleY); - var srcX = Mathf.FloorToInt(x / scaleX); - O[b, y, x, c] = X[X.IndexWithClamp(b, srcY, srcX, c)]; - } - } - return O; - } - - /// - public virtual Tensor DepthToSpace(Tensor X, int[] blocksize, Layer.DepthToSpaceMode mode) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(blocksize.Length, 2); - int bsX = blocksize[0]; - int bsY = blocksize[1]; - - Assert.AreEqual(X.channels % (bsX * bsY), 0); - - var O = NewTensor(X.dataType, X.batch, X.height * bsY, X.width * bsX, X.channels / (bsX * bsY)); - - for (int b = 0; b < O.batch; ++b) - for (int y = 0; y < O.height; ++y) - for (int x = 0; x < O.width; ++x) - for (int c = 0; c < O.channels; ++c) - { - int iy = y / bsY; - int by = y % bsY; - int ix = x / bsX; - int bx = x % bsX; - switch (mode) - { - case Layer.DepthToSpaceMode.CRD: - O[b, y, x, c] = X[b, iy, ix, (c * bsX * bsY) + (by * bsX) + bx]; - break; - case Layer.DepthToSpaceMode.DCR: - O[b, y, x, c] = X[b, iy, ix, (by * bsX * O.channels) + (bx * O.channels) + c]; - break; - } - } - - return O; - } - - /// - public virtual Tensor SpaceToDepth(Tensor X, int[] blocksize) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(blocksize.Length, 2); - int bsX = blocksize[0]; - int bsY = blocksize[1]; - - Assert.AreEqual(X.height % bsY, 0); - Assert.AreEqual(X.width % bsX, 0); - - var O = NewTensor(X.dataType, X.batch, X.height / bsY, X.width / bsX, X.channels * (bsX * bsY)); - - for (int b = 0; b < O.batch; ++b) - for (int y = 0; y < O.height; ++y) - for (int x = 0; x < O.width; ++x) - for (int c = 0; c < O.channels; ++c) - { - int ic = c % X.channels; - int bx = c / X.channels % bsX; - int by = c / X.channels / bsX; - int ix = x * bsX + bx; - int iy = y * bsY + by; - - O[b, y, x, c] = X[b, iy, ix, ic]; - } - - return O; - } - - /// - public virtual Tensor MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewTensor(X.dataType, X.shape.ApplyPool(pool, stride, pad)); - - for (int b = 0; b < O.batch; ++b) - for (int y = 0; y < O.height; ++y) - for (int x = 0; x < O.width; ++x) - for (int c = 0; c < O.channels; ++c) - { - float maxVal = float.MinValue; - for (int dy = 0; dy < pool[1]; ++dy) - for (int dx = 0; dx < pool[0]; ++dx) - { - int oy = y * stride[1] + dy - pad[1]; - int ox = x * stride[0] + dx - pad[0]; - - if (oy < 0) continue; - if (oy >= X.height) continue; - if (ox < 0) continue; - if (ox >= X.width) continue; - - float v = X[b, oy, ox, c - //b * X.height * X.width * X.channels + - //oy * X.width * X.channels + - //ox * X.channels + - //c + - //X.offset - ]; - maxVal = Mathf.Max(v, maxVal); - } - - O[b, y, x, c - //b * O.height * O.width * O.channels + - //y * O.width * O.channels + - //x * O.channels + - //c + - //O.offset - ] = maxVal; - } - return O; - } - - /// - public virtual Tensor AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewTensor(X.dataType, X.shape.ApplyPool(pool, stride, pad)); - - for (int b = 0; b < O.batch; ++b) - for (int y = 0; y < O.height; ++y) - for (int x = 0; x < O.width; ++x) - for (int c = 0; c < O.channels; ++c) - { - float accum = 0.0f; - float counter = 0.0f; - for (int dy = 0; dy < pool[1]; ++dy) - for (int dx = 0; dx < pool[0]; ++dx) - { - int oy = y * stride[1] + dy - pad[1]; - int ox = x * stride[0] + dx - pad[0]; - - if (oy < 0) continue; - if (oy >= X.height) continue; - if (ox < 0) continue; - if (ox >= X.width) continue; - - float v = X[b, oy, ox, c - //b * X.height * X.width * X.channels + - //oy * X.width * X.channels + - //ox * X.channels + - //c + - //X.offset - ]; - accum += v; - ++counter; - } - - O[b, y, x, c - //b * O.height * O.width * O.channels + - //y * O.width * O.channels + - //x * O.channels + - //c + - //O.offset - ] = accum / counter; - } - return O; - } - - /// - public virtual Tensor GlobalMaxPool2D(Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - var O = NewTensor(X.dataType, X.batch, 1, 1, X.channels); - - for (int b = 0; b < X.batch; ++b) - for (int c = 0; c < X.channels; ++c) - { - float maxVal = float.MinValue; - for (int y = 0; y < X.height; ++y) - for (int x = 0; x < X.width; ++x) - { - float v = X[b, y, x, c - //b * X.height * X.width * X.channels + - //y * X.width * X.channels + - //x * X.channels + - //c + - //X.offset - ]; - maxVal = Mathf.Max(v, maxVal); - } - - O[b, 0, 0, c - //b * O.channels + - //c + - //O.offset - ] = maxVal; - } - return O; - } - - /// - public virtual Tensor GlobalAvgPool2D(Tensor X) - { - var O = NewTensor(X.dataType, X.batch, 1, 1, X.channels); - - for (int b = 0; b < X.batch; ++b) - for (int c = 0; c < X.channels; ++c) - { - float accum = 0.0f; - for (int y = 0; y < X.height; ++y) - for (int x = 0; x < X.width; ++x) - { - float v = X[b, y, x, c - //b * X.height * X.width * X.channels + - //y * X.width * X.channels + - //x * X.channels + - //c + - //X.offset - ]; - accum += v; - } - - O[b, 0, 0, c - //b * O.channels + - //c + - //O.offset - ] = accum / (X.width * X.height); - } - return O; - } - - /// - public virtual Tensor GlobalAvgVariancePool2D(Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - var O = NewTensor(X.dataType, X.batch, 2, 1, X.channels); - - for (int b = 0; b < X.batch; ++b) - for (int c = 0; c < X.channels; ++c) - { - float mean = 0.0f; - float mean2 = 0.0f; - for (int y = 0; y < X.height; ++y) - for (int x = 0; x < X.width; ++x) - { - float v = X[b, y, x, c - //b * X.height * X.width * X.channels + - //y * X.width * X.channels + - //x * X.channels + - //c + - //X.offset - ]; - mean += v; - mean2 += v*v; - } - - mean /= (X.width * X.height); - mean2 /= (X.width * X.height); - - O[b, 0, 0, c - //b * O.channels + - //c + - //O.offset - ] = mean; - - O[b, 1, 0, c - //b * O.channels + - //c + - //O.offset - ] = mean2 - mean * mean; - } - return O; - } - - private Tensor ApplyPadding(Tensor X, int[] pad, Func paddingOp) - { - Assert.IsTrue(X.shape.IsNDHWC()); - Assert.IsTrue(pad.Length == 6 || pad.Length == 8); - - var O = NewTensor(X.dataType, X.shape.ApplyBorder(pad)); - - int prePadW = pad[0]; - int prePadH = pad[1]; - int prePadD = pad.Length == 6 ? 0 : pad[2]; - int prePadC = pad.Length == 6 ? pad[2] : pad[3]; - - int postPadW = pad.Length == 6 ? pad[3] : pad[4]; - int postPadH = pad.Length == 6 ? pad[4] : pad[5]; - int postPadD = pad.Length == 6 ? 0 : pad[6]; - int postPadC = pad.Length == 6 ? pad[5] : pad[7]; - - // NOTE: negative "pad" variable will crop X tensor - int croppedWidth = X.width - Math.Max(0, -postPadW); - int croppedHeight = X.height - Math.Max(0, -postPadH); - int croppedDepth = X.depth - Math.Max(0, -postPadD); - int croppedChannels = X.channels - Math.Max(0, -postPadC); - - for (int b = 0; b < O.batch; ++b) - for (int d = 0; d < O.depth; ++d) - for (int h = 0; h < O.height; ++h) - for (int w = 0; w < O.width; ++w) - for (int c = 0; c < O.channels; ++c) - { - int readW = w - prePadW; - int readH = h - prePadH; - int readD = d - prePadD; - int readC = c - prePadC; - - if (readW < 0 || readW >= croppedWidth || - readH < 0 || readH >= croppedHeight || - readD < 0 || readD >= croppedDepth || - readC < 0 || readC >= croppedChannels) - { - O[b, d, h, w, c] = paddingOp(X, b, readD, readH, readW, readC); - } - else - { - O[b, d, h, w, c] = X[b, readD, readH, readW, readC]; - } - } - return O; - } - - /// - public virtual Tensor Border2D(Tensor X, int[] pad, float value) - { - Func padOp = (tensor, b, d, h, w, c) => value; - return ApplyPadding(X, pad, padOp); - } - - /// - public virtual Tensor Border3D(Tensor X, int[] pad, float value) - { - Func padOp = (tensor, b, d, h, w, c) => value; - return ApplyPadding(X, pad, padOp); - } - - private static void ClampHWCToTensorShape(TensorShape shape, ref int height, ref int width, ref int channels) - { - width = Math.Max(width, 0); - height = Math.Max(height, 0); - channels = Math.Max(channels, 0); - width = Math.Min(width, shape.width - 1); - height = Math.Min(height, shape.height - 1); - channels = Math.Min(channels, shape.channels - 1); - } - - /// - public virtual Tensor Pad2DReflect(Tensor X, int[] pad) - { - float GetReflectPadding(Tensor tensorX, int b, int readD, int readY, int readX, int readC) - { - //TODO when implementing Pad3DReflect change to function and support depth - int lastXIndex = tensorX.shape.width - 1; - int lastYIndex = tensorX.shape.height - 1; - int lastCIndex = tensorX.shape.channels - 1; - - if (readX < 0) - readX = -readX; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex); - - if (readY < 0) - readY = -readY; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex); - - if (readC < 0) - readC = -readC; - else if (readC > lastCIndex) - readC = lastCIndex - (readC - lastCIndex); - - ClampHWCToTensorShape(tensorX.shape, ref readY, ref readX, ref readC); - return tensorX[b, readY, readX, readC]; - } - - return ApplyPadding(X, pad, GetReflectPadding); - } - - /// - public virtual Tensor Pad2DSymmetric(Tensor X, int[] pad) - { - float GetSymmetricPadding(Tensor tensorX, int b, int readD, int readY, int readX, int readC) - { - //TODO when implementing Pad3DSymmetric change to function and support depth - int lastXIndex = tensorX.shape.width - 1; - int lastYIndex = tensorX.shape.height - 1; - int lastCIndex = tensorX.shape.channels - 1; - - if (readX < 0) - readX = -readX - 1; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex) + 1; - - if (readY < 0) - readY = -readY - 1; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex) + 1; - - if (readC < 0) - readC = -readC - 1; - else if (readC > lastCIndex) - readC = lastCIndex - (readC - lastCIndex) + 1; - - ClampHWCToTensorShape(tensorX.shape, ref readY, ref readX, ref readC); - return tensorX[b, readY, readX, readC]; - } - - return ApplyPadding(X, pad, GetSymmetricPadding); - } - - /// - public virtual Tensor Pad2DEdge(Tensor X, int[] pad) - { - float GetEdgePadding(Tensor tensorX, int b, int readD, int readY, int readX, int readC) - { - //TODO when implementing Pad3DEdge change to function and support depth - ClampHWCToTensorShape(tensorX.shape, ref readY, ref readX, ref readC); - return tensorX[b, readY, readX, readC]; - } - - return ApplyPadding(X, pad, GetEdgePadding); - } - - /// - public virtual Tensor ScaleBias(Tensor X, Tensor S, Tensor B) - { - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - - var O = NewTensorLike(X); - - for (var it = new TensorIterator(O); it.IsValid(); it.Next()) - { - float beta = B[0, 0, 0, it.d7];//.array[c + B.offset]; - float gamma = S[0, 0, 0, it.d7];//S.array[c + S.offset]; - - //var i = X.IndexWithOffset(b, y, x, c); - float v = X[it.index];//.array[i]; - O[it.index] = v * gamma + beta; - } - return O; - } - - /// - public virtual Tensor LRN(Tensor X, float alpha, float beta, float bias, int size) - { - // https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf - // However divide the sum by size to follow onnx and pytorch implementation - // ONNX https://github.com/onnx/onnx/blob/master/docs/Operators.md#LRN - // PYTORCH https://github.com/pytorch/pytorch/blob/1465970a343e61f2f2b104859ca7f5d7e03f5d02/torch/nn/functional.py#L2069 - // Tensorflow don't and follow the paper to the letter https://github.com/tensorflow/tensorflow/blob/e6faa845c51bb69465146d93646947fd2ba53efa/tensorflow/python/kernel_tests/lrn_op_test.py#L53 - // However they bake the division to alpha when exporting to ONNX https://github.com/onnx/tensorflow-onnx/blob/7c37ccb97e0fd478ce093910c4a1411b18e44fd7/tf2onnx/onnx_opset/math.py - var O = NewTensorLike(X); - float sizef = size; - - for (var it = new TensorIterator(O); it.IsValid(); it.Next()) - { - int c = it.d7; - float regionCenter = (sizef - 1.0f) / 2.0f; - int regionStart = Math.Max(0, c - (int)Mathf.Floor(regionCenter)); - int regionEnd = Math.Min(X.channels, c + (int)Mathf.Ceil(regionCenter)+1); - float sumOfSquared = 0.0f; - for (int ci = regionStart; ci < regionEnd; ++ci) - { - float regionValue = X[it.d0, it.d1, it.d2, it.d3, it.d4, it.d5, it.d6 ,ci]; - sumOfSquared += regionValue * regionValue; - } - - O[it.index] = X[it.index] / Mathf.Pow(bias + alpha * sumOfSquared / sizef, beta); - } - return O; - } - - /// - public virtual Tensor Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) - { - if (!X.shape.Is4D()) - throw new NotImplementedException(); - - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - - if (axis != TensorShape.C && axis != -1) - throw new NotImplementedException(); - - // Special cases of Normalization: - // 1) Instance Normalization, if pool == 1 - // 2) Batch Normalization, if pool <= 0 - if (pool <= 0) - pool = X.batch; - - var O = NewTensorLike(X); - - var channels = X.channels; - var width = X.width; - var height = X.height; - - for (int subBatch = 0; subBatch < O.batch; subBatch += pool) - for (int c = 0; c < channels; ++c) - { - int bBegin = subBatch; - int bEnd = Math.Min(subBatch + pool, O.batch); - - float gamma = S[0, 0, 0, c];//.array[c + S.offset]; - float beta = B[0, 0, 0, c];//B.array[c + B.offset]; - - // calc mean - double sum = 0; - for (int b = bBegin; b < bEnd; ++b) - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) - { - double v = X[b, y, x, c]; - sum += v; - } - double mean = sum / (width * height); - - // calc variance - sum = 0; - for (int b = bBegin; b < bEnd; ++b) - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) - { - double v = X[b, y, x, c]; - sum += (v - mean) * (v - mean); - } - double var = sum / (width * height); - - // apply normalization - for (int b = bBegin; b < bEnd; ++b) - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) - { - float v = X[b, y, x, c]; - v = (float)(gamma * (v - mean) / Math.Sqrt(var + epsilon) + beta); - O[b, y, x, c] = ApplyFusedActivation(v, fusedActivation); - } - } - return O; - } - - /// - /// Bernoulli distribution - /// - /// p - /// random value - protected float Bernoulli(float p) - { - return (Random.value <= p) ? 1f: 0f; - } - - /// - /// Gaussian distribution - /// - /// mean - /// standard deviation - /// random value - protected float Gaussian(float mean, float stdDev) - { - float u, v, s; - do { - u = Random.value * 2 - 1; - v = Random.value * 2 - 1; - s = u * u + v * v; - } while (s >= 1 || s == 0); - float mul = Mathf.Sqrt(-2.0f * Mathf.Log(s) / s); - return mean + stdDev * u * mul; - } - - internal class Seed : IDisposable - { - Random.State[] m_SeedStorage; - Random.State m_EngineSeed; - public Seed(ref Random.State[] storage, int initialSeed) - { - m_EngineSeed = Random.state; - if (storage == null) - { - storage = new Random.State[1]; - Random.InitState(initialSeed); - storage[0] = Random.state; - } - else - Random.state = storage[0]; - m_SeedStorage = storage; - } - - public virtual void Dispose() - { - m_SeedStorage[0] = Random.state; - Random.state = m_EngineSeed; - } - } - - internal Random.State[] m_DropoutSeed; - /// - public virtual Tensor Dropout(Tensor X, float alpha) - { - Assert.IsTrue(alpha >= 0f && alpha <= 1f); - var O = NewTensorLike(X); - - // Based on PyTorch Dropout implementation - // See: https://github.com/pytorch/pytorch/blob/master/torch/nn/_functions/dropout.py - - using (var seedOverride = new Seed(ref m_DropoutSeed, 1337)) - { - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v *= Bernoulli(1f - alpha) / (1f - alpha); - O[i] = v; - } - } - return O; - } - - private Random.State[] m_RandomNormalSeed; - /// - public virtual Tensor RandomNormal(TensorShape s, float mean, float scale, int seed) - { - var O = NewTensor(DataType.Float, s); - //TODO fp16: RandomNormal should be able to select output type - //see dtype here https://github.com/onnx/onnx/blob/master/docs/Operators.md#RandomNormal - - using (var seedOverride = new Seed(ref m_RandomNormalSeed, seed)) - { - var end = O.length; - for (int i = 0; i < end; ++i) - O[i] = Gaussian(mean, scale); - } - - return O; - } - - private Random.State[] m_RandomUniformSeed; - /// - public virtual Tensor RandomUniform(TensorShape s, float mean, float scale, int seed) - { - var O = NewTensor(DataType.Float, s); - //TODO fp16: RandomNormal should be able to select output type - //see dtype here https://github.com/onnx/onnx/blob/master/docs/Operators.md#RandomUniform - - using (var seedOverride = new Seed(ref m_RandomUniformSeed, seed)) - { - var end = O.length; - for (int i = 0; i < end; ++i) - O[i] = mean + scale * Random.value; - } - - return O; - } - - private Random.State[] m_MultinomialSeed; - /// - public virtual Tensor Multinomial(Tensor X, int count, int seed) - { - if (X.shape.sequenceLength != 1 || X.shape.numberOfDirections != 1) - throw new NotImplementedException(); - - var O = NewTensor(X.dataType, X.flatHeight, count); - - // Tensorflow Multinomial for reference - // See: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/kernels/multinomial_op.cc - - using (var seedOverride = new Seed(ref m_MultinomialSeed, seed)) - { - for (int n = 0; n < X.flatHeight; ++n) - { - var maxLogP = Mathf.NegativeInfinity; - for (int i = 0; i < X.flatWidth; ++i) - maxLogP = Mathf.Max(X[n, i], maxLogP); - - float sumOfProbabilities = 0f; - for (int i = 0; i < X.flatWidth; ++i) - sumOfProbabilities += Mathf.Exp(X[n, i] - maxLogP); // NOTE: X contains log-probabilities - - for (int sample = 0; sample < count; ++sample) - { - float p = Random.value * sumOfProbabilities; - - int i = 0; - float cumulativeP = 0f; - while (i < X.flatWidth && p > cumulativeP) - { - cumulativeP += Mathf.Exp(X[n, i] - maxLogP); - i++; - } - Assert.IsTrue(i > 0); - O[n, sample] = (float)(i - 1); - } - } - } - - return O; - } - - /// - public virtual Tensor OneHot(Tensor X, int depth, float onValue, float offValue, int inputRank=-1) - { - if (inputRank == -1) - inputRank = X.dimensions; - - if (inputRank >= 4) - throw new NotImplementedException(); - - Tensor O; - if (inputRank == 1) - O = NewOutputTensor(X.dataType, new TensorShape(X.flatHeight, depth)); - else if (inputRank == 2) - O = NewOutputTensor(X.dataType, new TensorShape(X.flatHeight, 1, depth, X.channels)); - else - O = NewOutputTensor(X.dataType, new TensorShape(X.batch, X.width, depth, X.channels)); - - // rank1: X = n,_,_,_ - // rank2: X = n,_,_,c - // rank3: X = n,_,w,c - - for (int n = 0; n < X.batch; ++n) - { - for (int j = 0; j < depth; ++j) - { - for (int k = 0; k < X.width; ++k) - { - for (int i = 0; i < X.channels; ++i) - { - if (inputRank == 1) - { - int index = (int)X[n]; - float v = (j == index) ? onValue: offValue; - O[n, j] = v; - } - else if (inputRank == 2) - { - int index = (int)X[n, i]; - float v = (j == index) ? onValue: offValue; - O[n, 0, j, i] = v; - } - else - { - int index = (int)X[n, 0, k, i]; - float v = (j == index) ? onValue: offValue; - O[n, k, j, i] = v; - } - } - } - } - } - return O; - } - - private float NearestNeighbourBilinearInterpolation(Tensor X, int n, float y, float x, int c, bool snapToBorder = false) - { - if (snapToBorder) - { - y = Mathf.Clamp(y, 0, X.height - 1); - x = Mathf.Clamp(x, 0, X.width - 1); - } - - int y_low = (int)Mathf.Floor(y); - int x_low = (int)Mathf.Floor(x); - int y_high = y_low + 1; - int x_high = x_low + 1; - - float wy_h = y - y_low; - float wx_h = x - x_low; - float wy_l = 1.0f - wy_h; - float wx_l = 1.0f - wx_h; - - float v = 0.0f; - if(y_low >= 0 && y_low < X.height && x_low >= 0 && x_low < X.width) - v += wx_l * wy_l * X[n, y_low, x_low, c]; - if (y_low >= 0 && y_low < X.height && x_high >= 0 && x_high < X.width) - v += wx_h * wy_l * X[n, y_low, x_high, c]; - if (y_high >= 0 && y_high < X.height && x_low >= 0 && x_low < X.width) - v += wx_l * wy_h * X[n, y_high, x_low, c]; - if (y_high >= 0 && y_high < X.height && x_high >= 0 && x_high < X.width) - v += wx_h * wy_h * X[n, y_high, x_high, c]; - - return v; - } - - /// - - public virtual Tensor RoiAlign(Tensor X, Tensor Rois, Tensor Indices, int outputHeight, int outputWidth, int samplingRatio, float spatialScale) - { - // https://arxiv.org/abs/1703.06870 - // https://github.com/pytorch/vision/blob/cdb6fba52f461b276d9b4d0a817b62e69344021c/test/test_ops.py - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(Rois.flatHeight, Indices.batch); - Assert.AreEqual(Rois.flatWidth, 4); - - Tensor O = NewTensor(X.dataType, Rois.flatHeight, outputHeight, outputWidth, X.channels); - - bool aligned = false; - float offset = aligned ? 0.5f : 0.0f; - - for (int n = 0; n < Rois.flatHeight; n++) - { - float j_begin = Rois[n, 0] * spatialScale - offset; - float i_begin = Rois[n, 1] * spatialScale - offset; - float j_end = Rois[n, 2] * spatialScale - offset; - float i_end = Rois[n, 3] * spatialScale - offset; - - float roi_h = i_end - i_begin; - float roi_w = j_end - j_begin; - float bin_h = roi_h / ((float)outputHeight); - float bin_w = roi_w / ((float)outputWidth); - - int batchIdx = (int)Indices[n]; - - for (int i = 0; i < outputHeight; i++) - for (int j = 0; j < outputWidth; j++) - { - float start_h = i_begin + i * bin_h; - float grid_h = samplingRatio > 0 ? samplingRatio : Mathf.Ceil(bin_h); - float start_w = j_begin + j * bin_w; - float grid_w = samplingRatio > 0 ? samplingRatio : Mathf.Ceil(bin_w); - - for (int c = 0; c < X.channels; c++) - { - float v = 0.0f; - for (int iy = 0; iy < (int)grid_h; iy++) - for (int ix = 0; ix < (int)grid_w; ix++) - { - float y = start_h + (iy + 0.5f) * bin_h / grid_h; - float x = start_w + (ix + 0.5f) * bin_w / grid_w; - - if(x >= X.width || x < 0 || y >= X.height || y < 0) - v += 0.0f; - else - v += NearestNeighbourBilinearInterpolation(X, batchIdx, y, x, c, true); - } - - v /= grid_h * grid_w; - - - O[n, i, j, c] = v; - } - } - } - - return O; - } - - - // TODO: Revisit flattened approach (see previous attempt in source history), which had two of the four axis cases working - // but couldn't get the strides just right for the outer loop, so opted for this straightforward approach - // NOTE: If `sorted` is false, then the output is undefined, so it's only necessary to implement something explicitly - // if there is a benefit in terms of performance - /// - public virtual Tensor TopKIndices(Tensor X, int k, int axis, bool largest, bool sorted) - { - if (!X.shape.Is4D()) - throw new NotImplementedException(); - - TensorShape xShape = X.shape; - int[] inputShape = xShape.ToArray(); - - int[] outputShape = xShape.ToArray(); - outputShape[axis] = Mathf.Min(k, outputShape[axis]); // Can't have more elements then there are in the original input tensor - var O = NewTensor(X.dataType, new TensorShape(outputShape)); - TensorShape oShape = O.shape; - - // Determine the iteration order, so that the selected axis is the final loop; Everything else is shifted accordingly - int[] iterators = new int[4]; // initialized to all 0s - int[] iteratorAxes = new int[4]; // initialized below - int[] iteratorAxes8D = new int[4]; // initialized below - - // Since we are assuming rank 4 convert axis to appropriate index (from rank 8) - axis = TensorExtensions.Convert8DAxisTo4D(axis); - int axisIndex = axis; - for (int i = iteratorAxes.Length - 1; i >= 0; i--) - { - iteratorAxes[i] = axisIndex % iteratorAxes.Length; - iteratorAxes8D[i] = TensorExtensions.Convert4DTo8DAxis(iteratorAxes[i]); - axisIndex++; - } - - var topK = new SortedList(); - int[] coords = new int[4]; - for (iterators[0] = 0; iterators[0] < inputShape[iteratorAxes8D[0]]; iterators[0]++) - { - for (iterators[1] = 0; iterators[1] < inputShape[iteratorAxes8D[1]]; iterators[1]++) - { - for (iterators[2] = 0; iterators[2] < inputShape[iteratorAxes8D[2]]; iterators[2]++) - { - for (iterators[3] = 0; iterators[3] < inputShape[iteratorAxes8D[3]]; iterators[3]++) - { - coords[iteratorAxes[0]] = iterators[0]; - coords[iteratorAxes[1]] = iterators[1]; - coords[iteratorAxes[2]] = iterators[2]; - coords[iteratorAxes[3]] = iterators[3]; - int n = coords[0]; - int h = coords[1]; - int w = coords[2]; - int c = coords[3]; - int index = xShape.Index(n, h, w, c); - float value = X[index]; - if (topK.TryGetValue(value, out int existingIndex)) - index = Mathf.Min(index, existingIndex); // Per ONNX choose the lower index - - topK[value] = index; - } - - IEnumerable> elements = largest ? topK.Reverse().Take(k) : topK.Take(k); - - int e = 0; - foreach (KeyValuePair element in elements) - { - int index = element.Value; - xShape.GetPositionsFromIndex(index, ref coords[0], ref coords[1], ref coords[2], ref coords[3]); - int n = coords[0]; - int h = coords[1]; - int w = coords[2]; - int c = coords[3]; - var outputCoords = new [] { n, h, w, c }; - outputCoords[axis] = e; - - int outputIndex = oShape.Index(outputCoords[0], outputCoords[1], outputCoords[2], outputCoords[3]); - O[outputIndex] = coords[axis]; - e++; - } - - topK.Clear(); - } - } - } - - return O; - } - - /// - public Tensor NonZero(Tensor X) - { - //https://github.com/onnx/onnx/blob/master/docs/Operators.md#NonZero - //https://numpy.org/doc/stable/reference/generated/numpy.nonzero.html - //Return the indices of the elements that are non-zero. - - //The values are supposed to be return in row-major, C-style order. In order to match ONNX - //result we need to iterate tensor as if it was channel first. - List nonZeroIndices = new List(); - for (var d0 = 0; d0 < X.shape[0]; ++d0) //s - for (var d1 = 0; d1 < X.shape[1]; ++d1) //r - for (var d2 = 0; d2 < X.shape[2]; ++d2) //n - for (var d7 = 0; d7 < X.shape[7]; ++d7) //c <--channel first - for (var d3 = 0; d3 < X.shape[3]; ++d3) //t - for (var d4 = 0; d4 < X.shape[4]; ++d4) //d - for (var d5 = 0; d5 < X.shape[5]; ++d5) //h - for (var d6 = 0; d6 < X.shape[6]; ++d6) //w - { - if (Math.Abs(X[d0,d1,d2,d3,d4,d5,d6,d7]) > Single.Epsilon) - { - nonZeroIndices.Add(new int[] {d0,d1,d2,d3,d4,d5,d6,d7}); - } - } - - var O = NewTensor(X.dataType, new TensorShape(X.dimensions,nonZeroIndices.Count)); - for(int i = 0; i < nonZeroIndices.Count; ++i) - { - int destinationTensorDim = 0; - for (int d = 0; d < TensorShape.MaxRank; ++d) - { - //TODO: This won't match ONNX output size for tensor with one or many dimension of size 1. - //We need the notion of rank in Barracuda to handle this according to ONNX spec. - if (X.shape[d] > 1) - { - O[destinationTensorDim, i] = nonZeroIndices[i][d]; - ++destinationTensorDim; - } - } - } - - return O; - } - - /// - public virtual Tensor TopKValues(Tensor X, Tensor I, int axis) - { - if (!X.shape.Is4D()) - throw new NotImplementedException(); - - TensorShape xShape = X.shape; - TensorShape iShape = I.shape; - int[] indicesShape = iShape.ToArray(); - - var O = NewTensor(X.dataType, iShape); - // Determine the iteration order, so that the selected axis is the final loop; Everything else is shifted accordingly - int[] iterators = new int[4]; // initialized to all 0s - int[] iteratorAxes = new int[4]; // initialized below - int[] iteratorAxes8D = new int[4]; // initialized below - - // Since we are assuming rank 4 convert axis to appropriate index (from rank 8) - axis = TensorExtensions.Convert8DAxisTo4D(axis); - int axisIndex = axis; - for (int i = iteratorAxes.Length - 1; i >= 0; i--) - { - iteratorAxes[i] = axisIndex % iteratorAxes.Length; - iteratorAxes8D[i] = TensorExtensions.Convert4DTo8DAxis(iteratorAxes[i]); - axisIndex++; - } - - - int[] coords = new int[4]; - for (iterators[0] = 0; iterators[0] < indicesShape[iteratorAxes8D[0]]; iterators[0]++) - { - for (iterators[1] = 0; iterators[1] < indicesShape[iteratorAxes8D[1]]; iterators[1]++) - { - for (iterators[2] = 0; iterators[2] < indicesShape[iteratorAxes8D[2]]; iterators[2]++) - { - for (iterators[3] = 0; iterators[3] < indicesShape[iteratorAxes8D[3]]; iterators[3]++) - { - coords[iteratorAxes[0]] = iterators[0]; - coords[iteratorAxes[1]] = iterators[1]; - coords[iteratorAxes[2]] = iterators[2]; - coords[iteratorAxes[3]] = iterators[3]; - int n = coords[0]; - int h = coords[1]; - int w = coords[2]; - int c = coords[3]; - // Even though storage format is NHWC use NCHW indexing to match ONNX iteration - int index = iShape.Index(n, h, w, c); - - // Get the computed index (axis-relative) value for this element - int topKAxisIndex = (int)I[index]; - coords[iteratorAxes[3]] = topKAxisIndex; // Replace original coordinate lookup - n = coords[0]; - h = coords[1]; - w = coords[2]; - c = coords[3]; - int topKIndex = xShape.Index(n, h, w, c); - - O[index] = X[topKIndex]; - } - } - } - } - - return O; - } - - - /// - public virtual Tensor Relu(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Max(v, 0.0f); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor PRelu(Tensor X, Tensor S) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - float slope = S[i % S.length]; - - v = Mathf.Max(0.0f, v) + slope * Mathf.Min(0.0f, v); - O[i] = v; - } - - return O; - } - - /// - public virtual Tensor Softmax(Tensor X, int axis) - { - TensorShape xShape = X.shape; - axis = xShape.Axis(axis); // Adjust for negative axis values - var O = NewTensor(X.dataType, xShape); - Assert.AreEqual(O.flatWidth, X.flatWidth); - - int height = 1; - int axis8D = axis; - for (var i = 0; i < axis8D; i++) - { - height *= xShape[i]; - } - - int width = 1; - for (var i = axis8D + 1; i < TensorShape.MaxRank; i++) - { - width *= xShape[i]; - } - - int reducedDim = xShape[axis8D]; - - //e_x = np.exp(X - X.max(axis=1, keepdims=True)) - //X = e_x / e_x.sum(axis=1, keepdims=True) - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - float maxV = Mathf.NegativeInfinity; - for (int r = 0; r < reducedDim; ++r) - { - float v = X[y * width * reducedDim + r * width + x]; - - if (v > maxV) - maxV = v; - } - - float sum = 0.0f; - for (int r = 0; r < reducedDim; ++r) - { - float v = X[y * width * reducedDim + r * width + x]; - sum += Mathf.Exp(v - maxV); - } - - for (int r = 0; r < reducedDim; ++r) - { - float v = X[y * width * reducedDim + r * width + x]; - v = Mathf.Exp(v - maxV) / sum; - O[y * width * reducedDim + r * width + x] = v; - } - } - } - - return O; - } - - /// - public virtual Tensor LogSoftmax(Tensor X, int axis) - { - TensorShape xShape = X.shape; - axis = xShape.Axis(axis); // Adjust for negative axis values - var O = NewTensor(X.dataType, xShape); - Assert.AreEqual(O.flatWidth, X.flatWidth); - - int height = 1; - int axis8D = axis; - for (var i = 0; i < axis8D; i++) - { - height *= xShape[i]; - } - - int width = 1; - for (var i = axis8D + 1; i < TensorShape.MaxRank; i++) - { - width *= xShape[i]; - } - - int reducedDim = xShape[axis8D]; - - //e_x = np.exp(X - X.max(axis=1, keepdims=True)) - //X = log(e_x / e_x.sum(axis=1, keepdims=True)) - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - float maxV = Mathf.NegativeInfinity; - for (int r = 0; r < reducedDim; ++r) - { - float v = X[y * width * reducedDim + r * width + x]; - - if (v > maxV) - maxV = v; - } - - float sum = 0.0f; - for (int r = 0; r < reducedDim; ++r) - { - float v = X[y * width * reducedDim + r * width + x]; - sum += Mathf.Exp(v - maxV); - } - - for (int r = 0; r < reducedDim; ++r) - { - float v = X[y * width * reducedDim + r * width + x]; - v = (v - maxV) - Mathf.Log(sum); - O[y * width * reducedDim + r * width + x] = v; - } - } - } - - return O; - } - - /// - public virtual Tensor Tanh(Tensor X) - { - // f(x) = tanh(x) = sinh(x) / cosh(x) = (exp(2*x) - 1) / (exp(2*x) + 1) - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - O[i] = MathfEx.Tanh(X[i]); - } - return O; - } - - /// - public virtual Tensor Softplus(Tensor X) - { - // f(x) = ln(exp(x) + 1) - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Log(Mathf.Exp(v) + 1f); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Sigmoid(Tensor X) - { - // f(x) = 1 / (1 + exp(-x)) - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = 1f / (1f + Mathf.Exp(-v)); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor HardSigmoid(Tensor X, float alpha, float beta) - { - // https://pytorch.org/docs/stable/generated/torch.nn.Hardsigmoid.html - // https://github.com/onnx/onnx/blob/master/docs/Operators.md#HardSigmoid - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Max(0.0f, Mathf.Min(1.0f, alpha*v + beta)); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Relu6(Tensor X) - { - // f(x) = min(max(x, 0), 6) - // "Convolutional Deep Belief Networks on CIFAR-10", A Krizhevsky, 2010 - // http://www.cs.utoronto.ca/~kriz/conv-cifar10-aug2010.pdf - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Min(Mathf.Max(0f, v), 6f); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Elu(Tensor X, float alpha) - { - // f(x) = alpha * (exp(x) - 1.) for x < 0, f(x) = x for x >= 0 - // "Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs)", DA Clevert, 2015 - // https://arxiv.org/abs/1511.07289 - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - if (v <= 0) - v = alpha * (Mathf.Exp(v) - 1f); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor LeakyRelu(Tensor X, float alpha) - { - // f(x) = alpha * x for x < 0, f(x) = x for x >= 0. - // "Rectifier Nonlinearities Improve Neural Network Acoustic Models". AL Maas, 2013 - // http://web.stanford.edu/~awni/papers/relu_hybrid_icml2013_final.pdf - Assert.IsTrue(alpha <= 1); - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Max(v, alpha * v); - // @TODO: doublecheck the following code - // from Theano impl - // https://github.com/Theano/theano/blob/d395439aec5a6ddde8ef5c266fd976412a5c5695/theano/tensor/nnet/nnet.py#L2209-L2251 - //float f1 = 0.5f * (1f + alpha) - //float f2 = 0.5f * (1f - alpha) - //v = f1 * v + f2 * Mathf.Abs(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Selu(Tensor X, float alpha, float gamma) - { - // f(x) = gamma * (alpha * e^x - alpha) for x <= 0, f(x) = gamma * x for x > 0 - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - if (v <= 0) - v = gamma * (alpha * Mathf.Exp(v) - alpha); - else - v = gamma * v; - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Swish(Tensor X) - { - // f(x) = sigmoid(x) * x = x / (1 + exp(-x)) - // "Searching for Activation Functions". P Ramachandran, 2017 - // https://arxiv.org/abs/1710.05941 - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = v / (1f + Mathf.Exp(-v)); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Abs(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Abs(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Neg(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = -v; - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Ceil(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Ceil(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Clip(Tensor X, float min, float max) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Clamp(v, min, max); - - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Floor(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Floor(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Round(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Round(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Reciprocal(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = 1.0f / v; - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Pow(Tensor X, float alpha) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Pow(v, alpha); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Exp(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Exp(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Log(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Log(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Sqrt(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Sqrt(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Acos(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Acos(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Acosh(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Log(v + Mathf.Sqrt(v*v - 1.0f)); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Asin(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Asin(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Asinh(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Log(v + Mathf.Sqrt(v*v + 1.0f)); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Atan(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Atan(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Atanh(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = 0.5f * Mathf.Log((1.0f + v)/(1.0f - v)); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Cos(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Cos(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Cosh(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = 0.5f * (Mathf.Exp(v) + Mathf.Exp(-v)); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Sin(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Sin(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Sinh(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = 0.5f * (Mathf.Exp(v) - Mathf.Exp(-v)); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Tan(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - v = Mathf.Tan(v); - O[i] = v; - } - return O; - } - - /// - public virtual Tensor Erf(Tensor X) - { - var O = NewTensorLike(X); - - var end = X.length; - for (int i = 0; i < end; ++i) - { - float v = X[i]; - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x = Mathf.Abs(v); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t = 1.0f / (1.0f + p * x); - float t2 = t * t; - float t3 = t2 * t; - float t4 = t3 * t; - float t5 = t4 * t; - - v = Mathf.Sign(v) * (1 - (a1 * t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5) * Mathf.Exp(-x * x)); - O[i] = v; - } - return O; - } - - internal long GetAggregatedDimLength(TensorShape shape, int startDim, int endDim) - { - long aggregatedLength = 1L; - for (var d = startDim; d < endDim; ++d) - aggregatedLength *= shape[d]; - return aggregatedLength; - } - - /// - public virtual Tensor Concat(Tensor[] tensors, int axis) - { - var concatShape = TensorExtensions.Concat(tensors, axis); - var dataType = tensors.Length > 0 ? tensors[0].dataType : DataType.Float; - var O = NewTensor(dataType, concatShape); - - unsafe - { - var srcIndices = stackalloc long[tensors.Length]; - UnsafeUtility.MemClear(srcIndices, tensors.Length * Marshal.SizeOf()); - // NOTE: once we have Tensor.ToReadOnlyArray(ref arrayOffset), - // will need to initialize srcIndices[i] = arrayOffset; - - // product of all tensor dimensions starting from axis - var copyBlockLengths = stackalloc long[tensors.Length]; - for (int i = 0; i < tensors.Length; ++i) - copyBlockLengths[i] = GetAggregatedDimLength(tensors[i].shape, tensors[i].shape.Axis(axis), TensorShape.MaxRank); - - // copy tensor data interleaved into O - int intDstIndex = 0; - var dstArray = new float[concatShape.length]; - long dstIndex = intDstIndex; - long takes = GetAggregatedDimLength(concatShape, 0, concatShape.Axis(axis)); - for (int take = 0; take < takes; ++take) - for (int i = 0; i < tensors.Length; ++i) - { - var copyLength = copyBlockLengths[i]; - - Array.Copy(tensors[i].ToReadOnlyArray(), srcIndices[i], // from - dstArray, dstIndex, copyLength); // to - - srcIndices[i] += copyLength; - dstIndex += copyLength; - } - - O.data.Upload(dstArray, concatShape, 0); - } - return O; - } - - /// - public virtual Tensor StridedSlice(Tensor X, int[] starts4Dor8D, int[] ends4Dor8D, int[] strides4Dor8D) - { - - unsafe - { - int* starts = stackalloc int[TensorShape.MaxRank]; - int* ends = stackalloc int[TensorShape.MaxRank]; - int* strides = stackalloc int[TensorShape.MaxRank]; - TensorExtensions.Get8DParametersNoAlloc(X.shape, starts4Dor8D, starts, 0); - TensorExtensions.Get8DParametersNoAlloc(X.shape, ends4Dor8D, ends, 1); - TensorExtensions.Get8DParametersNoAlloc(X.shape, strides4Dor8D, strides, 1); - - var O = NewTensor(X.dataType, X.shape.ApplyStridedSlice8DUnsafeNoAlloc(starts, ends, strides)); - - int* wrappedStartsIndices = ends;//reuse buffer to save a stack allocation. - for (int i = 0; i < TensorShape.MaxRank; ++i) - wrappedStartsIndices[i] = Math.Min(TensorExtensions.WrapIndex(starts[i], X.shape[i]), X.shape[i] - 1); - - Assert.AreEqual(8, TensorShape.MaxRank); - for (var it = new TensorIterator(O); it.IsValid(); it.Next()) - { - // sample either from dim or index 0 in case of expansion - O[it.index] = X[ - wrappedStartsIndices[0] + it.d0 * strides[0], - wrappedStartsIndices[1] + it.d1 * strides[1], - wrappedStartsIndices[2] + it.d2 * strides[2], - wrappedStartsIndices[3] + it.d3 * strides[3], - wrappedStartsIndices[4] + it.d4 * strides[4], - wrappedStartsIndices[5] + it.d5 * strides[5], - wrappedStartsIndices[6] + it.d6 * strides[6], - wrappedStartsIndices[7] + it.d7 * strides[7]]; - } - - return O; - } - } - - /// - public virtual Tensor Tile(Tensor X, int[] repeats) - { - Tensor O = NewTensor(X.dataType, X.shape.Scale(repeats)); - - for (var it = new TensorIterator(O); it.IsValid(); it.Next()) - { - // sample either from dim or index 0 in case of expansion - O[it.index] = X[it.d0 % X.shape[0], - it.d1 % X.shape[1], - it.d2 % X.shape[2], - it.d3 % X.shape[3], - it.d4 % X.shape[4], - it.d5 % X.shape[5], - it.d6 % X.shape[6], - it.d7 % X.shape[7]]; - } - return O; - } - - /// - public virtual Tensor ConstantOfShape(TensorShape X, DataType type, float value = 0.0f) - { - Tensor O = NewTensor(type, X); - for (int i = 0; i < O.length; ++i) - O[i] = value; - - return O; - } - - /// - public Tensor Shape(Tensor X, int axis = -1) - { - int[] shape = X.shape.ToArray(); - - int shapeRank = axis > 0 ? 1 : shape.Length; - var O = NewTensor(X.dataType, new TensorShape(shapeRank, 1, 1, 1)); - if (axis > 0) - { - O[0] = shape[axis]; - } - else - { - for (var i = 0; i < shape.Length; i++) - { - O[i] = shape[i]; - } - } - - return O; - } - - private Tensor ApplyElementwiseWithBroadcast(Tensor[] tensors, Func operation) - { - var O = NewTensorLike(tensors, AllocScope.LayerOutput, false); - var A = tensors[0]; - for (int t = 1; t < tensors.Length; ++t) - { - var B = tensors[t]; - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - var valueA = A[A.IndexWithBroadcast(itO.d0, itO.d1, itO.d2, itO.d3, itO.d4, itO.d5, itO.d6, itO.d7)]; - var valueB = B[B.IndexWithBroadcast(itO.d0, itO.d1, itO.d2, itO.d3, itO.d4, itO.d5, itO.d6, itO.d7)]; - O[itO.index] = operation(valueA, valueB); - } - - A = O; - } - return O; - } - - /// - // O = tensors[0] + tensors[1] + ... + tensors[N-1] - public virtual Tensor Add(Tensor[] tensors) - { - Func op = (a, b) => a + b; - return ApplyElementwiseWithBroadcast(tensors, op); - } - - /// - // O = tensors[0] - tensors[1] - ... - tensors[N-1] - public virtual Tensor Sub(Tensor[] tensors) - { - Func op = (a, b) => a - b; - return ApplyElementwiseWithBroadcast(tensors, op); - } - - /// - // O = tensors[0] * tensors[1] * ... * tensors[N-1] - public virtual Tensor Mul(Tensor[] tensors) - { - Func op = (a, b) => a * b; - return ApplyElementwiseWithBroadcast(tensors, op); - } - - /// - // O = tensors[0] / tensors[1] / ... / tensors[N-1] - public virtual Tensor Div(Tensor[] tensors) - { - Func op = (a, b) => a / b; - return ApplyElementwiseWithBroadcast(tensors, op); - } - - /// - // O = tensors[0] ^ tensors[1] ^ ... ^ tensors[N-1] - public virtual Tensor Pow(Tensor[] tensors) - { - Func op = (a, b) => Mathf.Pow(a, b); - return ApplyElementwiseWithBroadcast(tensors, op); - } - - /// - // O = min(tensors[0], tensors[1], ... , tensors[N-1]) - public virtual Tensor Min(Tensor[] tensors) - { - Func op = (a, b) => Mathf.Min(a, b); - return ApplyElementwiseWithBroadcast(tensors, op); - } - - /// - // O = max(tensors[0], tensors[1], ... , tensors[N-1]) - public virtual Tensor Max(Tensor[] tensors) - { - Func op = (a, b) => Mathf.Max(a, b); - return ApplyElementwiseWithBroadcast(tensors, op); - } - - /// - // O = (1/N) * (tensors[0] + tensors[1] + ... + tensors[N-1]) - public virtual Tensor Mean(Tensor[] tensors) - { - // accumulate - Func op = (a, b) => a + b; - var O = ApplyElementwiseWithBroadcast(tensors, op); - - // div by N - var invN = 1.0f / tensors.Length; - var end = O.length; - for (int i = 0; i < end; ++i) - { - float v = O[i]; - v *= invN; - O[i] = v; - } - return O; - } - - /// - public virtual Tensor ReduceMin(Tensor X, int axis) - { - var O = NewTensor(X.dataType, X.shape.Reduce(axis)); - - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - O[itO.index] = float.MaxValue; - } - for (var itX = new TensorIterator(X.shape); itX.IsValid(); itX.Next()) - { - int iO = itX.IndexInReducedShape(O.shape); - O[iO] = Mathf.Min(O[iO], X[itX.index]); - } - - return O; - } - - /// - public virtual Tensor ReduceMax(Tensor X, int axis) - { - var O = NewTensor(X.dataType, X.shape.Reduce(axis)); - - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - O[itO.index] = float.MinValue; - } - for (var itX = new TensorIterator(X.shape); itX.IsValid(); itX.Next()) - { - int iO = itX.IndexInReducedShape(O.shape); - O[iO] = Mathf.Max(O[iO], X[itX.index]); - } - - return O; - } - - /// - public virtual Tensor ArgMax(Tensor X, int axis) - { - var O = NewTensor(X.dataType, X.shape.Reduce(axis)); - - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - O[itO.index] = 0; - } - - for (var itX = new TensorIterator(X.shape); itX.IsValid(); itX.Next()) - { - int iO = itX.IndexInReducedShape(O.shape); - int xBestValueIndex = itX.IndexWithReplacedAxis(axis, (int) O[iO]); - if (X[itX.index] > X[xBestValueIndex]) - O[iO] = itX[axis]; - } - - return O; - } - - /// - public virtual Tensor ArgMin(Tensor X, int axis) - { - var O = NewTensor(X.dataType, X.shape.Reduce(axis)); - - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - O[itO.index] = 0; - } - - for (var itX = new TensorIterator(X.shape); itX.IsValid(); itX.Next()) - { - int iO = itX.IndexInReducedShape(O.shape); - int xBestValueIndex = itX.IndexWithReplacedAxis(axis, (int) O[iO]); - if (X[itX.index] < X[xBestValueIndex]) - O[iO] = itX[axis]; - } - - return O; - } - - /// - public virtual Tensor ReduceSum(Tensor X, int axis) - { - var O = NewTensor(X.dataType, X.shape.Reduce(axis)); - - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - O[itO.index] = 0.0f; - } - for (var itX = new TensorIterator(X.shape); itX.IsValid(); itX.Next()) - { - O[itX.IndexInReducedShape(O.shape)] += X[itX.index]; - } - - return O; - } - - /// - public virtual Tensor ReduceMean(Tensor X, int axis) - { - var O = NewTensor(X.dataType, X.shape.Reduce(axis)); - - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - O[itO.index] = 0.0f; - } - for (var itX = new TensorIterator(X.shape); itX.IsValid(); itX.Next()) - { - O[itX.IndexInReducedShape(O.shape)] += X[itX.index]; - } - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - O[itO.index] /= X.shape[axis]; - } - - return O; - } - - /// - public virtual Tensor ReduceProd(Tensor X, int axis) - { - var O = NewTensor(X.dataType, X.shape.Reduce(axis)); - - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - O[itO.index] = 1.0f; - } - for (var itX = new TensorIterator(X.shape); itX.IsValid(); itX.Next()) - { - O[itX.IndexInReducedShape(O.shape)] *= X[itX.index]; - } - - return O; - } - - /// - private Tensor ApplyLogicalOperator(Tensor tensorA, Tensor tensorB, Func logicOp) - { - var O = NewTensorLike(new Tensor[] { tensorA, tensorB }, AllocScope.LayerOutput, false); - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - var A = tensorA[tensorA.IndexWithBroadcast(itO.d0, itO.d1, itO.d2, itO.d3, itO.d4, itO.d5, itO.d6, itO.d7)]; - var B = tensorB[tensorB.IndexWithBroadcast(itO.d0, itO.d1, itO.d2, itO.d3, itO.d4, itO.d5, itO.d6, itO.d7)]; - O[itO.index] = logicOp(A,B); - } - - return O; - } - - /// - public virtual Tensor Greater(Tensor A, Tensor B) - { - Func logicOp = (a, b) => Convert.ToSingle(a > b); - return ApplyLogicalOperator(A, B, logicOp); - } - - /// - public virtual Tensor GreaterEqual(Tensor A, Tensor B) - { - Func logicOp = (a, b) => Convert.ToSingle(a >= b); - return ApplyLogicalOperator(A, B, logicOp); - } - - /// - public virtual Tensor Less(Tensor A, Tensor B) - { - Func logicOp = (a, b) => Convert.ToSingle(a < b); - return ApplyLogicalOperator(A, B, logicOp); - } - - /// - public virtual Tensor LessEqual(Tensor A, Tensor B) - { - Func logicOp = (a, b) => Convert.ToSingle(a <= b); - return ApplyLogicalOperator(A, B, logicOp); - } - - /// - public virtual Tensor Equal(Tensor A, Tensor B) - { - Func logicOp = (a, b) => Convert.ToSingle(a == b); - return ApplyLogicalOperator(A, B, logicOp); - } - - /// - public virtual Tensor LogicalOr(Tensor A, Tensor B) - { - Func logicOp = (a, b) => Convert.ToSingle( Convert.ToBoolean(a) || Convert.ToBoolean(b) ); - return ApplyLogicalOperator(A, B, logicOp); - } - - /// - public virtual Tensor LogicalAnd(Tensor A, Tensor B) - { - Func logicOp = (a, b) => Convert.ToSingle( Convert.ToBoolean(a) && Convert.ToBoolean(b) ); - return ApplyLogicalOperator(A, B, logicOp); - } - - /// - public virtual Tensor LogicalXor(Tensor A, Tensor B) - { - Func logicOp = (a, b) => Convert.ToSingle( Convert.ToBoolean(a) ^ Convert.ToBoolean(b) ); - return ApplyLogicalOperator(A, B, logicOp); - } - - /// - public virtual Tensor LogicalNot(Tensor X) - { - var O = NewTensorLike(X); - var end = O.length; - for (int i = 0; i < end; ++i) - O[i] = Convert.ToSingle( !Convert.ToBoolean(X[i]) ); - return O; - } - - /// - public virtual Tensor Sign(Tensor X) - { - var O = NewTensorLike(X); - var end = O.length; - for (int i = 0; i < end; ++i) - O[i] = (X[i] > 0) ? 1.0f : ((X[i] < 0) ? -1.0f : 0.0f); - return O; - } - - /// - public virtual Tensor Where(Tensor C, Tensor A, Tensor B) - { - var O = NewTensorLike(new [] { C, A, B }, AllocScope.LayerOutput, false); - for (var itO = new TensorIterator(O.shape); itO.IsValid(); itO.Next()) - { - var x = A[A.IndexWithBroadcast(itO.d0, itO.d1, itO.d2, itO.d3, itO.d4, itO.d5, itO.d6, itO.d7)]; - var y = B[B.IndexWithBroadcast(itO.d0, itO.d1, itO.d2, itO.d3, itO.d4, itO.d5, itO.d6, itO.d7)]; - var c = C[C.IndexWithBroadcast(itO.d0, itO.d1, itO.d2, itO.d3, itO.d4, itO.d5, itO.d6, itO.d7)]; - O[itO.index] = Convert.ToBoolean(c) ? x : y; - } - - return O; - } - - /// - /// Copy and reshape `Tensor` - /// - /// input - /// shape - /// output `Tensor` - protected virtual Tensor CopyAndReshape(Tensor X, TensorShape shape) - { - Assert.AreEqual(X.length, shape.length); - var O = NewTensor(X.dataType, shape); - for (int i = 0; i < X.length; ++i) - O[i] = X[i]; - return O; - } - - /// - public virtual Tensor Copy(Tensor X) - { - // make shallow copy and patch the shape, if already managed by allocator - if (X.allocator != null) - return X.ShallowCopy(m_StringCache.Lookup("ShallowCopy of", X.name)); - - return CopyAndReshape(X, X.shape); - } - - /// - public virtual Tensor Flatten(Tensor X) - { - // make shallow copy and patch the shape, if already managed by allocator - if (X.allocator != null) - return X.Flatten(m_StringCache.Lookup("Flatten of", X.name)); - - // otherwise deep copy - var newShape = X.shape.Flatten(); - return CopyAndReshape(X, newShape); - } - - /// - public virtual Tensor Reshape(Tensor X, TensorShape newShape) - { - // if already managed by allocator, can do a shallow copy - bool canDoShallowCopy = X.allocator != null; - - // in most case layer needing storage should use there own - // allocator to avoid memory fragmentation in the long run. - // Here we disallow shallow copy in that case here to help. - // Would be better to verify if target and source allocator - // are the same but storage/reshape-to-storage is an uncommon case. - var varsWithReuse = m_Allocator as GenericVarsWithReuse; - canDoShallowCopy &= varsWithReuse != null && - !varsWithReuse.layerRequiresStorage; - - // however if tensor is on GPU and in channel first memory layout we can't (reshape is actually a transpose in that case) - var onDeviceComputeTensorData = X.tensorOnDevice as ComputeTensorData; - canDoShallowCopy &= onDeviceComputeTensorData == null || - onDeviceComputeTensorData.channelsOrder == ComputeInfo.ChannelsOrder.NHWC; - - if (canDoShallowCopy) - return X.Reshape(newShape, m_StringCache.Lookup("Reshape of", X.name)); - - // otherwise deep copy - return CopyAndReshape(X, newShape); - } - - /// - public virtual Tensor Expand(Tensor X, TensorShape newShape) - { - // scale is either 1 or 0 in case of expansion - int[] s = new int[TensorShape.MaxRank]; - for(int i = 0; i < TensorShape.MaxRank; ++i) - s[i] = X.shape[i] / newShape[i]; - - for (int i = 0; i < TensorShape.MaxRank; ++i) - { - Assert.IsTrue(newShape[i] == X.shape[i] || X.shape[i] == 1); - Assert.IsTrue(s[i] == 0 || s[i] == 1); - } - - var O = NewTensor(X.dataType, newShape); - Assert.AreEqual(8, TensorShape.MaxRank); - for (var it = new TensorIterator(newShape); it.IsValid(); it.Next()) - { - // sample either from dim or index 0 in case of expansion - O[it.index] = X[s[0]*it.d0, s[1]*it.d1, s[2]*it.d2, s[3]*it.d3, s[4]*it.d4, s[5]*it.d5, s[6]*it.d6, s[7]*it.d7]; - } - - return O; - } - - /// - public virtual Tensor Gather(Tensor[] tensors, int axis) - { - Tensor X = tensors[0]; - Tensor indices = tensors[1]; - - var shape = X.shape; - shape[axis] = indices.length; - - var O = NewTensor(X.dataType, shape); - - Assert.AreEqual(TensorShape.MaxRank, 8); - for (var it = new TensorIterator(shape); it.IsValid(); it.Next()) - { - int d0 = (axis == 0) ? (int) indices[it.d0] : it.d0; - int d1 = (axis == 1) ? (int) indices[it.d1] : it.d1; - int d2 = (axis == 2) ? (int) indices[it.d2] : it.d2; - int d3 = (axis == 3) ? (int) indices[it.d3] : it.d3; - int d4 = (axis == 4) ? (int) indices[it.d4] : it.d4; - int d5 = (axis == 5) ? (int) indices[it.d5] : it.d5; - int d6 = (axis == 6) ? (int) indices[it.d6] : it.d6; - int d7 = (axis == 7) ? (int) indices[it.d7] : it.d7; - O[it.index] = X[d0, d1, d2, d3, d4, d5, d6, d7]; - } - return O; - } - - public virtual Tensor ScatterND(Tensor X, Tensor indices, Tensor updates, Layer.ScatterNDReductionMode reduction) - { - // only support for scattering on C for now - Assert.IsTrue(indices.batch == X.batch); - Assert.IsTrue(updates.width == X.width && updates.height == X.height); - var outputShape = X.shape; - - var O = NewTensor(X.dataType, outputShape); - - for (var n = 0; n < O.batch; ++n) - for (var h = 0; h < O.height; ++h) - for (var w = 0; w < O.width; ++w) - for (var c = 0; c < O.channels; ++c) - { - float v = X[n, h, w, c]; - O[n, h, w, c] = v; - - for (int idx = 0; idx < indices.flatWidth; idx++) - { - int indexRemap = (int)(indices[idx]); - if (c != indexRemap) - continue; - - float vw = updates[n % updates.batch, h % updates.height, w % updates.width, idx % updates.channels]; - - int indexWrite = O.Index(n, h, w, indexRemap); - if (reduction == Layer.ScatterNDReductionMode.None) - { - O[indexWrite] = vw; - } - else if (reduction == Layer.ScatterNDReductionMode.Add) - { - O[indexWrite] += vw; - } - else if (reduction == Layer.ScatterNDReductionMode.Mul) - { - O[indexWrite] *= vw; - } - } - } - - return O; - } - - /// - public Tensor NonMaxSuppression(Tensor[] tensors, int maxOutputBoxesPerClass, float iouThreshold, float scoreThreshold, int centerPointBox) - { - // ONNX: https://github.com/onnx/onnx/blob/master/docs/Operators.md#NonMaxSuppression - // ORT reference: https://github.com/microsoft/onnxruntime/blob/464bbd27a939ebc73bfd7fe3eea0eeb93a76e56b/onnxruntime/core/providers/cpu/object_detection/non_max_suppression.cc - // PyTorch: https://pytorch.org/docs/stable/_modules/torchvision/ops/boxes.html#nms - var boxes = tensors[0]; - var scores = tensors[1]; - - Assert.IsTrue(boxes.shape.Is4D());//should be rank 3 - Assert.IsTrue(scores.shape.Is4D());//should be rank 3 - - int boxCount = Mathf.Min(boxes.channels, scores.width); // Box spatial dimension (C) / Score spatial dimension (W) - var boxIndices = new List(boxCount); - var selectedIndices = new List<(int, int, int)>(); // batch index, class index, box index - var classSelectedIndices = new List<(int, int, int)>(); // batch index, class index, box index - var S = new List(); - - for (int n = 0; n < scores.batch; n++) - { - // Iterate over each class - for (int c = 0; c < scores.channels; c++) - { - classSelectedIndices.Clear(); - - boxIndices.Clear(); - S.Clear(); - for (int b = 0; b < boxCount; b++) - { - float score = scores[n, 0, b, c]; - if (score > scoreThreshold) - { - S.Add(score); - boxIndices.Add(b); - } - } - - while (boxIndices.Any() && classSelectedIndices.Count < maxOutputBoxesPerClass) - { - float maxScore = float.MinValue; - int relativeIndex = 0; - for (int i = 0; i < S.Count; i++) - { - float score = S[i]; - if (score > maxScore) - { - maxScore = score; - relativeIndex = i; - } - } - - int m = boxIndices[relativeIndex]; // Get absolute index from relative index since the working sets change - Rect M = centerPointBox == 0 ? GetRect(boxes, n, m) : GetRectFromCenter(boxes, n, m); - - boxIndices.RemoveAt(relativeIndex); - S.RemoveAt(relativeIndex); - - // Suppress this box if IOU with another box exceeds threshold - var selected = true; - foreach (var (_, _, otherIndex) in classSelectedIndices) - { - Rect b = centerPointBox == 0 ? GetRect(boxes, n, otherIndex) : GetRectFromCenter(boxes, n, otherIndex); - if (M.Overlaps(b) && GetIntersectionOverUnionArea(M, b) > iouThreshold) - { - selected = false; - break; - } - } - - if (selected) - classSelectedIndices.Add((n, c, m)); - } - - // Collect what was selected for this class - selectedIndices.AddRange(classSelectedIndices); - } - } - - var O = NewTensor(boxes.dataType, new TensorShape(new [] {selectedIndices.Count, 1, 1, 3})); - if (selectedIndices.Count > 0) - { - for (var i = 0; i < selectedIndices.Count; i++) - { - (int batchIndex, int classIndex, int boxIndex) = selectedIndices[i]; - O[i, 0] = batchIndex; - O[i, 1] = classIndex; - O[i, 2] = boxIndex; - } - } - else - { - // TODO: Remove this when empty tensors are supported - // See https://github.com/Unity-Technologies/barracuda-release/issues/173#issuecomment-837352917 - O.Fill(-1f); - } - - return O; - - float GetIntersectionOverUnionArea(Rect a, Rect b) - { - var intersectionArea = GetIntersectionArea(a, b); - return intersectionArea / (a.width * a.height + b.width * b.height - intersectionArea); - } - - float GetIntersectionArea(Rect a, Rect b) - { - float xMin = Mathf.Max(a.xMin, b.xMin); - float yMin = Mathf.Max(a.yMin, b.yMin); - float xMax = Mathf.Min(a.xMax, b.xMax); - float yMax = Mathf.Min(a.yMax, b.yMax); - - var rect = Rect.MinMaxRect(xMin, yMin, xMax, yMax); - return Math.Max(rect.width, 0) * Math.Max(rect.height, 0); // Non-overlapping rects will have negative width / height - } - - Rect GetRect(Tensor t, int batch, int index) - { - TensorShape tShape = t.shape; - float x1 = t[tShape.Index(batch, 0, 1, index)]; - float y1 = t[tShape.Index(batch, 0, 0, index)]; - float x2 = t[tShape.Index(batch, 0, 3, index)]; - float y2 = t[tShape.Index(batch, 0, 2, index)]; - - // Correct flipped coordinates - if (x1 > x2) - { - float temp = x1; - x1 = x2; - x2 = temp; - } - - if (y1 > y2) - { - float temp = y1; - y1 = y2; - y2 = temp; - } - - return Rect.MinMaxRect(x1, y1, x2, y2); - } - - Rect GetRectFromCenter(Tensor t, int batch, int index) - { - TensorShape tShape = t.shape; - float xCenter = t[tShape.Index(batch, 0, 0, index)]; - float yCenter = t[tShape.Index(batch, 0, 1, index)]; - float width = t[tShape.Index(batch, 0, 2, index)]; - float height = t[tShape.Index(batch, 0, 3, index)]; - - float halfWidth = width * 0.5f; - float halfHeight = height * 0.5f; - - return new Rect(xCenter - halfWidth, yCenter - halfHeight, width, height); - } - } - - /// - public virtual Tensor[] LSTM(Tensor X, Tensor[] W, Tensor[] R, Tensor[] Wb, Tensor[] Rb, Tensor hidden, Tensor cell) - { - // Gate indices [iofj] - const int g_i = 0, g_o = 1, g_f = 2, g_j = 3; - - TensorShape xShape = X.shape; - int sequenceLength = xShape.batch; // X shape is [seq_length, batch_size, input_size] - - Tensor O = null; - - for (int s = 0; s < sequenceLength; s++) - { - using (var td = new TensorScope()) // This will dispose every sequence iteration - { - TensorScope.F _ = td._; // Shorthand - Tensor X_sequence = _(StridedSlice(X, new[] { s, 0, 0, 0 }, new[] { s + 1, int.MaxValue, int.MaxValue, int.MaxValue }, new[] { 1, 1, 1, 1 })); - - // Convert to [batch_size, input_size], dropping sequence axis - X_sequence = _(Transpose(X_sequence, new[] { 3, 0, 1, 2 })); - - var i_mad_w = _(Add(new[] { _(MatMul(X_sequence, false, W[g_i], false)), Wb[g_i] })); - var i_mad_r = _(Add(new[] { _(MatMul(hidden, false, R[g_i], false)), Rb[g_i] })); - var i_mad = _(Add(new[] { i_mad_w, i_mad_r })); - - var j_mad_w = _(Add(new[] { _(MatMul(X_sequence, false, W[g_j], false)), Wb[g_j] })); - var j_mad_r = _(Add(new[] { _(MatMul(hidden, false, R[g_j], false)), Rb[g_j] })); - var j_mad = _(Add(new[] { j_mad_w, j_mad_r })); - - var f_mad_w = _(Add(new[] { _(MatMul(X_sequence, false, W[g_f], false)), Wb[g_f] })); - var f_mad_r = _(Add(new[] { _(MatMul(hidden, false, R[g_f], false)), Rb[g_f] })); - var f_mad = _(Add(new[] { f_mad_w, f_mad_r })); - - var o_mad_w = _(Add(new[] { _(MatMul(X_sequence, false, W[g_o], false)), Wb[g_o] })); - var o_mad_r = _(Add(new[] { _(MatMul(hidden, false, R[g_o], false)), Rb[g_o] })); - var o_mad = _(Add(new[] { o_mad_w, o_mad_r })); - - var i = _(Sigmoid(i_mad)); - var j = _(Tanh(j_mad)); - var f = _(Sigmoid(f_mad)); - var o = _(Sigmoid(o_mad)); - - var state_c_mul = _(Mul(new[] { cell, f })); - var i_j_mul = _(Mul(new[] { i, j })); - var state_c = Add(new[] { state_c_mul, i_j_mul }); // Not disposed automatically - var state_c_tanh = _(Tanh(state_c)); - var state_h = Mul(new[] { o, state_c_tanh }); // Not disposed automatically - - // Must be in the shape [num_directions=1, batch_size, hidden_size] - Tensor reshaped_state_h = Reshape(state_h, new TensorShape(1, state_h.batch, state_h.channels, 1)); - if (O == null) - O = reshaped_state_h; - else - O = Concat(new[] { _(O), _(reshaped_state_h) }, TensorShape.DataBatch); - - // Collect previous memories before assigning new ones. - // Don't dispose the original hidden / cell memories since those were input tensors - if (s != 0) - { - _(hidden); - _(cell); - } - - hidden = state_h; - cell = state_c; - } - } - - return new[] { O, hidden, cell }; - } - - /// - public virtual Tensor Transpose(Tensor X) - { - // TODO: reshape when possible - Assert.IsTrue(X.dimensions <= 2); - X = Flatten(X); - - var O = NewTensor(X.dataType, X.flatWidth, X.flatHeight); - - for (int y = 0; y < O.flatHeight; ++y) - for (int x = 0; x < O.flatWidth; ++x) - O[y, x] = X[x, y]; - - return O; - } - - /// - public virtual Tensor Transpose(Tensor X, int[] permutations) - { - permutations = TensorExtensions.Get8DPermutationsForNHWCPermutationsAndShape(X.shape, permutations); - var O = NewTensor(X.dataType, X.shape.Permute(permutations)); - - Assert.AreEqual(TensorShape.MaxRank, 8); - for (var it = new TensorIterator(X); it.IsValid(); it.Next()) - { - O[ it[permutations[0]], it[permutations[1]], - it[permutations[2]], it[permutations[3]], - it[permutations[4]], it[permutations[5]], - it[permutations[6]], it[permutations[7]]] = X[it.index]; - } - return O; - } - - /// - public virtual Tensor Prepare(Tensor X) - { - X.PrepareCacheForAccess(); - return X; - } - - /// - public virtual Tensor PrepareNoAlloc(Tensor X) - { - // reference op 0-initalize tensors - X.PrepareCacheForAccess(); - return X; - } -} - -internal class MathfEx -{ - internal static float Tanh(float x) - { - // tanh = (exp(2*x) - 1) / (exp(2*x) + 1) - - // Constant taken from http://llvm.org/svn/llvm-project/libclc/trunk/generic/lib/math/tanh.cl - // const float large_threshold = 0x1.0a2b24p+3f; - const float LargeThreshold = 8.317766f; - - // See also: https://stackoverflow.com/questions/34835641/tanh-returning-nan-for-large-input - - // Handle edge-cases to prevent NaNs creeping in - if (x >= LargeThreshold || x <= -LargeThreshold) - return Mathf.Sign(x); - - float exp2 = Mathf.Exp(2f * x); - return (exp2 - 1f) / (exp2 + 1f); - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCPU.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCPU.cs.meta deleted file mode 100644 index d12ae3a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCPU.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: e7398940fb81d45ee8e648e0b0f467f2 -timeCreated: 1503433373 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCompute.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCompute.cs deleted file mode 100644 index 49d7bdf..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCompute.cs +++ /dev/null @@ -1,2715 +0,0 @@ -//#define DEBUG_TRACK_ALLOCATIONS - -using UnityEngine; -using UnityEngine.Rendering; -using UnityEngine.Experimental.Rendering; // AsyncGPUReadback -using UnityEngine.Assertions; -using UnityEngine.Profiling; -using System; -using System.Linq; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -[assembly: InternalsVisibleTo("Barracuda.EditorTests")] - -namespace Unity.Barracuda { - -internal static class ComputeHelper -{ - public static int IDivC(int v, int div) - { - return (v + div - 1) / div; - } -} - -/// -/// `Tensor` data storage for GPU backends -/// -public class ComputeTensorData : UniqueResourceId, ITensorData -{ - private bool m_DisposeBufferAfterUse; - private ComputeBuffer m_Buffer; - private TensorShape m_Shape; - private int m_Offset; - private ComputeInfo.ChannelsOrder m_OnDeviceChannelsOrder; - - /// - /// Data storage as `ComputeBuffer` - /// - public ComputeBuffer buffer { get { return m_Buffer; } } - - /// - /// Offset in the data storage buffer - /// - public int offset { get { return m_Offset; } } - - /// - /// Parent `Tensor` name - /// - public string name; - - /// - /// Channel order channels-first vs channels-last - /// - public ComputeInfo.ChannelsOrder channelsOrder { get { return m_OnDeviceChannelsOrder; } } - -#if DEBUG_TRACK_ALLOCATIONS - protected StackTrace m_AllocationTrace; -#endif - - /// - /// Create `ComputeTensorData` - /// - /// shape - /// buffer name - /// channel order - /// clear on init - public ComputeTensorData(TensorShape shape, string buffername, ComputeInfo.ChannelsOrder onDeviceChannelsOrder, bool clearOnInit = true) - { - m_OnDeviceChannelsOrder = onDeviceChannelsOrder; - name = buffername; - m_Buffer = new ComputeBuffer(shape.length, sizeof(float)); - - // @TODO: consider zero initialization only for "debug" mode - if (clearOnInit) - { - float[] zeros = new float[shape.length]; - m_Buffer.SetData(zeros); - } - - m_Shape = shape; - m_Offset = 0; - - m_DisposeBufferAfterUse = true; - -#if DEBUG_TRACK_ALLOCATIONS - m_AllocationTrace = new System.Diagnostics.StackTrace(); -#endif - } - - /// - /// Create `ComputeTensorData` with specified `buffer` - /// - /// buffer - /// shape - /// offset - /// buffer name - /// channels order - internal ComputeTensorData(ComputeBuffer buffer, TensorShape shape, int offset, string buffername, ComputeInfo.ChannelsOrder onDeviceChannelsOrder) - { - m_OnDeviceChannelsOrder = onDeviceChannelsOrder; - name = buffername; - m_Buffer = buffer; - m_Shape = shape; - m_Offset = offset; - - m_DisposeBufferAfterUse = false; - } - - /// - /// Finalizer - /// - ~ComputeTensorData() - { - if (m_Buffer == null) - return; - if (!m_DisposeBufferAfterUse) - return; - - D.LogWarning($"Found unreferenced, but undisposed Tensor data which might lead to GPU resource leak: {ToString()}"); - - Dispose(); - } - - /// - /// Dispose internal storage - /// - public virtual void Dispose() - { - if (m_DisposeBufferAfterUse) - { - m_Buffer.Dispose(); - m_Buffer = null; - } - m_DisposeBufferAfterUse = false; - } - - /// - public virtual void Reserve(int count) - { - if (count > maxCapacity) - throw new ArgumentException("ComputeTensorData buffer is too small to reserve " + count + " elements."); - } - - /// - public virtual void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0) - { - var numItemToCopy = shape.length; - var numItemAvailableInData = data.Length - managedBufferStartIndex; - - Assert.IsTrue(managedBufferStartIndex >= 0); - Assert.IsTrue(numItemToCopy <= numItemAvailableInData); - - if (m_OnDeviceChannelsOrder == ComputeInfo.ChannelsOrder.NCHW) - { - //Transpose from HWC to CHW, TODO use a compute shader or threaded code. - Profiler.BeginSample("Tensor.Upload_ChannelFirstTranpose"); - float[] chwData = new float[numItemToCopy]; - if (shape.Is4D()) - { - for (int readIndex=0; readIndex < numItemToCopy; ++readIndex) - { - int b = 0, h = 0, w = 0, ch = 0; - shape.GetPositionsFromIndex(readIndex, ref b, ref h, ref w, ref ch); - int writeIndex = shape.IndexChannelFirst(b, h, w, ch); - chwData[writeIndex] = data[managedBufferStartIndex+readIndex]; - } - } - else - { - for (int readIndex=0; readIndex < numItemToCopy; ++readIndex) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, ch = 0; - shape.GetPositionsFromIndex(readIndex, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref ch); - int writeIndex = shape.IndexChannelFirst(s, r, n, t, d, h, w, ch); - chwData[writeIndex] = data[managedBufferStartIndex+readIndex]; - } - } - Profiler.EndSample(); - m_Buffer.SetData(chwData, 0, m_Offset, numItemToCopy); - } - else - { - m_Buffer.SetData(data, managedBufferStartIndex, m_Offset, numItemToCopy); - } - - m_AsyncDownloadSchedulingFrame = -1; - #if UNITY_2018_2_OR_NEWER - m_AsyncDownloadRequested = false; - #endif - } - - /// - public virtual bool ScheduleAsyncDownload(int count) - { - #if UNITY_2018_2_OR_NEWER - if (SystemInfo.supportsAsyncGPUReadback) - return WaitForAsyncReadback(count); - #endif - - return WaitFor3Frames(count); - } - - private int m_AsyncDownloadSchedulingFrame = -1; - private bool WaitFor3Frames(int count) - { - if (m_AsyncDownloadSchedulingFrame < 0) - m_AsyncDownloadSchedulingFrame = Time.frameCount; - var framesPassed = Time.frameCount - m_AsyncDownloadSchedulingFrame; - return framesPassed > 3; - } - - #if UNITY_2018_2_OR_NEWER - private bool m_AsyncDownloadRequested = false; - private AsyncGPUReadbackRequest m_AsyncDownloadRequest; - private bool WaitForAsyncReadback(int count) - { - if (m_AsyncDownloadRequested) - { - if (m_AsyncDownloadRequest.hasError) - m_AsyncDownloadRequested = false; - else - m_AsyncDownloadRequest.Update(); - } - - if (!m_AsyncDownloadRequested) - { - m_AsyncDownloadRequest = AsyncGPUReadback.Request(m_Buffer, count * sizeof(float), m_Offset * sizeof(float)); - m_AsyncDownloadRequested = true; - } - - return m_AsyncDownloadRequest.done; - } - #endif - - private ConvertFromOnDeviceFormatHelper m_ConvertFromOnDeviceFormatHelper = new ConvertFromOnDeviceFormatHelper(); - private float[] ConvertFromOnDeviceFormat(TensorShape shape, float[] data) - { - return m_ConvertFromOnDeviceFormatHelper.GetNHWCData(shape, data, m_OnDeviceChannelsOrder); - } - - private unsafe class ConvertFromOnDeviceFormatHelper - { - private float* oPtr; - private float* xPtr; - private TensorShape shape; - private int unrollSize = 4; - public Action unrolledInnerLoopDelegate; - - internal ConvertFromOnDeviceFormatHelper() - { - unrolledInnerLoopDelegate = UnrolledInnerLoop; - } - - internal float[] GetNHWCData(TensorShape shape, float[] data, ComputeInfo.ChannelsOrder onDeviceFormat, bool useRefImplementation = false) - { - //tensor is HWC on device, no need to concert. - if (onDeviceFormat == ComputeInfo.ChannelsOrder.NHWC) - return data; - - //tensor is flat in regard to CHW, no need to convert. - var channelOrderRelatedDimensions = 0; - for (int i = TensorShape.DataBatch + 1; i < TensorShape.MaxRank; ++i) - { - if (shape[i] > 1) - ++channelOrderRelatedDimensions; - } - if (channelOrderRelatedDimensions == 1) - return data; - - //else allocate new buffer, apply conversion and return it. - float[] hwcData = new float[shape.length]; - if (!useRefImplementation) - { - unsafe - { - fixed (float* xPtr = &data[0], oPtr = &hwcData[0]) - { - this.oPtr = oPtr; - this.xPtr = xPtr; - this.shape = shape; - ApplyConversion(); - } - } - } - else - { - for (int readIndex=0; readIndex < data.Length; ++readIndex) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - shape.GetPositionsFromIndexChannelFirst(readIndex, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - int writeIndex = shape.Index(s,r,n,t,d,h,w,c); - hwcData[writeIndex] = data[readIndex]; - } - } - - return hwcData; - } - - private void ApplyConversion() - { - UnsafeArrayCPUOps.Parallel_For(0L, shape.length / unrollSize, unrolledInnerLoopDelegate); - - // Remainder - for (int i = (shape.length / unrollSize) * unrollSize; i < shape.length; ++i) - { - int s = 0, r = 0, n = 0, t = 0, d = 0, h = 0, w = 0, c = 0; - shape.GetPositionsFromIndexChannelFirst(i, ref s, ref r, ref n, ref t, ref d, ref h, ref w, ref c); - int writeIndex = shape.Index(s,r,n,t,d,h,w,c); - oPtr[writeIndex] = xPtr[i]; - } - } - - private void UnrolledInnerLoop(long n) - { - int baseIndex = (int)n * 4; - int s0 = 0, r0 = 0, n0 = 0, t0 = 0, d0 = 0, h0 = 0, w0 = 0, c0 = 0; - int s1 = 0, r1 = 0, n1 = 0, t1 = 0, d1 = 0, h1 = 0, w1 = 0, c1 = 0; - int s2 = 0, r2 = 0, n2 = 0, t2 = 0, d2 = 0, h2 = 0, w2 = 0, c2 = 0; - int s3 = 0, r3 = 0, n3 = 0, t3 = 0, d3 = 0, h3 = 0, w3 = 0, c3 = 0; - shape.GetPositionsFromIndexChannelFirst(baseIndex+0, ref s0, ref r0, ref n0, ref t0, ref d0, ref h0, ref w0, ref c0); - shape.GetPositionsFromIndexChannelFirst(baseIndex+1, ref s1, ref r1, ref n1, ref t1, ref d1, ref h1, ref w1, ref c1); - shape.GetPositionsFromIndexChannelFirst(baseIndex+2, ref s2, ref r2, ref n2, ref t2, ref d2, ref h2, ref w2, ref c2); - shape.GetPositionsFromIndexChannelFirst(baseIndex+3, ref s3, ref r3, ref n3, ref t3, ref d3, ref h3, ref w3, ref c3); - int writeIndex0 = shape.Index(s0, r0, n0, t0, d0, h0, w0, c0); - int writeIndex1 = shape.Index(s1, r1, n1, t1, d1, h1, w1, c1); - int writeIndex2 = shape.Index(s2, r2, n2, t2, d2, h2, w2, c2); - int writeIndex3 = shape.Index(s3, r3, n3, t3, d3, h3, w3, c3); - oPtr[writeIndex0] = xPtr[baseIndex+0]; - oPtr[writeIndex1] = xPtr[baseIndex+1]; - oPtr[writeIndex2] = xPtr[baseIndex+2]; - oPtr[writeIndex3] = xPtr[baseIndex+3]; - } - } - - /// - public virtual float[] Download(TensorShape shape) - { - //;;D.logStackTraceEnabled = true; - //;;Debug.Log("Download ComputeTensorData " + name + " " + maxCapacity + " " + count); - //;;D.logStackTraceEnabled = false; - - var count = shape.length; - - Profiler.BeginSample("Barracuda.DownloadDataFromGPU"); - Assert.IsTrue(maxCapacity >= count); - count = Math.Min(maxCapacity, count); - - m_AsyncDownloadSchedulingFrame = -1; - #if UNITY_2018_2_OR_NEWER - if (m_AsyncDownloadRequested) - { - m_AsyncDownloadRequested = false; - if (!m_AsyncDownloadRequest.done) - m_AsyncDownloadRequest.WaitForCompletion(); - - if (!m_AsyncDownloadRequest.hasError) - { - var reqData = m_AsyncDownloadRequest.GetData().ToArray(); - if (reqData.Length >= count) - { // if we have retrieved enough data - reqData = ConvertFromOnDeviceFormat(shape, reqData); - Profiler.EndSample(); - return reqData; - } - } - } - #endif - - bool isAndroidPlayer = false; - #if UNITY_ANDROID - isAndroidPlayer = true; - #endif - - var data = new float[count]; - if (isAndroidPlayer && m_Offset != 0) - { - //On mobile GetData does not take m_Offset into account, need a full download. - var fullData = new float[m_Buffer.count]; - m_Buffer.GetData(fullData); - Array.Copy(fullData, m_Offset, data, 0, count); - } - else - { - m_Buffer.GetData(data, 0, m_Offset, count); - } - - data = ConvertFromOnDeviceFormat(shape, data); - Profiler.EndSample(); - - return data; - } - - /// - public virtual BarracudaArray SharedAccess(out int offset) - { - offset = 0; - return new BarracudaArrayFromManagedArray(Download(new TensorShape(0, 0, 0, maxCapacity)));//TODO fp16 - } - - /// - public virtual int maxCapacity => m_Shape.length; - - /// - public virtual DataType dataType => DataType.Float; //todo fp16 - - /// - public virtual bool inUse => true; - - /// - public virtual bool isGPUMem => true; - - /// - /// Summary - /// - /// summary - public override string ToString() - { - string allocationSource = ""; - -#if DEBUG_TRACK_ALLOCATIONS - allocationSource += "\nSource:\n" + m_AllocationTrace; -#endif - - return string.Format("(GPU:{0}#{1} {2} buffer: {3} created at: {4})", - name, GetHashCode(), m_Shape, m_Buffer, allocationSource); - } -} - -internal class SharedComputeTensorData : ComputeTensorData -{ - public SharedComputeTensorData(ComputeBuffer buffer, TensorShape shape, int offset, string buffername = "", ComputeInfo.ChannelsOrder channelsOrder = ComputeInfo.ChannelsOrder.NHWC) : base(buffer, shape, offset, buffername, channelsOrder) {} -} - -internal class TextureFormatUtils -{ - public static bool IsRedOnly(TextureFormat format) - { - return format == TextureFormat.R8 || - format == TextureFormat.R16 || - format == TextureFormat.RHalf || - format == TextureFormat.RFloat || - format == TextureFormat.BC4 || - format == TextureFormat.EAC_R || - format == TextureFormat.EAC_R_SIGNED; - } - - public static bool IsRedOnly(RenderTextureFormat format) - { - return format == RenderTextureFormat.R8 || - format == RenderTextureFormat.R16 || - format == RenderTextureFormat.RHalf || - format == RenderTextureFormat.RFloat; - } - - public static bool IsRedGreen(TextureFormat format) - { - return format == TextureFormat.RG16 || - format == TextureFormat.RGHalf || - format == TextureFormat.RGFloat || - format == TextureFormat.BC5 || - format == TextureFormat.EAC_RG || - format == TextureFormat.EAC_RG_SIGNED; - } - - public static bool IsRedGreen(RenderTextureFormat format) - { - return format == RenderTextureFormat.RG16 || - format == RenderTextureFormat.RGHalf || - format == RenderTextureFormat.RGFloat; - } - - public static bool IsRedGreenBlue(TextureFormat format) - { - return format == TextureFormat.RGB565 || - format == TextureFormat.RGB24 || - format == TextureFormat.DXT1 || - #if !UNITY_IOS - format == TextureFormat.DXT1Crunched || - #endif - format == TextureFormat.PVRTC_RGB2 || - format == TextureFormat.PVRTC_RGB4 || - format == TextureFormat.ETC_RGB4 || - #if !UNITY_IOS - format == TextureFormat.ETC_RGB4Crunched || - #endif - format == TextureFormat.ETC2_RGB || - #if UNITY_2019_1_OR_NEWER - format == TextureFormat.ASTC_4x4 || - format == TextureFormat.ASTC_5x5 || - format == TextureFormat.ASTC_6x6 || - format == TextureFormat.ASTC_8x8 || - format == TextureFormat.ASTC_10x10 || - format == TextureFormat.ASTC_12x12 || - #else - format == TextureFormat.ASTC_RGB_4x4 || - format == TextureFormat.ASTC_RGB_5x5 || - format == TextureFormat.ASTC_RGB_6x6 || - format == TextureFormat.ASTC_RGB_8x8 || - format == TextureFormat.ASTC_RGB_10x10 || - format == TextureFormat.ASTC_RGB_12x12 || - #endif - format == TextureFormat.BC6H; - } - - public static bool IsRedGreenBlue(RenderTextureFormat format) - { - return format == RenderTextureFormat.RGB565 || - format == RenderTextureFormat.BGR101010_XR; - } - - public static bool IsAlphaOnly(Texture tex) - { - var tex2D = tex as Texture2D; - var texArr = tex as Texture2DArray; - var tex3D = tex as Texture3D; - if (tex2D != null) - return tex2D.format == TextureFormat.Alpha8; - else if (texArr != null) - return texArr.format == TextureFormat.Alpha8; - else if (tex3D != null) - return tex3D.format == TextureFormat.Alpha8; - else - return false; - } - - public static bool IsRedOnly(Texture tex) - { - var tex2D = tex as Texture2D; - var texArr = tex as Texture2DArray; - var tex3D = tex as Texture3D; - var rt = tex as RenderTexture; - - if (tex2D != null) - return IsRedOnly(tex2D.format); - else if (texArr != null) - return IsRedOnly(texArr.format); - else if (tex3D != null) - return IsRedOnly(tex3D.format); - else if (rt != null) - return IsRedOnly(rt.format); - else - return false; - } - - public static bool IsRedGreen(Texture tex) - { - var tex2D = tex as Texture2D; - var texArr = tex as Texture2DArray; - var tex3D = tex as Texture3D; - var rt = tex as RenderTexture; - - if (tex2D != null) - return IsRedGreen(tex2D.format); - else if (texArr != null) - return IsRedGreen(texArr.format); - else if (tex3D != null) - return IsRedGreen(tex3D.format); - else if (rt != null) - return IsRedGreen(rt.format); - else - return false; - } - - public static bool IsRedGreenBlue(Texture tex) - { - var tex2D = tex as Texture2D; - var texArr = tex as Texture2DArray; - var tex3D = tex as Texture3D; - var rt = tex as RenderTexture; - - if (tex2D != null) - return IsRedGreenBlue(tex2D.format); - else if (texArr != null) - return IsRedGreenBlue(texArr.format); - else if (tex3D != null) - return IsRedGreenBlue(tex3D.format); - else if (rt != null) - return IsRedGreenBlue(rt.format); - else - return false; - } - - public static int FormatToChannelCount(Texture tex) - { - if (IsRedOnly(tex)) - return 1; - if (IsAlphaOnly(tex)) - return 1; - if (IsRedGreen(tex)) - return 2; - if (IsRedGreenBlue(tex)) - return 3; - return 4; - } - - public static int[] FormatToChannelMask(Texture tex, int interpretPixelAsChannels) - { - switch (interpretPixelAsChannels) - { - case 1: - if (IsRedOnly(tex)) - return new [] { 1,0,0,0 }; - if (IsAlphaOnly(tex)) - return new [] { 0,0,0,1 }; - // TODO: known issue, doesn't handle RG textures properly - return new [] { 0,0,0,0 }; // see specialCaseWhenChannelMaskIsEmptyStoresAverage - case 2: - return new [] { 1,1,0,0 }; - case 3: - return new [] { 1,1,1,0 }; - default: - return new [] { 1,1,1,1 }; - } - } - - public static int[] FormatToChannelReadMap(Texture tex, int interpretPixelAsChannels) - { - // -1 == use default channel value, otherwise channel index - - if (IsRedOnly(tex)) - return new[] { 0, -1, -1, -1 }; - if (IsAlphaOnly(tex)) - return new[] { -1, -1, -1, 3 }; - - switch (interpretPixelAsChannels) - { - case 1: - // TODO: known issue, doesn't handle RG textures properly - return new [] { -1,-1,-1,-1 }; // see specialCaseWhenChannelMaskIsEmptyStoresAverage - case 2: - return new[] { 0, 1, -1, -1 }; - case 3: - return new[] { 0, 1, 2, -1 }; - default: - return new[] { 0, 1, 2, 3 }; - } - } -} - -/// -/// Reference GPU compute `IOps` implementation -/// -public class ReferenceComputeOps : ReferenceCPUOps -{ - /// - /// Create `ReferenceComputeOps` - /// - /// allocator - public ReferenceComputeOps(ITensorAllocator allocator = null) - : base(allocator) - { - } - - /// - /// Pin `Tensor` to GPU compute device, if `uploadCache` is false, data is not uploaded to device and `Tensor` is not 0-filled - /// - /// `Tensor` - /// `bool` - /// `ComputeTensorData` - /// - public ComputeTensorData Pin(Tensor X, bool uploadCache = true) - { - X.FlushCache(uploadCache); - - var onDevice = X.tensorOnDevice as ComputeTensorData; - if (onDevice == null) - { - var asTexture = X.tensorOnDevice as TextureAsTensorData; - if (asTexture != null) - X.AttachToDevice(TextureToTensorData(asTexture, X.name)); - else - { - if (uploadCache) - X.UploadToDevice(new ComputeTensorData(X.shape, X.name, ComputeInfo.channelsOrder)); // device is not compatible, create new array and upload - else - X.AllocateOnDevice(new ComputeTensorData(X.shape, X.name, ComputeInfo.channelsOrder, false)); // device is not compatible, create new array but do not upload nor 0-fill - } - } - - Assert.IsNotNull(X.tensorOnDevice as ComputeTensorData); - Assert.IsNotNull((X.tensorOnDevice as ComputeTensorData).buffer); - - return X.tensorOnDevice as ComputeTensorData; - } - - internal void SetTensor(ComputeFunc fn, string name, Tensor X) - { - var XonDevice = Pin(X); - fn.SetTensor(name, X.shape, XonDevice.buffer, XonDevice.offset); - } - - internal Tensor NewTensor(ComputeFunc fn, string name, DataType dataType, TensorShape shape, AllocScope scope = AllocScope.LayerOutput) - { - var o = NewTensor(dataType, shape, scope, name); - fn.SetTensor(name, shape, Pin(o).buffer); - return o; - } - - internal Tensor Dispatch(ComputeFunc fn, DataType dataType, TensorShape outputShape, int workItemsX, int workItemsY, int workItemsZ, string outputName = "O") - { - var o = NewTensor(fn, outputName, dataType, outputShape); - fn.Dispatch(workItemsX, workItemsY, workItemsZ); - return o; - } - - // --------------------------------------------------------------------------------- - - internal ITensorData TextureToTensorData(TextureAsTensorData texData, string name) - { - var fn = new ComputeFunc(ComputeShaderContext.Optimized, "TextureToTensor", GetModelExecutionsReporter()); - var tensorData = new ComputeTensorData(texData.shape, name, ComputeInfo.channelsOrder, false); - - fn.SetTensor("O", texData.shape, tensorData.buffer); - fn.shader.SetBool("_FlipY", texData.flip == TextureAsTensorData.Flip.Y); - fn.shader.SetVector("_Scale", texData.scale); - fn.shader.SetVector("_Bias", texData.bias); - - var offsets = new int[] { 0,0,0,0 }; - foreach (var tex in texData.textures) - { - var texArr = tex as Texture2DArray; - var tex3D = tex as Texture3D; - var rt = tex as RenderTexture; - - var texDepth = 1; - if (texArr) - texDepth = texArr.depth; - else if (tex3D) - texDepth = tex3D.depth; - else if (rt) - texDepth = rt.volumeDepth; - - fn.SetTexture("X", tex); - fn.shader.SetInts("_Pool", new int [] {tex.width, tex.height}); - fn.shader.SetInts("_Pad", offsets); - fn.shader.SetInts("_ChannelWriteMask", - TextureFormatUtils.FormatToChannelMask(tex, texData.interpretPixelAsChannels)); - fn.shader.SetInts("_ChannelReadMap", - TextureFormatUtils.FormatToChannelReadMap(tex, texData.interpretPixelAsChannels)); - - fn.Dispatch(texData.shape.width, texData.shape.height, texDepth); - - if (texData.interpretDepthAs == TextureAsTensorData.InterpretDepthAs.Batch) - offsets[0] += texDepth; - else if (texData.interpretDepthAs == TextureAsTensorData.InterpretDepthAs.Channels) - offsets[3] += texDepth * texData.interpretPixelAsChannels; - } - - return tensorData; - } - - /// - /// Copy `Tensor` data to `RenderTexture` - /// - /// source `Tensor` - /// target `RenderTexture` - /// batch - /// from channel - /// scale - /// bias - /// LUT table - /// flips the texture along the Y dimension (optional, default: true) - public void TensorToRenderTexture(Tensor X, RenderTexture target, int batch, int fromChannel, Vector4 scale, Vector4 bias, Texture3D lut, bool flipY = true) - { - if (!target.enableRandomWrite || !target.IsCreated()) - { - target.Release(); - target.enableRandomWrite = true; - target.Create(); - } - - var fn = new ComputeFunc(ComputeShaderContext.Optimized, "TensorToTexture"+ (lut == null?"NoLUT":"3DLUT"), GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - fn.SetTexture("O", target); - fn.shader.SetVector("_Scale", scale); - fn.shader.SetVector("_Bias", bias); - fn.shader.SetInts("_Pad", new int[] { batch, 0, 0, fromChannel }); - fn.shader.SetBool("_FlipY", flipY); - if (lut != null) - { - fn.SetTexture("X", lut); - fn.shader.SetVector("_LutParams", new Vector2(1f / lut.width, lut.width - 1f)); - } - - fn.Dispatch(target.width, target.height, 1); - } - - /// - /// Check if `Flatten` is needed for `Dense` layer input - /// - /// input shape - /// `true` if `Flatten` is needed - protected bool ShouldFlattenInputForDenseLayer(TensorShape X) - { - //In HWC flatten is a no-op memory wise. - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NHWC) - return false; - - //In CHW flatten is return a tensor with items linearized in memory in regards to HWC layout. - int flattenDimensions = (X.height > 1 ? 1 : 0) + - (X.width > 1 ? 1 : 0) + - (X.channels > 1 ? 1 : 0); - return flattenDimensions > 1; - } - - /// - /// Check if `fusedActivation` type is supported in place - /// - /// fused activation type - /// `true` if supported - protected override bool IsFusedActivationSupported(Layer.FusedActivation fusedActivation) - { - switch (fusedActivation) - { - case Layer.FusedActivation.Relu: - return true; - case Layer.FusedActivation.None: - return true; - default: - return false; - } - } - - // --------------------------------------------------------------------------------- - /// - public override Tensor MatMul(Tensor X, int rankX, Tensor Y, int rankY) - { - // N.B: Current implementation is inefficient as it introduces Transposes/Slice and Concat. - // => consider refactoring dense to support batch - - // X and Y can be constants, in that cases the internal layout does not match ComputeInfo.channelsOrder and will allways be NHWC - // => permute them if there is a layout mismatch - X = GetTensorInCurrentMemoryLayoutHelper(X); - Y = GetTensorInCurrentMemoryLayoutHelper(Y); - - // V-Table magic, ReferenceCPU.MaMul is calls MatMul2D, Concat & Slice all which are overloaded by all respective IOps, so will call the correct backend - return base.MatMul(X, rankX, Y, rankY); - } - - /// - public override Tensor MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - X = GetTensorInCurrentMemoryLayoutHelper(X); - Y = GetTensorInCurrentMemoryLayoutHelper(Y); - - // MatMul implementation in terms of Dense - var A = (xTranspose) ? Transpose(X): X; - var B = (yTranspose) ? Transpose(Y): Y; - var C = NewTempTensor(X.dataType, new TensorShape(1, B.flatWidth)); - var Z = Sub(new[] { C, C }); // initialize bias with zeros, TODO will fragment ping pong allocator - - var O = Dense(A, B, Z, Layer.FusedActivation.None); - if (A != X) A.Dispose(); - if (B != Y) B.Dispose(); - C.Dispose(); - Z.Dispose(); - - return O; - } - - /// - public override Tensor Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(W.dimensions <= 2); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(X.flatWidth, W.flatHeight); - - if (ShouldFlattenInputForDenseLayer(X.shape)) - X = Flatten(X); - - var Oshape = new TensorShape(X.flatHeight, W.flatWidth); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Dense", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "W", W); - SetTensor(fn, "B", B); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - var O = Dispatch(fn, X.dataType, Oshape, Oshape.flatWidth, Oshape.flatHeight, 1); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Dense3(Tensor X, Tensor W, Tensor B) - { - var Oshape = new TensorShape(X.batch, 1, W.channels, X.channels); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Dense3", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "W", W); - SetTensor(fn, "B", B); - - var O = Dispatch(fn, X.dataType, Oshape, Oshape.width, Oshape.channels, Oshape.batch); - - return O; - } - - /// - /// Convolution implementation via Winograd transform - /// - /// input - /// convolution kernel - /// bias - /// stride - /// padding - /// fused activation type - /// output `Tensor` - private Tensor Conv2DWinograd(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var Oshape = X.shape.ApplyKernel(K.shape, stride, pad); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Conv2DWinograd_2x2_3x3", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "K", K); - SetTensor(fn, "B", B); - - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - var O = Dispatch(fn, X.dataType, Oshape, K.kernelCount, ComputeHelper.IDivC(Oshape.width, 2), ComputeHelper.IDivC(Oshape.height, 2)); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Conv3D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.IsNDHWC()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 3);//WHD - Assert.AreEqual(pad.Length, 6); - - var Oshape = X.shape.ApplyKernel(K.shape, stride, pad); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Conv3D", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "K", K); - SetTensor(fn, "B", B); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad.Take(3).ToArray()); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - var O = Dispatch(fn, X.dataType, Oshape, K.kernelCount, Oshape.width, Oshape.height); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2);//WH - Assert.AreEqual(pad.Length, 4); - - var Oshape = X.shape.ApplyKernel(K.shape, stride, pad); - - bool useWinograd = (K.kernelWidth == 3) && (K.kernelHeight == 3) && (stride[0] == 1) && (stride[1] == 1) && ((Oshape.height % 2) == 0) && ((Oshape.width % 2) == 0); - if( useWinograd ) - { - return Conv2DWinograd(X, K, B, stride, pad, fusedActivation); - } - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Conv2D", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "K", K); - SetTensor(fn, "B", B); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - var O = Dispatch(fn, X.dataType, Oshape, K.kernelCount, Oshape.width, Oshape.height); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - if (K.kernelDepth != 1) - return base.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(K.kernelDepth, 1); - Assert.AreEqual(K.kernelCount, X.channels); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var Oshape = X.shape.ApplyKernel(K.shape, stride, pad); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "DepthwiseConv2D", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "K", K); - SetTensor(fn, "B", B); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - var O = Dispatch(fn, X.dataType, Oshape, K.kernelCount, Oshape.width, Oshape.height); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var Oshape = X.shape.ApplyKernelInverse(K.shape, stride, pad, outputAdjustment); - - // one pass version - pad = new int[] - { - K.kernelWidth - pad[0] - 1, K.kernelHeight - pad[1] - 1, - K.kernelWidth - pad[2] - 1, K.kernelHeight - pad[3] - 1 - }; - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Conv2DTrans", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "K", K); - SetTensor(fn, "B", B); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - var O = Dispatch(fn, X.dataType, Oshape, K.kernelCount, Oshape.width, Oshape.height); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor Upsample2D(Tensor X, int[] scale, bool bilinear) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(scale.Length, 2); - - var O = new TensorShape(X.batch, X.height*scale[1], X.width*scale[0], X.channels); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, bilinear ? "UpsampleBilinear2D": "Upsample2D", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - fn.shader.SetInts("_Pool", scale); - - if (bilinear) // dispatches over output dimensions (O) - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - else // dispatches over input dimensions (X) - return Dispatch(fn, X.dataType, O, X.channels, X.width, X.height); - } - - /// - public override Tensor Upsample3D(Tensor X, int[] scale, bool trilinear) - { - Assert.IsTrue(X.shape.IsNDHWC()); - Assert.AreEqual(scale.Length, 3); - - var O = new TensorShape(1, 1, X.batch, 1, X.depth*scale[2], X.height*scale[1], X.width*scale[0], X.channels); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, trilinear ? "UpsampleTrilinear3D": "Upsample3D", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - fn.shader.SetInts("_Pool", scale); - - if (trilinear) // dispatches over output dimensions (O) - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - else // dispatches over input dimensions (X) - return Dispatch(fn, X.dataType, O, X.channels, X.width, X.height); - } - - /// - public override Tensor Resample2D(Tensor X, int[] size, bool bilinear) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(size.Length, 2); - - var O = new TensorShape(X.batch, size[1], size[0], X.channels); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, bilinear ? "ResampleBilinear2D" : "Resample2D", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor DepthToSpace(Tensor X, int[] blocksize, Layer.DepthToSpaceMode mode) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(blocksize.Length, 2); - - var O = new TensorShape(X.batch, X.height * blocksize[1], X.width * blocksize[0], X.channels / (blocksize[0] * blocksize[1])); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "DepthToSpace_" + mode, GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - fn.shader.SetInts("_Pool", blocksize); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor SpaceToDepth(Tensor X, int[] blocksize) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(blocksize.Length, 2); - - var O = new TensorShape(X.batch, X.height / blocksize[1], X.width / blocksize[0], X.channels * (blocksize[0] * blocksize[1])); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "SpaceToDepth", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - fn.shader.SetInts("_Pool", blocksize); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - protected virtual Tensor Pool2D(string kernelName, Tensor X, int[] pool, int[] stride, int[] pad) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - - var O = X.shape.ApplyPool(pool, stride, pad); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, kernelName, GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - fn.shader.SetInts("_Pool", pool); - fn.shader.SetInts("_Stride", stride); - fn.shader.SetInts("_Pad", pad); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - return Pool2D("MaxPool2D", X, pool, stride, pad); - } - - /// - public override Tensor AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - return Pool2D("AvgPool2D", X, pool, stride, pad); - } - - /// - /// Generic pooling 2D - /// - /// kernel name - /// input - /// output `Tensor` - protected virtual Tensor GlobalPool2D(string kernelName, Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - var O = new TensorShape(X.batch, 1, 1, X.channels); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, kernelName, GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - return Dispatch(fn, X.dataType, O, O.channels, 1, 1); - } - - /// - public override Tensor GlobalMaxPool2D(Tensor X) - { - return GlobalPool2D("GlobalMaxPool2D", X); - } - - /// - public override Tensor GlobalAvgPool2D(Tensor X) - { - return GlobalPool2D("GlobalAvgPool2D", X); - } - - /// - public override Tensor GlobalAvgVariancePool2D(Tensor X) - { - Assert.IsTrue(X.shape.Is4D()); - var O = new TensorShape(X.batch, 2, 1, X.channels); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "GlobalAvgVariancePool2D", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - return Dispatch(fn, X.dataType, O, O.channels, 1, 1); - } - - /// - /// Apply padding - /// - /// input - /// padding - /// kernel name - /// constant - /// output `Tensor` - protected virtual Tensor ApplyPadding(Tensor X, int[] pad, string kernelName, float constant = 0.0f) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pad.Length, 6); - - var O = X.shape.ApplyBorder(pad); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, kernelName, GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - fn.shader.SetInts("_Pad", pad.Take(3).ToArray()); - - if (kernelName == "Border2D") - { - // NOTE: negative "pad" variable will crop X tensor - int croppedWidth = X.width - Math.Max(0, -pad[3]); - int croppedHeight = X.height - Math.Max(0, -pad[4]); - int croppedChannels = X.channels - Math.Max(0, -pad[5]); - var croppedSize = new int[] { 0, 0, 0 }; - croppedSize[0] = croppedWidth; - croppedSize[1] = croppedHeight; - croppedSize[2] = croppedChannels; - - fn.shader.SetInts("_Pool", croppedSize); - fn.shader.SetFloat("_Beta", constant); - } - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - - /// - /// Apply 3D padding - /// - /// input - /// padding - /// kernel name - /// padding constant - /// output `Tensor` - protected virtual Tensor ApplyPadding3D(Tensor X, int[] pad, string kernelName, float constant = 0.0f) - { - Assert.IsTrue(X.shape.IsNDHWC()); - Assert.AreEqual(pad.Length, 8); - - var O = X.shape.ApplyBorder(pad); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, kernelName, GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - fn.shader.SetInts("_Pad", pad.Take(4).ToArray()); - - if (kernelName == "Border3D") - { - // NOTE: negative "pad" variable will crop X tensor - int croppedWidth = X.width - Math.Max(0, -pad[4]); - int croppedHeight = X.height - Math.Max(0, -pad[5]); - int croppedDepth = X.depth - Math.Max(0, -pad[6]); - int croppedChannels = X.channels - Math.Max(0, -pad[7]); - - var croppedSize = new int[] { 0, 0, 0, 0 }; - croppedSize[0] = croppedWidth; - croppedSize[1] = croppedHeight; - croppedSize[2] = croppedDepth; - croppedSize[3] = croppedChannels; - - fn.shader.SetInts("_Pool", croppedSize); - fn.shader.SetFloat("_Beta", constant); - } - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor Border2D(Tensor X, int[] pad, float constant) - { - return ApplyPadding(X, pad, "Border2D", constant); - } - - /// - public override Tensor Border3D(Tensor X, int[] pad, float constant) - { - return ApplyPadding3D(X, pad, "Border3D", constant); - } - - /// - public override Tensor Pad2DReflect(Tensor X, int[] pad) - { - return ApplyPadding(X, pad, "Pad2DReflect"); - } - - /// - public override Tensor Pad2DSymmetric(Tensor X, int[] pad) - { - return ApplyPadding(X, pad, "Pad2DSymmetric"); - } - - /// - public override Tensor Pad2DEdge(Tensor X, int[] pad) - { - return ApplyPadding(X, pad, "Pad2DEdge"); - } - - /// - public override Tensor ScaleBias(Tensor X, Tensor S, Tensor B) - { - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - - var O = X.shape; - var fn = new ComputeFunc(ComputeShaderContext.Reference, "ScaleBias", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "W", S); - SetTensor(fn, "B", B); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) - { - if (!X.shape.Is4D()) - throw new NotImplementedException(); - - if (axis != TensorShape.C && axis != -1) - return base.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); - - if (pool == 1 && X.batch != 1) - return base.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); // @TODO: Instance Normalization with batch > 1 - - if (pool <= 0) - pool = X.batch; - - var Oshape = X.shape; - var fn = new ComputeFunc(ComputeShaderContext.Reference, "InstanceNorm", GetModelExecutionsReporter()); - fn.shader.SetFloat("_Epsilon", epsilon); - fn.shader.SetInt("_ActivationMode", (int)fusedActivation); - - SetTensor(fn, "X", X); - SetTensor(fn, "W", S); - SetTensor(fn, "B", B); - - var O = Dispatch(fn, X.dataType, Oshape, Oshape.channels, 1, 1); - - if (!IsFusedActivationSupported(fusedActivation)) - O = Activation(fusedActivation.ToString(), O); - - return O; - } - - /// - public override Tensor LRN(Tensor X, float alpha, float beta, float bias, int size) - { - var O = X.shape; - var fn = new ComputeFunc(ComputeShaderContext.Reference, "LRN", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - fn.shader.SetFloat("_Alpha", alpha); - fn.shader.SetFloat("_Beta", beta); - fn.shader.SetFloat("_Epsilon", bias); - fn.shader.SetInt("_Axis", size); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - // @TODO: debug & fix - /// - public override Tensor Dropout(Tensor X, float alpha) - { - Assert.IsTrue(alpha >= 0f && alpha <= 1f); - - var O = X.shape; - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Dropout", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - - fn.shader.SetFloat("_Alpha", alpha); - - using (var seedOverride = new Seed(ref m_DropoutSeed, 1337)) - { - fn.shader.SetFloat("_Seed", UnityEngine.Random.value); - } - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - /// Generic activation function - /// - /// kernel name - /// input - /// alpha - /// beta - /// output Tensor - protected virtual Tensor Activation(string kernelName, Tensor X, float alpha = 0f, float beta = 0f) - { - var O = X.shape; - var fn = new ComputeFunc(ComputeShaderContext.Reference, kernelName, GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - fn.shader.SetFloat("_Alpha", alpha); - fn.shader.SetFloat("_Beta", beta); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor Relu(Tensor X) - { - return Activation("Relu", X); - } - - /// - public override Tensor PRelu(Tensor X, Tensor S) - { - Assert.IsTrue((X.flatWidth == S.flatWidth) || (S.flatWidth == 1)); - - var O = X.shape; - var fn = new ComputeFunc(ComputeShaderContext.Reference, "PRelu", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "W", S); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor Softmax(Tensor X, int axis) - { - axis = X.shape.Axis(axis); - var Oshape = X.shape; - - int reducedDim = X.shape[axis]; - var XShape = X.shape.ToArray(); - - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW) - { - XShape[TensorShape.DataBatch + 1] = Oshape[TensorShape.C]; - for (int i = TensorShape.DataBatch + 1; i < TensorShape.C; i++) - XShape[i + 1] = Oshape[i]; - - if (axis == TensorShape.C) - axis = TensorShape.DataBatch + 1; - else if (axis > TensorShape.DataBatch) - axis += 1; - } - - int height = 1; - for (var i = 0; i < axis; i++) - height *= XShape[i]; - - int width = 1; - for (var i = axis + 1; i < X.shape.rank; i++) - width *= XShape[i]; - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Softmax", GetModelExecutionsReporter()); - - var strides = new[] { height, reducedDim, width, 0, 0 }; - fn.shader.SetInts("_Stride", strides); - - SetTensor(fn, "X", X); - - var O = Dispatch(fn, X.dataType, Oshape, height, width, 1); - - return O; - } - - /// - public override Tensor LogSoftmax(Tensor X, int axis) - { - axis = X.shape.Axis(axis); - var Oshape = X.shape; - - int reducedDim = X.shape[axis]; - var XShape = X.shape.ToArray(); - - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW) - { - XShape[TensorShape.DataBatch + 1] = Oshape[TensorShape.C]; - for (int i = TensorShape.DataBatch + 1; i < TensorShape.C; i++) - XShape[i + 1] = Oshape[i]; - - if (axis == TensorShape.C) - axis = TensorShape.DataBatch + 1; - else if (axis > TensorShape.DataBatch) - axis += 1; - } - - int height = 1; - for (var i = 0; i < axis; i++) - height *= XShape[i]; - - int width = 1; - for (var i = axis + 1; i < X.shape.rank; i++) - width *= XShape[i]; - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "LogSoftmax", GetModelExecutionsReporter()); - - var strides = new[] { height, reducedDim, width, 0, 0 }; - fn.shader.SetInts("_Stride", strides); - - SetTensor(fn, "X", X); - - var O = Dispatch(fn, X.dataType, Oshape, height, width, 1); - - return O; - } - - /// - public override Tensor Tanh(Tensor X) - { - return Activation("Tanh", X); - } - - /// - public override Tensor Softplus(Tensor X) - { - return Activation("Softplus", X); - } - - /// - public override Tensor Sigmoid(Tensor X) - { - return Activation("Sigmoid", X); - } - - /// - public override Tensor HardSigmoid(Tensor X, float alpha, float beta) - { - return Activation("HardSigmoid", X, alpha, beta); - } - - /// - public override Tensor Relu6(Tensor X) - { - return Activation("Relu6", X); - } - - /// - public override Tensor Elu(Tensor X, float alpha) - { - return Activation("Elu", X, alpha); - } - - /// - public override Tensor LeakyRelu(Tensor X, float alpha) - { - return Activation("LeakyRelu", X, alpha); - } - - /// - public override Tensor Selu(Tensor X, float alpha, float gamma) - { - return Activation("Selu", X, alpha, gamma); - } - - /// - public override Tensor Swish(Tensor X) - { - return Activation("Swish", X); - } - - /// - public override Tensor Abs(Tensor X) - { - return Activation("Abs", X); - } - - /// - public override Tensor Neg(Tensor X) - { - return Activation("Neg", X); - } - - /// - public override Tensor Ceil(Tensor X) - { - return Activation("Ceil", X); - } - - /// - public override Tensor Clip(Tensor X, float min, float max) - { - return Activation("Clip", X, min, max); - } - - /// - public override Tensor Floor(Tensor X) - { - return Activation("Floor", X); - } - - /// - public override Tensor Round(Tensor X) - { - return Activation("Round", X); - } - - /// - public override Tensor Reciprocal(Tensor X) - { - return Activation("Reciprocal", X); - } - - /// - public override Tensor Pow(Tensor X, float alpha) - { - return Activation("Pow", X, alpha); - } - - /// - public override Tensor Exp(Tensor X) - { - return Activation("Exp", X); - } - - /// - public override Tensor Log(Tensor X) - { - return Activation("Log", X); - } - - /// - public override Tensor Sqrt(Tensor X) - { - return Activation("Sqrt", X); - } - - /// - public override Tensor Acos(Tensor X) - { - return Activation("Acos", X); - } - - /// - public override Tensor Acosh(Tensor X) - { - return Activation("Acosh", X); - } - - /// - public override Tensor Asin(Tensor X) - { - return Activation("Asin", X); - } - - /// - public override Tensor Asinh(Tensor X) - { - return Activation("Asinh", X); - } - - /// - public override Tensor Atan(Tensor X) - { - return Activation("Atan", X); - } - - /// - public override Tensor Atanh(Tensor X) - { - return Activation("Atanh", X); - } - - /// - public override Tensor Cos(Tensor X) - { - return Activation("Cos", X); - } - - /// - public override Tensor Cosh(Tensor X) - { - return Activation("Cosh", X); - } - - /// - public override Tensor Sin(Tensor X) - { - return Activation("Sin", X); - } - - /// - public override Tensor Sinh(Tensor X) - { - return Activation("Sinh", X); - } - - /// - public override Tensor Tan(Tensor X) - { - return Activation("Tan", X); - } - - /// - public override Tensor Erf(Tensor X) - { - return Activation("Erf", X); - } - - /// - public override Tensor ConstantOfShape(TensorShape X, DataType type, float value = 0.0f) - { - var fn = new ComputeFunc(ComputeShaderContext.Reference, "ConstantOfShape", GetModelExecutionsReporter()); - fn.shader.SetFloat("_Alpha", value); - - return Dispatch(fn, type, X, X.channels, X.width, X.height); - } - - /// - public override Tensor Expand(Tensor X, TensorShape newShape) - { - Assert.IsTrue(newShape.sequenceLength == X.sequenceLength || X.sequenceLength == 1); - Assert.IsTrue(newShape.numberOfDirections == X.numberOfDirections || X.numberOfDirections == 1); - Assert.IsTrue(newShape.batch == X.batch || X.batch == 1); - Assert.IsTrue(newShape.extraDimension == X.extraDimension || X.extraDimension == 1); - Assert.IsTrue(newShape.depth == X.depth || X.depth == 1); - Assert.IsTrue(newShape.height == X.height || X.height == 1); - Assert.IsTrue(newShape.width == X.width || X.width == 1); - Assert.IsTrue(newShape.channels == X.channels || X.channels == 1); - - X = GetTensorInCurrentMemoryLayoutHelper(X); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Expand", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - - return Dispatch(fn, X.dataType, newShape, newShape.channels, newShape.width, newShape.height); - } - - internal static Tensor[] s_ElementwiseBroadcastTensors = new Tensor[2]; - - /// - /// Elementwise broadcast for specified kernel - /// - /// kernel name - /// input tensors - /// output `Tensor` - /// thrown if input `Tensor` is not compatible with 4D shape - protected virtual Tensor ElementwiseWithBroadcast(string kernelName, Tensor[] tensors) - { - var O = TensorExtensions.MaxShape(tensors); - - Assert.IsTrue(tensors.Length > 0); - var X = tensors[0]; - - var fn = new ComputeFunc(ComputeShaderContext.Reference, kernelName, GetModelExecutionsReporter()); - bool isFirstDispatch = true; - for (int t = 1; t < tensors.Length; ++t) - { - var B = tensors[t]; - - // B and X can be constants, in that cases the internal layout does not match ComputeInfo.channelsOrder and will allways be NHWC - // => permute them if there is a layout mismatch - X = GetTensorInCurrentMemoryLayoutHelper(X); - B = GetTensorInCurrentMemoryLayoutHelper(B); - - SetTensor(fn, "X", X); - SetTensor(fn, "B", B); - fn.shader.SetFloat("_Alpha", 1.0f/(float)tensors.Length); - fn.shader.SetInt("_IsFirstDispatch", isFirstDispatch ? 1 : 0); - - X = Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - isFirstDispatch = false; - } - - return X; - } - - /// - public override Tensor Add(Tensor[] tensors) - { - return ElementwiseWithBroadcast("BroadcastAdd", tensors); - } - - /// - public override Tensor Sub(Tensor[] tensors) - { - return ElementwiseWithBroadcast("BroadcastSub", tensors); - } - - /// - public override Tensor Mul(Tensor[] tensors) - { - return ElementwiseWithBroadcast("BroadcastMul", tensors); - } - - /// - public override Tensor Div(Tensor[] tensors) - { - return ElementwiseWithBroadcast("BroadcastDiv", tensors); - } - - /// - public override Tensor Pow(Tensor[] tensors) - { - return ElementwiseWithBroadcast("BroadcastPow", tensors); - } - - /// - public override Tensor Min(Tensor[] tensors) - { - return ElementwiseWithBroadcast("BroadcastMin", tensors); - } - - /// - public override Tensor Max(Tensor[] tensors) - { - return ElementwiseWithBroadcast("BroadcastMax", tensors); - } - - /// - public override Tensor Mean(Tensor[] tensors) - { - return ElementwiseWithBroadcast("BroadcastMean", tensors); - } - - internal static int[] s_ReducePermute = new int[8]; - - internal static void FillReducePermute(int axis) - { - for (var idx = 0; idx < s_ReducePermute.Length; idx++) - s_ReducePermute[idx] = idx; - s_ReducePermute[7] = axis; - s_ReducePermute[axis] = 7; - } - - /// - /// Reduce with specified kernel - /// - /// kernel name - /// input - /// axis - /// output `Tensor` - internal static readonly Dictionary s_ReduceRefKernelNames = new Dictionary { - {Layer.Type.ReduceMax, "ReduceMax"}, {Layer.Type.ReduceMean, "ReduceMean"}, - {Layer.Type.ReduceMin, "ReduceMin"}, {Layer.Type.ReduceProd, "ReduceProd"}, - {Layer.Type.ReduceSum, "ReduceSum"}, {Layer.Type.ArgMax, "ArgMax"}, - {Layer.Type.ArgMin, "ArgMin"} - }; - - private Tensor ReduceHelper(Layer.Type kernelName, Tensor X, int axis) - { - axis = X.shape.Axis(axis); - - bool needTranpose = axis != TensorShape.C; - FillReducePermute(axis); - - if (needTranpose) - X = Transpose(X, s_ReducePermute); - - var oShape = X.shape.Reduce(TensorShape.C); - Assert.AreEqual(oShape.channels, 1); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, s_ReduceRefKernelNames[kernelName], GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - - var O = Dispatch(fn, X.dataType, oShape, oShape.width, oShape.height, 1); - - if (needTranpose) - O = Transpose(O, s_ReducePermute); - - return O; - } - - /// - public override Tensor ArgMax(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ArgMax, X, axis); - } - - /// - public override Tensor ArgMin(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ArgMin, X, axis); - } - - /// - public override Tensor ReduceMin(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceMin, X, axis); - } - - /// - public override Tensor ReduceMax(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceMax, X, axis); - } - - /// - public override Tensor ReduceSum(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceSum, X, axis); - } - - /// - public override Tensor ReduceMean(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceMean, X, axis); - } - - /// - public override Tensor ReduceProd(Tensor X, int axis) - { - return ReduceHelper(Layer.Type.ReduceProd, X, axis); - } - - /// - public override Tensor Greater(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("BroadcastGreater", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor GreaterEqual(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("BroadcastGreaterEqual", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor Less(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("BroadcastLess", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LessEqual(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("BroadcastLessEqual", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor Equal(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("BroadcastEqual", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LogicalOr(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("BroadcastLogicalOr", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LogicalAnd(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("BroadcastLogicalAnd", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LogicalXor(Tensor A, Tensor B) - { - s_ElementwiseBroadcastTensors[0] = A; - s_ElementwiseBroadcastTensors[1] = B; - return ElementwiseWithBroadcast("BroadcastLogicalXor", s_ElementwiseBroadcastTensors); - } - - /// - public override Tensor LogicalNot(Tensor X) - { - return Activation("LogicalNot", X); - } - - /// - public override Tensor Sign(Tensor X) - { - return Activation("Sign", X); - } - - /// - public override Tensor Where(Tensor C, Tensor A, Tensor B) - { - var fn = new ComputeFunc(ComputeShaderContext.Reference, "BroadcastWhere", GetModelExecutionsReporter()); - - var O = TensorExtensions.MaxShape(new[] { C, A, B }); - - SetTensor(fn, "X", C); - SetTensor(fn, "W", A); - SetTensor(fn, "K", B); - - return Dispatch(fn, C.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor OneHot(Tensor X, int depth, float onValue, float offValue, int inputRank=-1) - { - if (inputRank == -1) - inputRank = X.dimensions; - - if (inputRank >= 4) - throw new NotImplementedException(); - - TensorShape O = new TensorShape(); - if (inputRank == 1) - O = new TensorShape(X.flatHeight, depth); - else if (inputRank == 2) - O = new TensorShape(X.flatHeight, 1, depth, X.channels); - else - O = new TensorShape(X.batch, X.width, depth, X.channels); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "OneHot", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - fn.shader.SetFloat("_Alpha", onValue); - fn.shader.SetFloat("_Beta", offValue); - fn.shader.SetInt("_Axis", depth); - fn.shader.SetInts("_Pad", new int[] { inputRank, 0, 0, 0 }); - - return Dispatch(fn, X.dataType, O, X.width, depth, X.channels); - } - - /// - public override Tensor RoiAlign(Tensor X, Tensor Rois, Tensor Indices, int outputHeight, int outputWidth, int samplingRatio, float spatialScale) - { - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(Rois.flatHeight, Indices.batch); - Assert.AreEqual(Rois.flatWidth, 4); - - TensorShape O = new TensorShape(Rois.flatHeight, outputHeight, outputWidth, X.channels); - var fn = new ComputeFunc(ComputeShaderContext.Reference, "RoiAlign", GetModelExecutionsReporter()); - - SetTensor(fn, "X", X); - SetTensor(fn, "K", Rois); - SetTensor(fn, "B", Indices); - - fn.shader.SetFloat("_Alpha", spatialScale); - fn.shader.SetInt("_Axis", samplingRatio); - - return Dispatch(fn, X.dataType, O, outputHeight, outputWidth, X.channels); - } - - /// - /// Copy and reshape tensor for NCHW layout - /// - /// input - /// new shape - /// output `Tensor` - protected virtual Tensor CopyAndReshape_NCHW(Tensor X, TensorShape newShape) - { - Assert.AreEqual(X.length, newShape.length); - Assert.AreEqual(ComputeInfo.ChannelsOrder.NCHW, ComputeInfo.channelsOrder); - - var O = NewTensor(X.dataType, newShape, AllocScope.LayerOutput, "O"); - - if (X.shape.Is4D() && newShape.Is4D()) - { - var fn = new ComputeFunc(ComputeShaderContext.Reference, "ReshapeFromNHWCModel_NCHW", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - SetTensor(fn, "O", O); - fn.Dispatch( O.width, O.height, O.channels); - } - else - { - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Reshape8DFromChannelFirstModel_NCHW", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - SetTensor(fn, "O", O); - var xD = new[] {X.shape[0], X.shape[1],X.shape[3],X.shape[4]}; - var oD = new[] {O.shape[0], O.shape[1],O.shape[3],O.shape[4]}; - fn.shader.SetInts("_Pad", xD); - fn.shader.SetInts("_Pool", oD); - fn.Dispatch( O.width, O.height, O.channels); - } - - return O; - } - - /// - protected override Tensor CopyAndReshape(Tensor X, TensorShape newShape) - { - Assert.AreEqual(X.length, newShape.length); - if (X.shape != newShape) - { - //In CHW mode one should call CopyAndReshape_NCHW if shape is modified - Assert.AreEqual(ComputeInfo.ChannelsOrder.NHWC, ComputeInfo.channelsOrder); - } - bool isNHWCCopy = X.shape.Is4D() && newShape.Is4D(); - - // NOTE: "Copy" kernel copies tensor data while preserving the shape - // However here in CopyAndReshape we want to both copy and change the shape, - // To be able to piggyback "Copy" kernel we specify new shape when allocating destination tensor, - // but use shape identical to source when copying. - var O = NewTensor(X.dataType, newShape, AllocScope.LayerOutput, "O"); - var fn = new ComputeFunc(ComputeShaderContext.Reference, isNHWCCopy?"Copy":"Copy8D", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - var copyShape = X.shape; - fn.SetTensor("O", copyShape, Pin(O).buffer); - - if (isNHWCCopy) - { - var offsets = new int[] {0, 0, 0, 0}; - fn.shader.SetInts("_Pad", offsets); - } - else - { - var XonDeviceShape = GetOnDeviceShape(X.shape); - var d0_3 = new[] {XonDeviceShape[0], XonDeviceShape[1],XonDeviceShape[2],XonDeviceShape[3]}; - var d4_7 = new[] {XonDeviceShape[4], XonDeviceShape[5],XonDeviceShape[6],XonDeviceShape[7]}; - fn.shader.SetInts("_Stride", d0_3); - fn.shader.SetInts("_Pool", d4_7); - } - - fn.Dispatch(X.channels, X.width, X.height); - return O; - } - - /// - public override Tensor Flatten(Tensor X) - { - var newShape = X.shape.Flatten(); - if (X.shape == newShape || ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NHWC) - return base.Flatten(X); - - return CopyAndReshape_NCHW(X, newShape); - } - - /// - public override Tensor Reshape(Tensor X, TensorShape newShape) - { - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NHWC || X.shape == newShape) - return base.Reshape(X, newShape); - - return CopyAndReshape_NCHW(X, newShape); - } - - /// - public override Tensor Transpose(Tensor X) - { - // TODO: reshape when possible - Assert.IsTrue(X.dimensions <= 2); - var O = new TensorShape(X.flatWidth, X.flatHeight); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Transpose2D", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - return Dispatch(fn, X.dataType, O, O.flatWidth, O.flatHeight, 1); - } - - /// - /// Get `Tensor` shape on GPU device - /// - /// shape - /// ouput shape as int array - protected int[] GetOnDeviceShape(TensorShape shape) - { - var onDeviceShape = shape.ToArray(); - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW) - { - //SRNTDHWC --> SRNCTDHW - var numChannel = onDeviceShape[7]; - onDeviceShape[7] = onDeviceShape[6]; - onDeviceShape[6] = onDeviceShape[5]; - onDeviceShape[5] = onDeviceShape[4]; - onDeviceShape[4] = onDeviceShape[3]; - onDeviceShape[3] = numChannel; - } - return onDeviceShape; - } - - /// - /// Convert permutation list to device specific layout - /// - /// permutations channels last - /// new permutation list - protected int[] ConvertPermutationToDeviceLayout(int[] permutationChannelLast) - { - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NHWC) - return permutationChannelLast; - - var permutationChannelFirst = new int[TensorShape.MaxRank]; - var channelLastToFirst = new[] {0, 1, 2, 7, 3, 4, 5, 6}; - for (int i = 0; i < TensorShape.MaxRank; ++i) - { - int sourceDestinationSemanticIndex = channelLastToFirst[i]; - int sourcePermutationSemanticIndex = permutationChannelLast[sourceDestinationSemanticIndex]; - permutationChannelFirst[i] = Array.IndexOf(channelLastToFirst, sourcePermutationSemanticIndex); - } - - return permutationChannelFirst; - } - - private Tensor Transpose8DHelper(Tensor X, int[] permutations) - { - permutations = TensorExtensions.Get8DPermutationsForNHWCPermutationsAndShape(X.shape, permutations); - - // See: Permute() in ONNXTensor.cs and https://stackoverflow.com/a/32034565 - var Oshape = X.shape.Permute(permutations); - - var OonDeviceShape = GetOnDeviceShape(Oshape); - var XonDeviceShape = GetOnDeviceShape(X.shape); - var onDevicePermutation = ConvertPermutationToDeviceLayout(permutations); - - // outTensor strides - var reversePermute = new int[permutations.Length]; - for (var i = 0; i < permutations.Length; ++i) - reversePermute[i] = Array.IndexOf(onDevicePermutation, i); - var tempOutStrides = new int[TensorShape.MaxRank+1]; - tempOutStrides[8] = 1; - for (int i = 7; i >= 0; --i) - tempOutStrides[i] = tempOutStrides[i+1] * OonDeviceShape[i]; - var outStride = new int[reversePermute.Length]; - for (var i = 0; i < reversePermute.Length; ++i) - outStride[i] = tempOutStrides[reversePermute[i] + 1]; - - var d0_3 = new[] {XonDeviceShape[0], XonDeviceShape[1],XonDeviceShape[2],XonDeviceShape[3]}; - var d4_7 = new[] {XonDeviceShape[4], XonDeviceShape[5],XonDeviceShape[6],XonDeviceShape[7]}; - var outStride0_3 = new[] {outStride[0],outStride[1],outStride[2],outStride[3]}; - var outStride4_7 = new[] {outStride[4],outStride[5],outStride[6],outStride[7]}; - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Transpose8D", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - fn.shader.SetInts("_Pad", d0_3); - fn.shader.SetInts("_Pool", d4_7); - fn.shader.SetInts("_Stride", outStride0_3); - fn.shader.SetInts("_ChannelWriteMask", outStride4_7); - - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW) - return Dispatch(fn, X.dataType, Oshape, X.width, X.height, X.depth); - else - return Dispatch(fn, X.dataType, Oshape, X.channels, X.width, X.height); - - } - - /// - public override Tensor Transpose(Tensor X, int[] permutations) - { - if (!X.shape.Is4D() || permutations.Length != 4) - return Transpose8DHelper(X, permutations); - - Assert.AreEqual(permutations.Length, 4); - - X = GetTensorInCurrentMemoryLayoutHelper(X); - var O = X.shape.Permute(permutations); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Transpose", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - fn.shader.SetInts("_Pool", permutations); - return Dispatch(fn, X.dataType, O, X.channels, X.width, X.height); - } - - internal Tensor GetTensorInCurrentMemoryLayoutHelper(Tensor tensor) - { - //Return a tensor in the current memory layout from ComputeInfo.channelsOrder. - //Noop in the general case it will transpose constant tensor when ComputeInfo.channelsOrder == NCHW - //as those tensor are always in channel last layout. - //This is needed for kernel that can accept both input and constant tensor in the same argument. - if (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NCHW && - Pin(tensor).channelsOrder == ComputeInfo.ChannelsOrder.NHWC) - return TransposeToChannelFirstHelper(tensor); - else - return tensor; - } - - internal virtual Tensor TransposeToChannelFirstHelper(Tensor X) - { - var O = X.shape; - var fn = new ComputeFunc(ComputeShaderContext.Reference, "TransposeToChannelFirst", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - return Dispatch(fn, X.dataType, O, X.channels, X.width, X.height); - } - - internal static int[] s_ConcatOffsets = new int[4]; - /// - public override Tensor Concat(Tensor[] tensors, int axis) - { - if (axis != TensorShape.C && axis != -1) - return base.Concat(tensors, axis); - - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || !TensorExtensions.Is8DAxisConvertibleTo4D(axis)) - return base.Concat(tensors, axis); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Copy", GetModelExecutionsReporter()); - - var dataType = tensors.Length > 0 ? tensors[0].dataType : DataType.Float; - var O = NewTensor(dataType, TensorExtensions.Concat(tensors, axis), AllocScope.LayerOutput); - - var offsets = s_ConcatOffsets; - Array.Clear(offsets, 0, offsets.Length); - axis = O.shape.Axis(axis); - var axisNHWC = TensorExtensions.Convert8DAxisTo4D(axis); - - foreach (var inputTensor in tensors) - { - // input can be constants, in that cases the internal layout does not match ComputeInfo.channelsOrder and will allways be NHWC - // => permute if there is a layout mismatch - var X = GetTensorInCurrentMemoryLayoutHelper(inputTensor); - - SetTensor(fn, "X", X); - SetTensor(fn, "O", O); - - fn.shader.SetInts("_Pad", offsets); - - fn.Dispatch(X.channels, X.width, X.height); - - offsets[axisNHWC] += X.shape[axis]; - } - - return O; - } - - private void Set8DParamsForShader(int[] srcValues, int[] firstSplit, int[] secondSplit) - { - Assert.IsTrue(srcValues.Length == 8); - Assert.IsTrue(firstSplit.Length == 4); - Assert.IsTrue(secondSplit.Length == 4); - firstSplit[0] = srcValues[TensorShape.DataBatch]; - firstSplit[1] = srcValues[TensorShape.H]; - firstSplit[2] = srcValues[TensorShape.W]; - firstSplit[3] = srcValues[TensorShape.C]; - secondSplit[0] = srcValues[TensorShape.SequenceLength]; - secondSplit[1] = srcValues[TensorShape.NumberOfDirections]; - secondSplit[2] = srcValues[TensorShape.DataFeature3]; - secondSplit[3] = srcValues[TensorShape.D]; - } - - private unsafe void Set8DParamsForShader(int* srcValues, int[] firstSplit, int[] secondSplit) - { - Assert.IsTrue(firstSplit.Length == 4); - Assert.IsTrue(secondSplit.Length == 4); - firstSplit[0] = srcValues[TensorShape.DataBatch]; - firstSplit[1] = srcValues[TensorShape.H]; - firstSplit[2] = srcValues[TensorShape.W]; - firstSplit[3] = srcValues[TensorShape.C]; - secondSplit[0] = srcValues[TensorShape.SequenceLength]; - secondSplit[1] = srcValues[TensorShape.NumberOfDirections]; - secondSplit[2] = srcValues[TensorShape.DataFeature3]; - secondSplit[3] = srcValues[TensorShape.D]; - } - - static private int[] s_StridedSliceStart = new int[4]; - static private int[] s_StridedSliceStart8D = new int[4]; - static private int[] s_StridedSliceStride = new int[4]; - static private int[] s_StridedSliceStride8D = new int[4]; - /// - public override Tensor StridedSlice(Tensor X, int[] starts4Dor8D, int[] ends4Dor8D, int[] strides4Dor8D) - { - X = GetTensorInCurrentMemoryLayoutHelper(X); - - unsafe - { - int* starts = stackalloc int[TensorShape.MaxRank]; - int* ends = stackalloc int[TensorShape.MaxRank]; - int* strides = stackalloc int[TensorShape.MaxRank]; - TensorExtensions.Get8DParametersNoAlloc(X.shape, starts4Dor8D, starts, 0); - TensorExtensions.Get8DParametersNoAlloc(X.shape, ends4Dor8D, ends, 1); - TensorExtensions.Get8DParametersNoAlloc(X.shape, strides4Dor8D, strides, 1); - - var O = X.shape.ApplyStridedSlice8DUnsafeNoAlloc(starts, ends, strides); - - for (int i = 0; i < TensorShape.MaxRank; ++i) - starts[i] = Math.Min(TensorExtensions.WrapIndex(starts[i], X.shape[i]), X.shape[i] - 1); - - Set8DParamsForShader(strides, s_StridedSliceStride, s_StridedSliceStride8D); - Set8DParamsForShader(starts, s_StridedSliceStart, s_StridedSliceStart8D); - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "StridedSlice", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - fn.shader.SetInts("_Stride4D", s_StridedSliceStride); - fn.shader.SetInts("_Stride8D", s_StridedSliceStride8D); - fn.shader.SetInts("_Pad", s_StridedSliceStart); - fn.shader.SetInts("_Pool", s_StridedSliceStart8D); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - } - - /// - public override Tensor Tile(Tensor X, int[] repeats) - { - X = GetTensorInCurrentMemoryLayoutHelper(X); - - var O = X.shape.Scale(repeats); - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Tile", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - - return Dispatch(fn, X.dataType, O, O.channels, O.width, O.height); - } - - /// - public override Tensor Gather(Tensor[] tensors, int axis) - { - Tensor X = tensors[0]; - Tensor indices = tensors[1]; - - var outputShape = X.shape; - outputShape[axis] = indices.length; - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "Gather", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - SetTensor(fn, "K", indices); - fn.shader.SetInt("_Axis", axis); - - return Dispatch(fn, X.dataType, outputShape, outputShape.channels, outputShape.width, outputShape.height); - } - - /// - public override Tensor ScatterND(Tensor X, Tensor indices, Tensor updates, Layer.ScatterNDReductionMode reduction) - { - // only support for scattering on C for now - Assert.IsTrue(indices.batch == X.batch); - Assert.IsTrue(updates.width == X.width && updates.height == X.height); - var outputShape = X.shape; - - var fn = new ComputeFunc(ComputeShaderContext.Reference, "ScatterND", GetModelExecutionsReporter()); - SetTensor(fn, "X", X); - SetTensor(fn, "K", indices); - SetTensor(fn, "W", updates); - - fn.shader.SetInt("_Axis", (int)reduction); - - return Dispatch(fn, X.dataType, outputShape, outputShape.channels, outputShape.width, outputShape.height); - } - - /// - public override Tensor Copy(Tensor X) - { - return base.Copy(X); - } - - /// - public override Tensor Prepare(Tensor X) - { - Pin(X); - return X; - } - - /// - public override Tensor PrepareNoAlloc(Tensor X) - { - Pin(X, uploadCache: false); - return X; - } -} - -internal struct ComputeFunc -{ - // dispatch dimension limitation coming from D3D11 - public static uint SafeDispatchLimit = 65535; - - public struct TensorDecl - { - public int ShapeId { get; } - public int ShapeId8D { get; } - public int InfoId { get; } - - public TensorDecl(int shapeId, int shapeId8D, int infoId) - { - ShapeId = shapeId; - ShapeId8D = shapeId8D; - InfoId = infoId; - } - } - - private readonly IModelExecutionsReporter executionReporter; - readonly public ComputeShader shader; - readonly public string kernelName; - readonly public ComputeShaderContext computeShaderContext; - readonly public int kernelIndex; - readonly public uint threadGroupSizeX; - readonly public uint threadGroupSizeY; - readonly public uint threadGroupSizeZ; - public uint threadGroupSize { get { return threadGroupSizeX * threadGroupSizeY * threadGroupSizeZ; } } - - public int width { get { return (int)threadGroupSizeX; } } - public int height { get { return (int)threadGroupSizeY; } } - public int depth { get { return (int)threadGroupSizeZ; } } - - static public TensorDecl GetTensorDecl(string name) - { - var shapeId = Shader.PropertyToID(s_StringCache.Lookup(name, "declShape")); - var shapeId8D = Shader.PropertyToID(s_StringCache.Lookup(name, "declShape8D")); - var infoId = Shader.PropertyToID(s_StringCache.Lookup(name, "declInfo")); - return new TensorDecl(shapeId, shapeId8D, infoId); - } - static public int GetTensorData(string name ) { return Shader.PropertyToID(s_StringCache.Lookup(name, "data")); } - - static private StringCache s_StringCache = new StringCache(); - - static private Texture2D s_DummyTexture2D; - static private Texture3D s_DummyTexture3D; - static private Texture2DArray s_DummyTexture2DArray; - - static private Texture2D dummyTexture2D { - get - { - if (s_DummyTexture2D == null) - s_DummyTexture2D = new Texture2D(8, 8); - return s_DummyTexture2D; - } - } - - static private Texture3D dummyTexture3D - { - get - { - if (s_DummyTexture3D == null) - s_DummyTexture3D = new Texture3D(8, 8, 1, TextureFormat.ARGB32, false); - return s_DummyTexture3D; - } - } - - static private Texture2DArray dummyTexture2DArray - { - get - { - if (s_DummyTexture2DArray == null) - s_DummyTexture2DArray = new Texture2DArray(8, 8, 1, TextureFormat.ARGB32, false); - return s_DummyTexture2DArray; - } - } - - // --------------------------------------------------------------------------------- - public ComputeFunc(ComputeShaderContext ctx, string kn, IModelExecutionsReporter reporter) - { - executionReporter = reporter; - string kernelNameWithChannelsOrder = s_StringCache.Lookup(kn, - (ComputeInfo.channelsOrder == ComputeInfo.ChannelsOrder.NHWC) ? "_NHWC" : "_NCHW"); - - var s = ComputeShaderSingleton.Instance.FindComputeShader(ctx, kernelNameWithChannelsOrder) ?? - ComputeShaderSingleton.Instance.FindComputeShader(ctx, kn); - - if (s != null && (s.HasKernel(kernelNameWithChannelsOrder) || s.HasKernel(kn))) - { - shader = s; - kernelName = s.HasKernel(kernelNameWithChannelsOrder)?kernelNameWithChannelsOrder:kn; - computeShaderContext = ctx; - kernelIndex = shader.FindKernel(kernelName); - shader.GetKernelThreadGroupSizes(kernelIndex, out threadGroupSizeX, out threadGroupSizeY, out threadGroupSizeZ); - return; - } - - throw new ArgumentException($"Kernel {kn} and {kernelNameWithChannelsOrder} are both missing"); - } - - // --------------------------------------------------------------------------------- - - public void SetTensor(string name, TensorShape shape, ComputeBuffer buffer, Int64 dataOffset = 0) - { - SetTensorDecl(name, shape, dataOffset); - SetTensorBuffer(name, buffer); - } - public void SetTensor(ComputeFunc.TensorDecl tensorDecl, int dataPropId, TensorShape shape, ComputeBuffer buffer, Int64 dataOffset = 0) - { - SetTensorDecl(tensorDecl, shape, dataOffset); - SetTensorBuffer(dataPropId, buffer); - } - - public void SetTensor(string name, TensorShape shape, Texture texture, Int64 dataOffset = 0) - { - SetTensorDecl(name, shape, dataOffset); - SetTexture(name, texture); - } - - public void SetTensorDecl(string name, TensorShape shape, Int64 dataOffset) - { - ComputeFunc.TensorDecl tensorDecl = GetTensorDecl(name); - SetTensorDecl(tensorDecl, shape, dataOffset); - } - - // WARN: SetTensorDecl() is not multi-thread safe due to s_TensorDeclScratchpad usage - // However there is no plan to call SetTensorDecl() from multiple threads - // NOTE: s_TensorDeclScratchpad is used to avoid memory allocation - static private int[] s_tTensorDeclScratchpadShape = new int[4]; - static private int[] s_tTensorDeclScratchpadShape8D = new int[4]; - static private int[] s_tTensorDeclScratchpadInfo = new int[2]; - public void SetTensorDecl(ComputeFunc.TensorDecl tensorDecl, TensorShape shape, Int64 dataOffset) - { - s_tTensorDeclScratchpadShape[0] = shape.batch; - s_tTensorDeclScratchpadShape[1] = shape.height; - s_tTensorDeclScratchpadShape[2] = shape.width; - s_tTensorDeclScratchpadShape[3] = shape.channels; - s_tTensorDeclScratchpadShape8D[0] = shape.sequenceLength; - s_tTensorDeclScratchpadShape8D[1] = shape.numberOfDirections; - s_tTensorDeclScratchpadShape8D[2] = shape.extraDimension; - s_tTensorDeclScratchpadShape8D[3] = shape.depth; - s_tTensorDeclScratchpadInfo[0] = (int)dataOffset; - s_tTensorDeclScratchpadInfo[1] = shape.length; - shader.SetInts(tensorDecl.ShapeId8D, s_tTensorDeclScratchpadShape8D); - shader.SetInts(tensorDecl.ShapeId, s_tTensorDeclScratchpadShape); - shader.SetInts(tensorDecl.InfoId, s_tTensorDeclScratchpadInfo); - } - - public void SetTensorBuffer(string name, ComputeBuffer buffer) - { - shader.SetBuffer(kernelIndex, GetTensorData(name), buffer); - } - public void SetTensorBuffer(int propId, ComputeBuffer buffer) - { - shader.SetBuffer(kernelIndex, propId, buffer); - } - - public void SetTexture(string name, Texture tex) - { - // set dummy textures for slots that are not used - to make API validation layers happy - Texture tex2D = dummyTexture2D; - Texture tex2Darray = dummyTexture2DArray; - Texture tex3D = dummyTexture3D; - - if (tex.dimension == TextureDimension.Tex2D) - tex2D = tex; - else if (tex.dimension == TextureDimension.Tex2DArray) - tex2Darray = tex; - else if (tex.dimension == TextureDimension.Tex3D) - tex3D = tex; - else - throw new InvalidOperationException("Unsupported texture type"); - - shader.SetTexture(kernelIndex, name + "tex2D", tex2D); - shader.SetTexture(kernelIndex, name + "tex3D", tex3D); - shader.SetTexture(kernelIndex, name + "tex2DArray", tex2Darray); - } - - public void Dispatch(ValueTuple workItems) - { - Dispatch(workItems.Item1, workItems.Item2, workItems.Item3); - } - - public void Dispatch(int workItemsX, int workItemsY, int workItemsZ) - { - Profiler.BeginSample(kernelName); - var x = IntDivCeil(workItemsX, (int) threadGroupSizeX); - var y = IntDivCeil(workItemsY, (int) threadGroupSizeY); - var z = IntDivCeil(workItemsZ, (int) threadGroupSizeZ); - - // some GFX APIs / GPU hw/drivers have limitation of 65535 per dimension - if (x > SafeDispatchLimit || y > SafeDispatchLimit || z > SafeDispatchLimit) - D.LogWarning($"Exceeded safe compute dispatch group count limit per dimension [{x}, {y}, {z}] for {kernelName}"); - - - ComputeDebugUtils.PrepareDispatch(); - -#if ENABLE_BARRACUDA_STATS - if (executionReporter != null) - { - var dispatchInfo = DispatchInfo.CreateFromComputeFunc(this, workItemsX, workItemsY, workItemsZ); - executionReporter.AddLayerDispatch(dispatchInfo); - } -#endif //ENABLE_BARRACUDA_STATS - - shader.Dispatch(kernelIndex, x, y, z); - - ComputeDebugUtils.VerifyDispatch(kernelName); - - Profiler.EndSample(); - } - - // --------------------------------------------------------------------------------- - - static public int IntDivCeil(int v, int div) - { - return (v + div - 1) / div; - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCompute.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCompute.cs.meta deleted file mode 100644 index 4fb005e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaReferenceCompute.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3e48b2167ab1b453bb10a8fdac9dc531 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaUnsafeArrayCPU.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaUnsafeArrayCPU.cs deleted file mode 100644 index b2b46c2..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaUnsafeArrayCPU.cs +++ /dev/null @@ -1,4789 +0,0 @@ -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; -using Unity.Collections; // Allocator -using Unity.Collections.LowLevel.Unsafe; // UnsafeUtility.Malloc -using System; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using System.Security; - - -namespace Unity.Barracuda { - -/// -/// `Tensor` data storage based on unsafe array -/// -public class UnsafeArrayTensorData : SharedArrayTensorData -{ - readonly internal bool m_Readonly = false; - - /// - /// Create `UnsafeArrayTensorData` with new array - /// - /// element count to reserve - public UnsafeArrayTensorData(int count, DataType dataType) : base(new BarracudaArray(count, dataType)) - { - } - - /// - /// Create `UnsafeArrayTensorData` with new array - /// - /// shape - public UnsafeArrayTensorData(TensorShape shape, DataType dataType) : this(shape.length, dataType) - { - } - - /// - /// Create `UnsafeArrayTensorData` and use shared array - /// - /// shared array - public UnsafeArrayTensorData(ArrayTensorData sharedArray) : base(sharedArray.array) - { - } - - /// - /// Create `UnsafeArrayTensorData` and use shared array - /// - /// shared array - public UnsafeArrayTensorData(SharedArrayTensorData sharedArray) : base(sharedArray.array, sharedArray.offset, sharedArray.count) - { - m_Readonly = true; - } - - /// - /// Create `UnsafeArrayTensorData` from supplied array - /// - /// data - /// offset in `data` - /// element count - /// read-only flag - protected UnsafeArrayTensorData(BarracudaArray data, int offset = 0, int count = -1, bool isReadonly = false) : base(data, offset, count) - { - m_Readonly = isReadonly; - } - - /// - /// Finalizer - /// - ~UnsafeArrayTensorData() - { - Dispose(); - } - - /// - /// Dispose - /// - public override void Dispose() - { - m_Array = null; - m_Offset = m_Count = 0; - } - - /// - public override void Reserve(int count) - { - if (m_Readonly) - { - base.Reserve(count); - return; - } - - if (count > maxCapacity) - { - m_Array = new BarracudaArray(count, m_Array.Type); - m_Offset = 0; - m_Count = m_Array.Length; - } - } - - /// - public override void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0) - { - if (m_Readonly) - { - base.Upload(data, shape, managedBufferStartIndex); - return; - } - - var numItemToCopy = shape.length; - var numItemAvailableInData = data.Length - managedBufferStartIndex; - Assert.IsTrue(managedBufferStartIndex >= 0); - Assert.IsTrue(numItemToCopy <= numItemAvailableInData); - - Reserve(numItemToCopy); - BarracudaArray.Copy(data, managedBufferStartIndex, m_Array, m_Offset, numItemToCopy); - } - - /// - /// Summary - /// - /// summary - public override string ToString() - { - return string.Format("(CPU unsafe: {0} length: {1} offset: {2} uploaded: {3})", - GetHashCode(), m_Array.Length, m_Offset, m_Count); - } -} - -/// -/// Unsafe array based `IOps` implementation -/// -public class UnsafeArrayCPUOps : ReferenceCPUOps -{ - internal BLASPlugin blas => m_Blas; - internal InnerLoop m_InnerLoop = new InnerLoop(); - - BLASPlugin m_Blas; - - /// - /// Create `UnsafeArrayCPUOps` - /// - /// allocator - public UnsafeArrayCPUOps(ITensorAllocator allocator = null) - : base(allocator) - { - m_Blas = BLASPluginFactory.CreateBLASPlugin(); - } - - /// - /// Pin specified `Tensor` to unsafe array based CPU device, if `uploadCache` is false, data is not uploaded to device - /// - /// `Tensor` - /// `bool` - /// `UnsafeArrayTensorData` - public static UnsafeArrayTensorData Pin(Tensor X, bool uploadCache = true) - { - X.FlushCache(uploadCache); - - // @TODO: consider abstracting job specific behavior and moving into ITensorData interface - var asBurstArray = X.tensorOnDevice as BurstTensorData; - if (asBurstArray != null) - { - asBurstArray.fence.Complete(); - asBurstArray.reuse.Complete(); - } - - var onDevice = X.tensorOnDevice as UnsafeArrayTensorData; - if (onDevice == null) - { - // try to adopt CPU arrays - var asSharedArray = X.tensorOnDevice as SharedArrayTensorData; - var asArray = X.tensorOnDevice as ArrayTensorData; - if (asSharedArray != null) X.AttachToDevice(new UnsafeArrayTensorData(asSharedArray)); - else if (asArray != null) X.AttachToDevice(new UnsafeArrayTensorData(asArray)); - else - { - if (uploadCache) - X.UploadToDevice(new UnsafeArrayTensorData(X.shape, X.dataType)); // device is not compatible, create new array and upload - else - X.AllocateOnDevice(new UnsafeArrayTensorData(X.shape, X.dataType)); // device is not compatible, create new array and upload - } - } - - return X.tensorOnDevice as UnsafeArrayTensorData; - } - - // --------------------------------------------------------------------------------- - - // NOTE: Parallel.For with small number of work items results in varying and often worse performance - // As a workaround we will fallback to 'for' loop when number of work items is below heuristically determined threshold - internal static void Parallel_For(long begin, long end, Action body) - { - if (end - begin > 2048) // threshold determined heuristically. If work items < threshold, then for loop is faster than Parallel.For() - Parallel.For(begin, end, body); - else - for(var n = begin; n < end; n++) - body(n); - } - - /// - public override Tensor Neg(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Neg(X); - - // f(x) = -x - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - NegInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - oPtr[i] = -xPtr[i]; - } - } - } - - return O; - } - - /// - private unsafe void NegInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_negInnerLoopDelegate); - } - - /// - public override Tensor Relu(Tensor X) - { - if (X.dataType != DataType.Float) - return base.Relu(X); - - // f(x) = max(x,0.0) - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 64; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - ReluInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = 0.5f * (v + Math.Abs(v)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void ReluInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 64); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_reluInnerLoopDelegate); - } - - /// - public override Tensor Relu6(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Relu6(X); - - // f(x) = min(max(x, 0), 6) - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 64; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - Relu6InnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = 0.5f * (-Math.Abs(v - 6f) + Math.Abs(v) + 6f); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void Relu6InnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 64); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_relu6InnerLoopDelegate); - } - - /// - public override Tensor LeakyRelu(Tensor X, float alpha) - { - if (AreAnyTensorsHalf(X)) - return base.LeakyRelu(X, alpha); - - // f(x) = alpha * x for x < 0, f(x) = x for x >= 0. - Assert.IsTrue(alpha <= 1); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 64; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - LeakyReluInnerLoop(end, unrollSize, xPtr, oPtr, alpha); - - // from Theano impl - // https://github.com/Theano/theano/blob/d395439aec5a6ddde8ef5c266fd976412a5c5695/theano/tensor/nnet/nnet.py#L2209-L2251 - float f1 = 0.5f * (1f + alpha); - float f2 = 0.5f * (1f - alpha); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = f1 * v + f2 * Math.Abs(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void LeakyReluInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr, float alpha) - { - Assert.AreEqual(unrollSize, 64); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr, alpha); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_leakyReluInnerLoopDelegate); - } - - /// - public override Tensor Elu(Tensor X, float alpha) - { - if (AreAnyTensorsHalf(X)) - return base.Elu(X, alpha); - - // f(x) = alpha * (exp(x) - 1.) for x < 0, f(x) = x for x >= 0 - // "Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs)", DA Clevert, 2015 - // https://arxiv.org/abs/1511.07289 - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - EluInnerLoop(end, unrollSize, xPtr, oPtr, alpha); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - if (v <= 0) - v = alpha * (Mathf.Exp(v) - 1f); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void EluInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr, float alpha) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr, alpha); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_eluInnerLoopDelegate); - } - - /// - public override Tensor PRelu(Tensor X, Tensor S) - { - if (AreAnyTensorsHalf(X, S)) - return base.PRelu(X, S); - - Assert.IsTrue((X.flatWidth == S.flatWidth) || (S.flatWidth == 1)); - - // f(x) = x for x >= 0, f(x) = slope*x for x <= 0 - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - float* wPtr = Pin(S).array.AddressAt(Pin(S).offset); - { - PReluInnerLoop(end, unrollSize, xPtr, X.length, oPtr, wPtr, S.length); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - float slope = wPtr[i % S.length]; - v = Mathf.Max(0.0f, v) + slope * Mathf.Min(0.0f, v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void PReluInnerLoop(int length, int unrollSize, float* xPtr, int xLen, float* oPtr, float* wPtr, int wLen) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, oPtr, xPtr, xLen, wPtr, wLen); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_preluInnerLoopDelegate); - } - - /// - public override Tensor Softplus(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Softplus(X); - - // f(x) = 1 / (1 + exp(-x)) - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - SoftplusInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Log(Mathf.Exp(v) + 1f); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void SoftplusInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_softplusInnerLoopDelegate); - } - - /// - public override Tensor Sigmoid(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Sigmoid(X); - - // f(x) = 1 / (1 + exp(-x)) - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - SigmoidInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = 1f / (1f + Mathf.Exp(-v)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void SigmoidInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_sigmoidInnerLoopDelegate); - } - - /// - public override Tensor HardSigmoid(Tensor X, float alpha, float beta) - { - if (AreAnyTensorsHalf(X)) - return base.HardSigmoid(X, alpha, beta); - - // f(x) = 1 / (1 + exp(-x)) - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - HardSigmoidInnerLoop(end, unrollSize, xPtr, oPtr, alpha, beta); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Max(0.0f, Mathf.Min(1.0f, alpha * v + beta)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void HardSigmoidInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr, float alpha, float beta) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr, alpha, beta); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_hardsigmoidInnerLoopDelegate); - } - - /// - public override Tensor Swish(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Swish(X); - - // f(x) = sigmoid(x) * x = x / (1 + exp(-x)) - // "Searching for Activation Functions". P Ramachandran, 2017 - // https://arxiv.org/abs/1710.05941 - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - SwishInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = v / (1f + Mathf.Exp(-v)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void SwishInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_swishInnerLoopDelegate); - } - - /// - public override Tensor Exp(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Exp(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - ExpInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Exp(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void ExpInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_expInnerLoopDelegate); - } - - /// - public override Tensor Sqrt(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Sqrt(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - SqrtInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Sqrt(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void SqrtInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_sqrtInnerLoopDelegate); - } - - /// - public override Tensor Tanh(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Tanh(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - TanhInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = MathfEx.Tanh(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void TanhInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_tanhInnerLoopDelegate); - } - - /// - public override Tensor Acos(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Acos(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - AcosInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Acos(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void AcosInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_acosInnerLoopDelegate); - } - - /// - public override Tensor Acosh(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Acosh(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - AcoshInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Log(v + Mathf.Sqrt(v*v - 1.0f)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void AcoshInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_acoshInnerLoopDelegate); - } - - /// - public override Tensor Asin(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Asin(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - AsinInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Asin(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void AsinInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_asinInnerLoopDelegate); - } - - /// - public override Tensor Asinh(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Asinh(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - AsinhInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Log(v + Mathf.Sqrt(v*v + 1.0f)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void AsinhInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_asinhInnerLoopDelegate); - } - - /// - public override Tensor Atan(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Atan(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - AtanInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Atan(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void AtanInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_atanInnerLoopDelegate); - } - - /// - public override Tensor Atanh(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Atanh(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - AtanhInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = 0.5f * Mathf.Log((1.0f + v)/(1.0f - v)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void AtanhInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_atanhInnerLoopDelegate); - } - - /// - public override Tensor Cos(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Cos(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - CosInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Cos(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void CosInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_cosInnerLoopDelegate); - } - - /// - public override Tensor Cosh(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Cosh(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - CoshInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = 0.5f * (Mathf.Exp(v) + Mathf.Exp(-v)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void CoshInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_coshInnerLoopDelegate); - } - - /// - public override Tensor Sin(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Sin(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - SinInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Sin(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void SinInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_sinInnerLoopDelegate); - } - - /// - public override Tensor Sinh(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Sinh(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - SinhInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = 0.5f * (Mathf.Exp(v) - Mathf.Exp(-v)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void SinhInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_sinhInnerLoopDelegate); - } - - /// - public override Tensor Tan(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Tan(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - TanInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - v = Mathf.Tan(v); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void TanInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_tanInnerLoopDelegate); - } - - /// - public override Tensor Erf(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Erf(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - ErfInnerLoop(end, unrollSize, xPtr, oPtr); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x = Mathf.Abs(v); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t = 1.0f / (1.0f + p * x); - float t2 = t * t; - float t3 = t2 * t; - float t4 = t3 * t; - float t5 = t4 * t; - - v = Mathf.Sign(v) * (1 - (a1 * t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5) * Mathf.Exp(-x * x)); - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void ErfInnerLoop(int length, int unrollSize, float* xPtr, float* oPtr) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_erfInnerLoopDelegate); - } - - private bool CanUseModuloForBroadcasting(TensorShape o, TensorShape a) - { - // last to first: dimensions must be equal. if not equal all rest must be 1 - if (o == a) - return true; - - bool dimensionMismatch = false; - for (int i = TensorShape.MaxRank - 1; i >= 0; --i) - { - if (dimensionMismatch) - { - if (a[i] != 1) - return false; - } - else - { - dimensionMismatch = (o[i] != a[i]); - } - } - - return true; - } - - private bool CanUseModuloForBroadcasting(TensorShape o, TensorShape a, TensorShape b) - { - return CanUseModuloForBroadcasting(o,a) && CanUseModuloForBroadcasting(o,b); - } - - private Tensor ApplyElementwiseWithBroadcast(Tensor[] tensors, Func opRemainder, Action opInnerLoop, Action opInnerLoopNoBroadcast) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || AreAnyTensorsHalf(tensors)) - throw new NotImplementedException(); - - var O = NewTensorLike(tensors, AllocScope.LayerOutput); - var A = tensors[0]; - - unsafe - { - float* t0Ptr = Pin(A).array.AddressAt(Pin(A).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - float* aPtr = t0Ptr; - var aShape = A.shape; - - for (int t = 1; t < tensors.Length; ++t) - { - var B = tensors[t]; - float* bPtr = Pin(B).array.AddressAt(Pin(B).offset); - { - //Inner loop - const int unrollSize = 4; - m_InnerLoop.SetState(unrollSize, oPtr, aPtr, bPtr, O.shape, aShape, B.shape); - if (CanUseModuloForBroadcasting(O.shape, aShape, B.shape)) - Parallel_For(0L, O.length / unrollSize, opInnerLoopNoBroadcast); - else - Parallel_For(0L, O.length / unrollSize, opInnerLoop); - - - // Remainder - for (int i = (O.length / unrollSize) * unrollSize; i < O.length; ++i) - { - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - O.shape.GetPositionsFromIndex(i, ref b0, ref h0, ref w0, ref ch0); - oPtr[i] = opRemainder(aPtr[A.shape.IndexWithBroadcast(b0, h0, w0, ch0)], bPtr[B.shape.IndexWithBroadcast(b0, h0, w0, ch0)]); - } - } - - aPtr = oPtr; - aShape = O.shape; - } - } - } - - return O; - } - - /// - public override Tensor Add(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || AreAnyTensorsHalf(tensors)) - return base.Add(tensors); - - return ApplyElementwiseWithBroadcast(tensors, m_InnerLoop.m_addOpDelegate, m_InnerLoop.m_addInnerLoopDelegate, m_InnerLoop.m_addInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor Sub(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || AreAnyTensorsHalf(tensors)) - return base.Sub(tensors); - - return ApplyElementwiseWithBroadcast(tensors, m_InnerLoop.m_subOpDelegate, m_InnerLoop.m_subInnerLoopDelegate, m_InnerLoop.m_subInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor Mul(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || AreAnyTensorsHalf(tensors)) - return base.Mul(tensors); - - return ApplyElementwiseWithBroadcast(tensors, m_InnerLoop.m_mulOpDelegate, m_InnerLoop.m_mulInnerLoopDelegate, m_InnerLoop.m_mulInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor Div(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || AreAnyTensorsHalf(tensors)) - return base.Div(tensors); - - return ApplyElementwiseWithBroadcast(tensors, m_InnerLoop.m_divOpDelegate, m_InnerLoop.m_divInnerLoopDelegate, m_InnerLoop.m_divInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor Min(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || AreAnyTensorsHalf(tensors)) - return base.Min(tensors); - - return ApplyElementwiseWithBroadcast(tensors, m_InnerLoop.m_minOpDelegate, m_InnerLoop.m_minInnerLoopDelegate, m_InnerLoop.m_minInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor Max(Tensor[] tensors) - { - if (!TensorExtensions.AreAllTensorsConvertibleTo4D(tensors) || AreAnyTensorsHalf(tensors)) - return base.Max(tensors); - - return ApplyElementwiseWithBroadcast(tensors, m_InnerLoop.m_maxOpDelegate, m_InnerLoop.m_maxInnerLoopDelegate, m_InnerLoop.m_maxInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor Greater(Tensor A, Tensor B) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - return base.Greater(A,B); - - return ApplyLogicalOperator(A, B, m_InnerLoop.m_greaterOpDelegate, m_InnerLoop.m_greaterInnerLoopDelegate, m_InnerLoop.m_greaterInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor GreaterEqual(Tensor A, Tensor B) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - return base.GreaterEqual(A,B); - - return ApplyLogicalOperator(A, B, m_InnerLoop.m_greaterEqualOpDelegate, m_InnerLoop.m_greaterEqualInnerLoopDelegate, m_InnerLoop.m_greaterEqualInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor Less(Tensor A, Tensor B) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - return base.Less(A,B); - - return ApplyLogicalOperator(A, B, m_InnerLoop.m_lessOpDelegate, m_InnerLoop.m_lessInnerLoopDelegate, m_InnerLoop.m_lessInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor LessEqual(Tensor A, Tensor B) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - return base.LessEqual(A,B); - - return ApplyLogicalOperator(A, B, m_InnerLoop.m_lessEqualOpDelegate, m_InnerLoop.m_lessEqualInnerLoopDelegate, m_InnerLoop.m_lessEqualInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor Equal(Tensor A, Tensor B) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - return base.Equal(A,B); - - return ApplyLogicalOperator(A, B, m_InnerLoop.m_equalOpDelegate, m_InnerLoop.m_equalInnerLoopDelegate, m_InnerLoop.m_equalInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor LogicalOr(Tensor A, Tensor B) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - return base.LogicalOr(A,B); - - return ApplyLogicalOperator(A, B, m_InnerLoop.m_logicalOrOpDelegate, m_InnerLoop.m_logicalOrInnerLoopDelegate, m_InnerLoop.m_logicalOrInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor LogicalAnd(Tensor A, Tensor B) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - return base.LogicalAnd(A,B); - - return ApplyLogicalOperator(A, B, m_InnerLoop.m_logicalAndOpDelegate, m_InnerLoop.m_logicalAndInnerLoopDelegate, m_InnerLoop.m_logicalAndInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor LogicalXor(Tensor A, Tensor B) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - return base.LogicalXor(A,B); - - return ApplyLogicalOperator(A, B, m_InnerLoop.m_logicalXorOpDelegate, m_InnerLoop.m_logicalXorInnerLoopDelegate, m_InnerLoop.m_logicalXorInnerLoopDelegateNoBroadcast); - } - - /// - public override Tensor LogicalNot(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.LogicalNot(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - const int unrollSize = 4; - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - Parallel_For(0L, O.length / unrollSize, m_InnerLoop.m_logicalNotInnerLoopDelegate); - - // Remainder - for (int i = (O.length / unrollSize) * unrollSize; i < O.length; ++i) - oPtr[i] = Convert.ToSingle( !Convert.ToBoolean(xPtr[i]) ); - } - } - return O; - } - - /// - public override Tensor Sign(Tensor X) - { - if (AreAnyTensorsHalf(X)) - return base.Sign(X); - - var O = NewTensorLike(X, AllocScope.LayerOutput); - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - const int unrollSize = 4; - m_InnerLoop.SetState(unrollSize, xPtr, oPtr); - Parallel_For(0L, O.length / unrollSize, m_InnerLoop.m_signInnerLoopDelegate); - - // Remainder - for (int i = (O.length / unrollSize) * unrollSize; i < O.length; ++i) - oPtr[i] = (xPtr[i] > 0) ? 1.0f : ((xPtr[i] < 0) ? -1.0f : 0.0f); - } - } - return O; - } - - /// - public override Tensor Where(Tensor C, Tensor A, Tensor B) - { - if (!C.shape.Is4D() || !C.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(C,A,B)) - return base.Where(C,A,B); - - var O = NewTensorLike(new [] { C, A, B }, AllocScope.LayerOutput); - - unsafe - { - float* cPtr = Pin(C).array.AddressAt(Pin(C).offset); - float* aPtr = Pin(A).array.AddressAt(Pin(A).offset); - float* bPtr = Pin(B).array.AddressAt(Pin(B).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - const int unrollSize = 4; - m_InnerLoop.SetState(unrollSize, oPtr, cPtr, aPtr, bPtr, O.shape, C.shape, A.shape, B.shape); - if ((O.shape == A.shape) && (O.shape == B.shape)) - Parallel_For(0L, O.length / unrollSize, m_InnerLoop.m_whereInnerLoopDelegateNoBroadcast); - else - Parallel_For(0L, O.length / unrollSize, m_InnerLoop.m_whereInnerLoopDelegate); - - // Remainder - for (int i = (O.length / unrollSize) * unrollSize; i < O.length; ++i) - { - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - O.shape.GetPositionsFromIndex(i, ref b0, ref h0, ref w0, ref ch0); - oPtr[i] = Convert.ToBoolean(cPtr[C.shape.IndexWithBroadcast(b0, h0, w0, ch0)]) ? aPtr[A.shape.IndexWithBroadcast(b0, h0, w0, ch0)] : bPtr[B.shape.IndexWithBroadcast(b0, h0, w0, ch0)]; - } - } - } - - return O; - } - - private Tensor ApplyLogicalOperator(Tensor A, Tensor B, Func logicalOpRemainder, Action logicalOpInnerLoop, Action logicalOpInnerLoopNoBroadcast) - { - if (!A.shape.Is4D() || !B.shape.Is4D() || AreAnyTensorsHalf(A, B)) - throw new NotImplementedException(); - - var O = NewTensorLike(new Tensor[] { A, B }, AllocScope.LayerOutput); - - unsafe - { - float* aPtr = Pin(A).array.AddressAt(Pin(A).offset); - float* bPtr = Pin(B).array.AddressAt(Pin(B).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - const int unrollSize = 4; - m_InnerLoop.SetState(unrollSize, oPtr, aPtr, bPtr, O.shape, A.shape, B.shape); - if ((O.shape == A.shape) && (O.shape == B.shape)) - Parallel_For(0L, O.length / unrollSize, logicalOpInnerLoopNoBroadcast); - else - Parallel_For(0L, O.length / unrollSize, logicalOpInnerLoop); - - // Remainder - for (int i = (O.length / unrollSize) * unrollSize; i < O.length; ++i) - { - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - O.shape.GetPositionsFromIndex(i, ref b0, ref h0, ref w0, ref ch0); - oPtr[i] = logicalOpRemainder(aPtr[A.shape.IndexWithBroadcast(b0, h0, w0, ch0)], bPtr[B.shape.IndexWithBroadcast(b0, h0, w0, ch0)]); - } - } - } - - return O; - } - - /// - public override Tensor MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - if (AreAnyTensorsHalf(X,Y)) - return base.MatMul(X, xTranspose, Y, yTranspose); - - Assert.IsTrue(X.dimensions <= 2); - Assert.IsTrue(Y.dimensions <= 2); - - int xw = X.flatWidth, xh = X.flatHeight; - int yw = Y.flatWidth, yh = Y.flatHeight; - - if (xTranspose) - { - var tmp = xw; xw = xh; xh = tmp; - } - if (yTranspose) - { - var tmp = yw; yw = yh; yh = tmp; - } - - Assert.AreEqual(xw, yh); - var O = NewOutputTensor(X.dataType, new TensorShape(xh, yw)); - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* yPtr = Pin(Y).array.AddressAt(Pin(Y).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - // zero-initialize before SGEMM - UnsafeUtility.MemClear(oPtr, O.length * sizeof(float)); - - //D.Log(string.Format("===> X.b[{0}] x Y.w[{1}] * Y.h[{2}] x Y.w[{3}] = O.w[{4}] x O.h[{5}]", X.flatHeight, X.flatWidth, Y.flatHeight, Y.flatWidth, O.batch, O.width)); - blas.SGEMM( - xPtr, X.flatHeight, X.flatWidth, - yPtr, Y.flatHeight, Y.flatWidth, - oPtr, O.flatHeight, O.flatWidth, 16, xTranspose, yTranspose); - } - } - - return O; - } - - /// - public override Tensor Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - if (AreAnyTensorsHalf(X,W,B)) - return base.Dense(X, W, B, fusedActivation); - - //D.Log(string.Format("X = {0}", X.shape)); - Assert.IsTrue(W.dimensions <= 2); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(B.flatWidth, W.flatWidth); - Assert.AreEqual(X.flatWidth, W.flatHeight); - var O = NewTensorForFusedActivation(X.dataType, new TensorShape(X.flatHeight, W.flatWidth), fusedActivation); - - var pinX = Pin(X); - var pinW = Pin(W); - var pinB = Pin(B); - var pinO = Pin(O, uploadCache:false); - - unsafe - { - float* xPtr = pinX.array.AddressAt(pinX.offset); - float* wPtr = pinW.array.AddressAt(pinW.offset); - float* bPtr = pinB.array.AddressAt(pinB.offset); - float* oPtr = pinO.array.AddressAt(pinO.offset); - { - var count = B.flatWidth; - - for (int i = 0; i < O.flatHeight; i++) - { - UnsafeUtility.MemCpy(oPtr + pinO.offset + i * count, bPtr, count * sizeof(float)); - } - - //X.Print(); W.Print(); - blas.SGEMM( - xPtr, X.flatHeight, X.flatWidth, - wPtr, W.flatHeight, W.flatWidth, - oPtr, O.flatHeight, O.flatWidth, 16); - } - } - - return ApplyFusedActivation(O, fusedActivation); - } - - /// - /// Apply fused activation - /// - /// input - /// fused activation type - /// output `Tensor` - /// thrown if unsupported activation type encountered - protected Tensor ApplyFusedActivation(Tensor X, Layer.FusedActivation fusedActivation) - { - switch (fusedActivation) - { - case Layer.FusedActivation.None: - return X; - case Layer.FusedActivation.Relu: - return Relu(X); - case Layer.FusedActivation.Tanh: - return Tanh(X); - case Layer.FusedActivation.Softplus: - return Softplus(X); - case Layer.FusedActivation.Sigmoid: - return Sigmoid(X); - case Layer.FusedActivation.Relu6: - return Relu6(X); - case Layer.FusedActivation.Swish: - return Swish(X); - case Layer.FusedActivation.Neg: - return Neg(X); - case Layer.FusedActivation.Sqrt: - return Sqrt(X); - case Layer.FusedActivation.Exp: - return Exp(X); - case Layer.FusedActivation.Log: - return Log(X); - case Layer.FusedActivation.Acos: - return Acos(X); - case Layer.FusedActivation.Acosh: - return Acosh(X); - case Layer.FusedActivation.Asin: - return Asin(X); - case Layer.FusedActivation.Asinh: - return Asinh(X); - case Layer.FusedActivation.Atan: - return Atan(X); - case Layer.FusedActivation.Atanh: - return Atanh(X); - case Layer.FusedActivation.Cos: - return Cos(X); - case Layer.FusedActivation.Cosh: - return Cosh(X); - case Layer.FusedActivation.Sin: - return Sin(X); - case Layer.FusedActivation.Sinh: - return Sinh(X); - case Layer.FusedActivation.Tan: - return Tan(X); - case Layer.FusedActivation.Erf: - return Erf(X); - default: - throw new NotImplementedException(); - } - } - - /// - public override Tensor MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - if (AreAnyTensorsHalf(X)) - return base.MaxPool2D(X, pool, stride, pad); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewOutputTensor(X.dataType, X.shape.ApplyPool(pool, stride, pad)); - - int xnMult = X.height * X.width * X.channels; - int xyMult = X.width * X.channels; - int xxMult = X.channels; - - int onMult = O.height * O.width * O.channels; - int oyMult = O.width * O.channels; - int oxMult = O.channels; - - int oBatch = O.batch; - int oHeight = O.height; - int oWidth = O.width; - int oChannels = O.channels; - int xHeight = X.height; - int xWidth = X.width; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - MaxPool2DInnerLoop(pool, stride, pad, - xHeight, xWidth, xPtr, xnMult, xyMult, xxMult, - oBatch, oHeight, oWidth, oChannels, oPtr, onMult, oyMult, oxMult); - } - } - - return O; - } - - private static unsafe void MaxPool2DInnerLoop(int[] pool, int[] stride, int[] pad, - int xHeight, int xWidth, float* xPtr, int xnMult, int xyMult, int xxMult, - int oBatch, int oHeight, int oWidth, int oChannels, float* oPtr, int onMult, int oyMult, int oxMult) - { - Parallel.For(0, oBatch, n => - { - for (var y = 0; y < oHeight; ++y) - for (var x = 0; x < oWidth; ++x) - for (var c = 0; c < oChannels; ++c) - { - float maxVal = float.MinValue; - for (int dy = 0; dy < pool[1]; ++dy) - for (int dx = 0; dx < pool[0]; ++dx) - { - int oy = y * stride[1] + dy - pad[1]; - int ox = x * stride[0] + dx - pad[0]; - - if (oy < 0) continue; - if (oy >= xHeight) continue; - if (ox < 0) continue; - if (ox >= xWidth) continue; - - float v = xPtr[n * xnMult + oy * xyMult + ox * xxMult + c]; - maxVal = Mathf.Max(v, maxVal); - } - oPtr[n * onMult + y * oyMult + x * oxMult + c] = maxVal; - } - }); - } - - /// - public override Tensor AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - if (AreAnyTensorsHalf(X)) - return base.AvgPool2D(X, pool, stride, pad); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(pool.Length, 2); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var O = NewOutputTensor(X.dataType, X.shape.ApplyPool(pool, stride, pad)); - - int xnMult = X.height * X.width * X.channels; - int xyMult = X.width * X.channels; - int xxMult = X.channels; - - int onMult = O.height * O.width * O.channels; - int oyMult = O.width * O.channels; - int oxMult = O.channels; - - int oBatch = O.batch; - int oHeight = O.height; - int oWidth = O.width; - int oChannels = O.channels; - int xHeight = X.height; - int xWidth = X.width; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - AvgPool2DInnerLoop(pool, stride, pad, - xHeight, xWidth, xPtr, xnMult, xyMult, xxMult, - oBatch, oHeight, oWidth, oChannels, oPtr, onMult, oyMult, oxMult); - } - } - - return O; - } - - private static unsafe void AvgPool2DInnerLoop(int[] pool, int[] stride, int[] pad, - int xHeight, int xWidth, float* xPtr, int xnMult, int xyMult, int xxMult, - int oBatch, int oHeight, int oWidth, int oChannels, float* oPtr, int onMult, int oyMult, int oxMult) - { - Parallel.For(0, oBatch, n => - { - for (var y = 0; y < oHeight; ++y) - for (var x = 0; x < oWidth; ++x) - for (var c = 0; c < oChannels; ++c) - { - float accum = 0.0f; - float counter = 0.0f; - for (int dy = 0; dy < pool[1]; ++dy) - for (int dx = 0; dx < pool[0]; ++dx) - { - int oy = y * stride[1] + dy - pad[1]; - int ox = x * stride[0] + dx - pad[0]; - - if (oy < 0) continue; - if (oy >= xHeight) continue; - if (ox < 0) continue; - if (ox >= xWidth) continue; - - float v = xPtr[n * xnMult + oy * xyMult + ox * xxMult + c]; - accum += v; - ++counter; - } - oPtr[n * onMult + y * oyMult + x * oxMult + c] = accum / counter; - } - }); - } - - /// - public override Tensor GlobalMaxPool2D(Tensor X) - { - return MaxPool2D(X, new[] {X.width, X.height}, new[] {1, 1}, new[] {0, 0, 0, 0}); - } - - /// - public override Tensor GlobalAvgPool2D(Tensor X) - { - return AvgPool2D(X, new[] {X.width, X.height}, new[] {1, 1}, new[] {0, 0, 0, 0}); - } - - /// - public override Tensor Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - // Basic Im2Col+SGEMM implementation for reference: - // - // var unrolledX = Im2Col(X, K.shape, stride, pad); - // var flatK = K.Reshape(new TensorShape(unrolledX.flatWidth, K.kernelCount)); - // var flatO = Dense(unrolledX, flatK, B); - // return flatO.Reshape(X.shape.ApplyKernel(K.shape, stride, pad)); - - // Memory efficient implementation of Im2Col+SGEMM - // Requires temporary tensor of input shape (X) divided by stride - // = sizeof(X) / (stride[0] * stride[1]) - // - // Performance measurements: - // (MacBookPro2016) - // Standalone - // VGG@1 338ms Dense 23.2ms ( 7%), Conv2D 230ms (68%): Broadcast 5.9ms ( 3%), Im2Col 33.9ms (15%), GEMM 188.7ms (82%) mono:0.57GB - // CNN@256 180ms Dense 3.7ms ( 2%), Conv2D 118ms (66%): Broadcast 6.3ms ( 5%), Im2Col 30.7ms (26%), GEMM 81.2ms (69%) mono:0.15GB - // MOB@1 65ms Dpthw 12.6ms (19%), Conv2D 11ms (17%): Broadcast 1.3ms (12%), Im2Col 0.4ms ( 4%), GEMM 8.5ms (77%) mono:0.025-0.03GB - // Editor - // VGG@1 502ms Dense 24.6ms ( 5%), Conv2D 210ms (42%): Broadcast 4.9ms ( 2%), Im2Col 33.0ms (16%), GEMM 170.8ms (81%) - // CNN@256 266ms Dense 3.2ms ( 1%), Conv2D 119ms (45%): Broadcast 7.0ms ( 6%), Im2Col 33.0ms (27%), GEMM 78.4ms (65%) - // MOB@1 131ms Dpthw 43.6ms (33%), Conv2D 11ms ( 8%): Broadcast 1.2ms (10%), Im2Col 0.6ms ( 5%), GEMM 8.1ms (74%) - // CNN@16 17ms Dense 1.1ms ( 6%), Conv2D 6ms (35%): Broadcast .34ms ( 6%), Im2Col 2.23ms (37%), GEMM 3.4ms (57%) - // Standalone log measurements - // VGG << - { - var to = oPtr + n * oStrideBatch; - for (var y = 0; y < oHeight; ++y) - for (var x = 0; x < oWidth; ++x) - for (int dy = 0; dy < kernelHeight; ++dy) - for (int dx = 0; dx < kernelWidth; ++dx) - { - int readX = x * stride[0] + dx - pad[0]; - int readY = y * stride[1] + dy - pad[1]; - - if (readX < 0 || - readY < 0 || - readX >= xWidth || - readY >= xHeight) - { - // pad-0 - UnsafeUtility.MemClear(destination: to, - size: xChannels * sizeof(float)); - to += xChannels; - } - else - { - var from = xPtr + n * xStrideBatch + readY * xStrideHeight + readX * xStrideWidth; - UnsafeUtility.MemCpy(destination: to, - source: from, - size: xChannels * sizeof(float)); - to += xChannels; - } - } - }); - }*/ - - static internal int SafeIntDivCeil(int v, int div) - { - if (div == 0) - return v; - return (v + div - 1) / div; - } - - private Tensor Conv2DUsingIm2ColSlicedHelper(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - Assert.IsFalse(AreAnyTensorsHalf(X,K,B)); - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(X.channels, K.kernelDepth); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - var kernelWidth = K.kernelWidth; - var kernelHeight = K.kernelHeight; - var inChannels = K.kernelDepth; - var outChannels = K.kernelCount; - var batch = X.batch; - - bool pointwiseConvolution = kernelWidth == 1 && kernelHeight == 1 && // 1x1 kernel - stride[0] == 1 && stride[1] == 1 && // no strides - pad[0] == 0 && pad[1] == 0 && pad[2] == 0 && pad[3] == 0; // no padding - - var O = NewTensorForFusedActivation(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad), fusedActivation); - var T = pointwiseConvolution ? null: // pointwise convolution is just O=X*K, we can completely skip Im2Col() - NewTempTensor(X.dataType, new TensorShape(O.batch, O.height, O.width, inChannels)); // holds slice of Im2Col(X) - - var outElements = O.batch * O.height * O.width; - - var xStrideBatch = X.height * X.width * X.channels; - var xStrideHeight = X.width * X.channels; - var xStrideWidth = X.channels; - var xWidth = X.width; - var xHeight = X.height; - - Assert.AreEqual(O.batch, batch); - Assert.AreEqual(O.channels, B.flatWidth); - Assert.AreEqual(O.channels, outChannels); - - unsafe - { - // input & constants - var pinnedX = Pin(X); - var pinnedK = Pin(K); - var pinnedB = Pin(B); - - // temporary slice - var pinnedT = (pointwiseConvolution) ? pinnedX : Pin(T); - - // output - var pinnedO = Pin(O, uploadCache: false); - - float* xPtr = pinnedX.array.AddressAt(pinnedX.offset); - float* tPtr = pinnedT.array.AddressAt(pinnedT.offset); - float* kPtr = pinnedK.array.AddressAt(pinnedK.offset); - float* bPtr = pinnedB.array.AddressAt(pinnedB.offset); - float* oPtr = pinnedO.array.AddressAt(pinnedO.offset); - { - // O = broadcast(B) - Profiler.BeginSample("Conv2D_Sliced.BroadcastB"); - UnsafeUtility.MemCpyReplicate(destination: oPtr, - source: bPtr, - size: outChannels * sizeof(float), - count: outElements); - Profiler.EndSample(); - - // We can solve convolution by iteratively accumulating - // matrix multiplication of X' and K' for each positon in kernel where: - // X' is input X repeatedly shifted according to kernel position, - // K' is slice of weights K according to kernel position. - // - // Pseudocode: - // X :: Input - // T :: Temporary - // K :: Kernel - // O :: Output - // foreach ky in kernelHeight: - // foreach kx in kernelWidth: - // Temporary = shift(Input, horizontal_shift = kx, vertical_shift = ky) - // Temporary = pad(Temporary) - // Temporary = stride(Temporary) - // Output += Temporary * Kernel[dy, dx, :, :] - // - // Note for functions above that: - // 1) shift() can be implemented by copying data from n to T in a linear fashion. - // 2) stride() can be implemented by copying data every Nth pixel in a linear fashion. - // 3) pad() can be optimized for top and bottom of the tensor by writing 0s across the whole row. - - // O += conv(X, K) - float* wPtr = kPtr; - for (int dy = 0; dy < kernelHeight; ++dy) - for (int dx = 0; dx < kernelWidth; ++dx) - { - if (!pointwiseConvolution) - { - Profiler.BeginSample("Conv2D_Sliced.Im2ColSlice"); - - var tStrideBatch = T.height * T.width * T.channels; - var tStrideHeight = T.width * T.channels; - var tHeight = T.height; - var tWidth = T.width; - - var offsetX = dx - pad[0]; - var offsetY = dy - pad[1]; - - var strideX = stride[0]; - var strideY = stride[1]; - - var firstPixel = 0 * strideX + offsetX; - var lastPixel = (tWidth - 1) * strideX + offsetX; - int numberOfPixelsToPadLeft = SafeIntDivCeil(Math.Max(0, 0 - firstPixel ), strideX); // count(x * stride[0] + offsetX < 0) - int numberOfPixelsToPadRight = SafeIntDivCeil(Math.Max(0, lastPixel - (xWidth - 1)), strideX); // count(x * stride[0] + offsetX >= xWidth) - int numberOfPixelsToSkipFromInputRow = (offsetX >= 0 || strideX == 0) ? offsetX : // strideX == 0 protects against div-by-zero - lastPixel % strideX; // first(x * stride[0] + offsetX >= 0) == (xWidth * stride[0] + offsetX) % stride[0] - int numberOfPixelsToCopyFromInputRow = tWidth - numberOfPixelsToPadLeft - numberOfPixelsToPadRight; - - if (UnityEngine.Debug.isDebugBuild) // only to Assert correctness of the values above - { - // validate above calculations with alternative approach - int assertNumberOfPixelsToPadLeft = 0; - int assertNumberOfPixelsToPadRight = 0; - int assertNumberOfPixelsToSkipFromInputRow = 0; - for (var x = 0; x < tWidth; ++x) - { - var readX = x * strideX + offsetX; - if (readX < 0) - assertNumberOfPixelsToPadLeft++; - else - { - assertNumberOfPixelsToSkipFromInputRow = readX; - break; - } - } - for (var x = tWidth - 1; x >= 0; --x) - { - var readX = x * strideX + offsetX; - if (readX >= xWidth) - assertNumberOfPixelsToPadRight++; - else - break; - } - int assertNumberOfPixelsToCopyFromInputRow = tWidth - assertNumberOfPixelsToPadLeft - assertNumberOfPixelsToPadRight; - - Assert.AreEqual(numberOfPixelsToPadLeft, assertNumberOfPixelsToPadLeft); - Assert.AreEqual(numberOfPixelsToPadRight, assertNumberOfPixelsToPadRight); - Assert.AreEqual(numberOfPixelsToSkipFromInputRow, assertNumberOfPixelsToSkipFromInputRow); - Assert.AreEqual(numberOfPixelsToCopyFromInputRow, assertNumberOfPixelsToCopyFromInputRow); - } - - Assert.IsTrue(numberOfPixelsToPadLeft >= 0); - Assert.IsTrue(numberOfPixelsToPadRight >= 0); - Assert.IsTrue(numberOfPixelsToCopyFromInputRow >= 0); - Assert.IsTrue(numberOfPixelsToSkipFromInputRow >= 0); - Assert.IsTrue(numberOfPixelsToPadLeft + numberOfPixelsToPadRight <= tWidth); - Assert.IsTrue(numberOfPixelsToSkipFromInputRow <= xWidth); - Assert.IsTrue(numberOfPixelsToCopyFromInputRow <= xWidth); - Assert.AreEqual(numberOfPixelsToPadLeft + numberOfPixelsToCopyFromInputRow + numberOfPixelsToPadRight, tWidth); - - // extra clamp for safety since we are in the unsafe code block - numberOfPixelsToPadLeft = Math.Min(Math.Max(0, numberOfPixelsToPadLeft), tWidth); - numberOfPixelsToPadRight = Math.Min(Math.Max(0, numberOfPixelsToPadRight), tWidth - numberOfPixelsToPadLeft); - numberOfPixelsToSkipFromInputRow = Math.Min(Math.Max(0, numberOfPixelsToSkipFromInputRow), xWidth); - numberOfPixelsToCopyFromInputRow = Math.Min(Math.Max(0, numberOfPixelsToCopyFromInputRow), xWidth - numberOfPixelsToSkipFromInputRow); - - for (var n = 0; n < batch; ++n) - for (var y = 0; y < tHeight; ++y) - { - var readY = strideY * y + offsetY; - var from = xPtr + n * xStrideBatch + readY * xStrideHeight + numberOfPixelsToSkipFromInputRow * xStrideWidth; - var to = tPtr + n * tStrideBatch + y * tStrideHeight; - - if (readY < 0 || - readY >= xHeight) - { - // pad-0 top or bottom line, len = tWidth - UnsafeUtility.MemClear(destination: to, - size: inChannels * tWidth * sizeof(float)); - to += inChannels * tWidth; - } - else - { - // pad-0 left, len = numberOfPixelsToPadLeft - UnsafeUtility.MemClear(destination: to, - size: inChannels * numberOfPixelsToPadLeft * sizeof(float)); - to += inChannels * numberOfPixelsToPadLeft; - - // copy from X with stride, if necessary - if (strideX == 1) - { - UnsafeUtility.MemCpy(destination: to, - source: from, - size: inChannels * numberOfPixelsToCopyFromInputRow * sizeof(float)); - to += inChannels * numberOfPixelsToCopyFromInputRow; - } - else - { - UnsafeUtility.MemCpyStride(destination: to, destinationStride: inChannels * sizeof(float), - source: from, sourceStride: strideX * inChannels * sizeof(float), - elementSize: inChannels * sizeof(float), - count: numberOfPixelsToCopyFromInputRow); - to += inChannels * numberOfPixelsToCopyFromInputRow; - } - - // pad-0 right, len = numberOfPixelsToPadRight - UnsafeUtility.MemClear(destination: to, - size: inChannels * numberOfPixelsToPadRight * sizeof(float)); - to += inChannels * numberOfPixelsToPadRight; - } - } - Profiler.EndSample(); - } - - Profiler.BeginSample("Conv2D_Sliced.SGEMM"); - // O += slice(im2col(X)) * slice(K) - blas.SGEMM( - tPtr, outElements, inChannels, - wPtr, inChannels, outChannels, - oPtr, outElements, outChannels, 16); - - wPtr += inChannels * outChannels; - Profiler.EndSample(); - } - } - } - - T?.Dispose(); - - return ApplyFusedActivation(O, fusedActivation); - } - - /// - public override Tensor DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - if (K.kernelDepth != 1 || AreAnyTensorsHalf(X,K,B)) - return base.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - - Assert.IsTrue(X.shape.Is4D()); - Assert.AreEqual(K.kernelDepth, 1); - Assert.AreEqual(K.kernelCount, X.channels); - Assert.AreEqual(K.kernelCount, B.flatWidth); - Assert.AreEqual(B.flatWidth, B.length); - Assert.AreEqual(stride.Length, 2); - Assert.AreEqual(pad.Length, 4); - - // ONNX: (M x C/group x kH x kW) - // TF: [H, W, in_channels, channel_multiplier] - - // TF pseudocode: - // output[b, i, j, k * channel_multiplier + q] = - // sum_{di, dj} - // input [b, i + di, j + dj, k] * - // filter[di, dj, k, q] * - - var O = NewTensorForFusedActivation(X.dataType, X.shape.ApplyKernel(K.shape, stride, pad), fusedActivation); - - int xnMult = X.height * X.width * X.channels; - int xyMult = X.width * X.channels; - int xxMult = X.channels; - - int kyMult = K.height * K.width * K.channels; - int kxMult = K.width * K.channels; - - int onMult = O.height * O.width * O.channels; - int oyMult = O.width * O.channels; - int oxMult = O.channels; - - int oBatch = O.batch; - int oHeight = O.height; - int oWidth = O.width; - int kKernelCount = K.kernelCount; - int kKernelHeight = K.kernelHeight; - int kKernelWidth = K.kernelWidth; - int xHeight = X.height; - int xWidth = X.width; - int xChannels = X.channels; - - unsafe - { - - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* kPtr = Pin(K).array.AddressAt(Pin(K).offset); - float* bPtr = Pin(B).array.AddressAt(Pin(B).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - { - DepthwiseConv2DInnerLoop(stride, pad, oBatch, oHeight, oWidth, kKernelCount, bPtr, kKernelHeight, kKernelWidth, - xHeight, xWidth, xChannels, xPtr, xnMult, xyMult, xxMult, kPtr, kyMult, kxMult, - oPtr, onMult, oyMult, oxMult); - } - } - - return ApplyFusedActivation(O, fusedActivation); - } - - // private static unsafe void DepthwiseConv2DInnerLoop(int[] stride, int[] pad, int oBatch, int oHeight, int oWidth, int kKernelCount, - // float* bPtr, int kKernelHeight, int kKernelWidth, int xHeight, int xWidth, int xChannels, float* xPtr, - // int xnMult, int xyMult, int xxMult, float* kPtr, int kyMult, int kxMult, float* oPtr, int onMult, - // int oyMult, int oxMult) - // { - // Parallel.For(0, oBatch, n => - // { - // for (var y = 0; y < oHeight; ++y) - // for (var x = 0; x < oWidth; ++x) - // for (var k = 0; k < kKernelCount; ++k) - // { - // float v = bPtr[k]; - // for (int dy = 0; dy < kKernelHeight; ++dy) - // { - // for (int dx = 0; dx < kKernelWidth; ++dx) - // { - // int oy = y * stride[1] + dy - pad[1]; - // int ox = x * stride[0] + dx - pad[0]; - - // if (oy < 0) continue; - // if (oy >= xHeight) continue; - // if (ox < 0) continue; - // if (ox >= xWidth) continue; - - // float xv = xPtr[n * xnMult + oy * xyMult + ox * xxMult + k]; - // float kv = kPtr[dy * kyMult + dx * kxMult + k]; - - // v += xv * kv; - // } - // } - - // oPtr[n * onMult + y * oyMult + x * oxMult + k] = v; - // } - // }); - // } - - // private static unsafe void DepthwiseConv2DInnerLoop(int[] stride, int[] pad, int oBatch, int oHeight, int oWidth, int kKernelCount, - // float* bPtr, int kKernelHeight, int kKernelWidth, int xHeight, int xWidth, int xChannels, float* xPtr, - // int xnMult, int xyMult, int xxMult, float* kPtr, int kyMult, int kxMult, float* oPtr, int onMult, - // int oyMult, int oxMult) - // { - // Parallel.For(0, oBatch, n => - // { - // for (var y = 0; y < oHeight; ++y) - // for (var x = 0; x < oWidth; ++x) - // for (var k = 0; k < kKernelCount; ++k) - // { - // float v = bPtr[k]; - // for (int dy = 0; dy < kKernelHeight; ++dy) - // { - // int oy = y * stride[1] + dy - pad[1]; - // if (oy < 0) continue; - // if (oy >= xHeight) continue; - - // for (int dx = 0; dx < kKernelWidth; ++dx) - // { - // int ox = x * stride[0] + dx - pad[0]; - // if (ox < 0) continue; - // if (ox >= xWidth) continue; - - // float xv = xPtr[n * xnMult + oy * xyMult + ox * xxMult + k]; - // float kv = kPtr[dy * kyMult + dx * kxMult + k]; - - // v += xv * kv; - // } - // } - - // oPtr[n * onMult + y * oyMult + x * oxMult + k] = v; - // } - // }); - // } - - // private static unsafe void DepthwiseConv2DInnerLoop(int[] stride, int[] pad, int oBatch, int oHeight, int oWidth, int kKernelCount, - // float* bPtr, int kKernelHeight, int kKernelWidth, int xHeight, int xWidth, int xChannels, float* xPtr, - // int xnMult, int xyMult, int xxMult, float* kPtr, int kyMult, int kxMult, float* oPtr, int onMult, - // int oyMult, int oxMult) - // { - // Parallel.For(0, oBatch, n => - // { - // var ks = new float[kKernelCount]; - - // for (var y = 0; y < oHeight; ++y) - // for (var x = 0; x < oWidth; ++x) - // { - // for (int dy = 0; dy < kKernelHeight; ++dy) - // { - // int oy = y * stride[1] + dy - pad[1]; - // if (oy < 0) continue; - // if (oy >= xHeight) continue; - - // for (int dx = 0; dx < kKernelWidth; ++dx) - // { - // int ox = x * stride[0] + dx - pad[0]; - // if (ox < 0) continue; - // if (ox >= xWidth) continue; - - // for (var k = 0; k < kKernelCount; ++k) - // { - // float xv = xPtr[n * xnMult + oy * xyMult + ox * xxMult + k]; - // float kv = kPtr[dy * kyMult + dx * kxMult + k]; - - // ks[k] += xv * kv; - // } - // } - // } - - // for (var k = 0; k < kKernelCount; ++k) - // { - // oPtr[n * onMult + y * oyMult + x * oxMult + k] = ks[k] + bPtr[k]; - // ks[k] = 0; - // } - - // } - // }); - // } - - // private static unsafe void DepthwiseConv2DInnerLoop(int[] stride, int[] pad, int oBatch, int oHeight, int oWidth, int kKernelCount, - // float* bPtr, int kKernelHeight, int kKernelWidth, int xHeight, int xWidth, int xChannels, float* xPtr, - // int xnMult, int xyMult, int xxMult, float* kPtr, int kyMult, int kxMult, float* oPtr, int onMult, - // int oyMult, int oxMult) - // { - // Parallel.For(0, oHeight, y => - // { - // var ks = new float[kKernelCount]; - // for (var n = 0; n < oBatch; ++n) - // for (var x = 0; x < oWidth; ++x) - // { - // for (int dy = 0; dy < kKernelHeight; ++dy) - // { - // int oy = y * stride[1] + dy - pad[1]; - // if (oy < 0) continue; - // if (oy >= xHeight) continue; - - // for (int dx = 0; dx < kKernelWidth; ++dx) - // { - // int ox = x * stride[0] + dx - pad[0]; - // if (ox < 0) continue; - // if (ox >= xWidth) continue; - - // for (var k = 0; k < kKernelCount; ++k) - // { - // float xv = xPtr[n * xnMult + oy * xyMult + ox * xxMult + k]; - // float kv = kPtr[dy * kyMult + dx * kxMult + k]; - - // ks[k] += xv * kv; - // } - // } - // } - - // for (var k = 0; k < kKernelCount; ++k) - // { - // oPtr[n * onMult + y * oyMult + x * oxMult + k] = ks[k] + bPtr[k]; - // ks[k] = 0; - // } - - // } - // }); - // } - - // private static unsafe void DepthwiseConv2DInnerLoop(int[] stride, int[] pad, int oBatch, int oHeight, int oWidth, int kKernelCount, - // float* bPtr, int kKernelHeight, int kKernelWidth, int xHeight, int xWidth, int xChannels, float* xPtr, - // int xnMult, int xyMult, int xxMult, float* kPtr, int kyMult, int kxMult, float* oPtr, int onMult, - // int oyMult, int oxMult) - // { - // Parallel.For(0, oHeight, y => - // { - // var ks = new float[kKernelCount]; - // for (var n = 0; n < oBatch; ++n) - // for (var x = 0; x < oWidth; ++x) - // { - // for (int dy = 0; dy < kKernelHeight; ++dy) - // { - - // int oy = y * stride[1] + dy - pad[1]; - // if (oy < 0) continue; - // if (oy >= xHeight) continue; - - // for (int dx = 0; dx < kKernelWidth; ++dx) - // { - // int ox = x * stride[0] + dx - pad[0]; - // if (ox < 0) continue; - // if (ox >= xWidth) continue; - - // var k = 0; - // for (; k < kKernelCount; k += 8) - // { - // var xIndex = n * xnMult + oy * xyMult + ox * xxMult + k; - // var kIndex = dy * kyMult + dx * kxMult + k; - - // float x0 = xPtr[xIndex + 0]; - // float k0 = kPtr[kIndex + 0]; - // float x1 = xPtr[xIndex + 1]; - // float k1 = kPtr[kIndex + 1]; - // float x2 = xPtr[xIndex + 2]; - // float k2 = kPtr[kIndex + 2]; - // float x3 = xPtr[xIndex + 3]; - // float k3 = kPtr[kIndex + 3]; - // float x4 = xPtr[xIndex + 4]; - // float k4 = kPtr[kIndex + 4]; - // float x5 = xPtr[xIndex + 5]; - // float k5 = kPtr[kIndex + 5]; - // float x6 = xPtr[xIndex + 6]; - // float k6 = kPtr[kIndex + 6]; - // float x7 = xPtr[xIndex + 7]; - // float k7 = kPtr[kIndex + 7]; - - // ks[k + 0] += x0 * k0; - // ks[k + 1] += x1 * k1; - // ks[k + 2] += x2 * k2; - // ks[k + 3] += x3 * k3; - // ks[k + 4] += x4 * k4; - // ks[k + 5] += x5 * k5; - // ks[k + 6] += x6 * k6; - // ks[k + 7] += x7 * k7; - // } - - // for (; k < kKernelCount; k++) - // { - // var xIndex = n * xnMult + oy * xyMult + ox * xxMult + k; - // var kIndex = dy * kyMult + dx * kxMult + k; - - // float x0 = xPtr[xIndex]; - // float k0 = kPtr[kIndex]; - // ks[k] += x0 * k0; - // } - // } - // } - - // var q = 0; - // for (; q < kKernelCount; q += 8) - // { - // var oIndex = n * onMult + y * oyMult + x * oxMult + q; - // oPtr[oIndex + 0] = ks[q + 0] + bPtr[q + 0]; ks[q + 0] = 0; - // oPtr[oIndex + 1] = ks[q + 1] + bPtr[q + 1]; ks[q + 1] = 0; - // oPtr[oIndex + 2] = ks[q + 2] + bPtr[q + 2]; ks[q + 2] = 0; - // oPtr[oIndex + 3] = ks[q + 3] + bPtr[q + 3]; ks[q + 3] = 0; - // oPtr[oIndex + 4] = ks[q + 4] + bPtr[q + 4]; ks[q + 4] = 0; - // oPtr[oIndex + 5] = ks[q + 5] + bPtr[q + 5]; ks[q + 5] = 0; - // oPtr[oIndex + 6] = ks[q + 6] + bPtr[q + 6]; ks[q + 6] = 0; - // oPtr[oIndex + 7] = ks[q + 7] + bPtr[q + 7]; ks[q + 7] = 0; - // } - // for (; q < kKernelCount; q++) - // { - // var oIndex = n * onMult + y * oyMult + x * oxMult + q; - // oPtr[oIndex] = ks[q] + bPtr[q]; - // ks[q] = 0; - // } - // } - // }); - // } - - - // private static unsafe void DepthwiseConv2DInnerLoop(int[] stride, int[] pad, int oBatch, int oHeight, int oWidth, int kKernelCount, - // float* bPtr, int kKernelHeight, int kKernelWidth, int xHeight, int xWidth, int xChannels, float* xPtr, - // int xnMult, int xyMult, int xxMult, float* kPtr, int kyMult, int kxMult, float* oPtr, int onMult, - // int oyMult, int oxMult) - // { - // var unrollSize = 8; - // Parallel.For(0, oHeight, y => - // { - // float* ks = (float*)UnsafeUtility.Malloc(kKernelCount * sizeof(float), 16 * sizeof(float), Allocator.TempJob); - // for (var n = 0; n < oBatch; ++n) - // for (var x = 0; x < oWidth; ++x) - // { - // for (int dy = 0; dy < kKernelHeight; ++dy) - // { - // int oy = y * stride[1] + dy - pad[1]; - // if (oy < 0) continue; - // if (oy >= xHeight) continue; - - // for (int dx = 0; dx < kKernelWidth; ++dx) - // { - // int ox = x * stride[0] + dx - pad[0]; - // if (ox < 0) continue; - // if (ox >= xWidth) continue; - - // var k = 0; - // for (; k < kKernelCount - (unrollSize - 1); k += unrollSize) - // { - // var xIndex = n * xnMult + oy * xyMult + ox * xxMult + k; - // var kIndex = dy * kyMult + dx * kxMult + k; - - // float x0 = xPtr[xIndex + 0], k0 = kPtr[kIndex + 0]; - // float x1 = xPtr[xIndex + 1], k1 = kPtr[kIndex + 1]; - // float x2 = xPtr[xIndex + 2], k2 = kPtr[kIndex + 2]; - // float x3 = xPtr[xIndex + 3], k3 = kPtr[kIndex + 3]; - // float x4 = xPtr[xIndex + 4], k4 = kPtr[kIndex + 4]; - // float x5 = xPtr[xIndex + 5], k5 = kPtr[kIndex + 5]; - // float x6 = xPtr[xIndex + 6], k6 = kPtr[kIndex + 6]; - // float x7 = xPtr[xIndex + 7], k7 = kPtr[kIndex + 7]; - - // ks[k + 0] += x0 * k0; - // ks[k + 1] += x1 * k1; - // ks[k + 2] += x2 * k2; - // ks[k + 3] += x3 * k3; - // ks[k + 4] += x4 * k4; - // ks[k + 5] += x5 * k5; - // ks[k + 6] += x6 * k6; - // ks[k + 7] += x7 * k7; - // } - - // for (; k < kKernelCount; k++) - // { - // var xIndex = n * xnMult + oy * xyMult + ox * xxMult + k; - // var kIndex = dy * kyMult + dx * kxMult + k; - - // float x0 = xPtr[xIndex]; - // float k0 = kPtr[kIndex]; - // ks[k] += x0 * k0; - // } - // } - // } - - // var q = 0; - // for (; q < kKernelCount - (unrollSize - 1); q += unrollSize) - // { - // var oIndex = n * onMult + y * oyMult + x * oxMult + q; - // oPtr[oIndex + 0] = ks[q + 0] + bPtr[q + 0]; ks[q + 0] = 0; - // oPtr[oIndex + 1] = ks[q + 1] + bPtr[q + 1]; ks[q + 1] = 0; - // oPtr[oIndex + 2] = ks[q + 2] + bPtr[q + 2]; ks[q + 2] = 0; - // oPtr[oIndex + 3] = ks[q + 3] + bPtr[q + 3]; ks[q + 3] = 0; - // oPtr[oIndex + 4] = ks[q + 4] + bPtr[q + 4]; ks[q + 4] = 0; - // oPtr[oIndex + 5] = ks[q + 5] + bPtr[q + 5]; ks[q + 5] = 0; - // oPtr[oIndex + 6] = ks[q + 6] + bPtr[q + 6]; ks[q + 6] = 0; - // oPtr[oIndex + 7] = ks[q + 7] + bPtr[q + 7]; ks[q + 7] = 0; - // } - // for (; q < kKernelCount; q++) - // { - // var oIndex = n * onMult + y * oyMult + x * oxMult + q; - // oPtr[oIndex] = ks[q] + bPtr[q]; - // ks[q] = 0; - // } - // } - // UnsafeUtility.Free(ks, Allocator.TempJob); - // }); - // } - - - - private static unsafe void DepthwiseConv2DInnerLoop(int[] stride, int[] pad, int oBatch, int oHeight, int oWidth, int kKernelCount, - float* bPtr, int kKernelHeight, int kKernelWidth, int xHeight, int xWidth, int xChannels, float* xPtr, - int xnMult, int xyMult, int xxMult, float* kPtr, int kyMult, int kxMult, float* oPtr, int onMult, - int oyMult, int oxMult) - { - var unrollSize = 8; - var accumulatorMemSize = kKernelCount * sizeof(float); - var accumulatorAlignmment = 16 * sizeof(float); - - Parallel.For(0, oHeight, y => - { - float* outputAccumulators = (float*)UnsafeUtility.Malloc(accumulatorMemSize, accumulatorAlignmment, Allocator.TempJob); - for (var n = 0; n < oBatch; ++n) - for (var x = 0; x < oWidth; ++x) - { - // reset accumulators to 0 - UnsafeUtility.MemClear(outputAccumulators, accumulatorMemSize); - - for (int dy = 0; dy < kKernelHeight; ++dy) - { - int oy = y * stride[1] + dy - pad[1]; - if (oy < 0) continue; - if (oy >= xHeight) continue; - - for (int dx = 0; dx < kKernelWidth; ++dx) - { - int ox = x * stride[0] + dx - pad[0]; - if (ox < 0) continue; - if (ox >= xWidth) continue; - - var k = 0; - var xIndex = n * xnMult + oy * xyMult + ox * xxMult; - var kIndex = dy * kyMult + dx * kxMult; - for (; k < kKernelCount - (unrollSize - 1); k += unrollSize) - { - - float x0 = xPtr[xIndex + 0], k0 = kPtr[kIndex + 0]; - float x1 = xPtr[xIndex + 1], k1 = kPtr[kIndex + 1]; - float x2 = xPtr[xIndex + 2], k2 = kPtr[kIndex + 2]; - float x3 = xPtr[xIndex + 3], k3 = kPtr[kIndex + 3]; - float x4 = xPtr[xIndex + 4], k4 = kPtr[kIndex + 4]; - float x5 = xPtr[xIndex + 5], k5 = kPtr[kIndex + 5]; - float x6 = xPtr[xIndex + 6], k6 = kPtr[kIndex + 6]; - float x7 = xPtr[xIndex + 7], k7 = kPtr[kIndex + 7]; - xIndex += unrollSize; - kIndex += unrollSize; - - outputAccumulators[k + 0] += x0 * k0; - outputAccumulators[k + 1] += x1 * k1; - outputAccumulators[k + 2] += x2 * k2; - outputAccumulators[k + 3] += x3 * k3; - outputAccumulators[k + 4] += x4 * k4; - outputAccumulators[k + 5] += x5 * k5; - outputAccumulators[k + 6] += x6 * k6; - outputAccumulators[k + 7] += x7 * k7; - } - - for (; k < kKernelCount; k++) - { - float x0 = xPtr[xIndex++], k0 = kPtr[kIndex++]; - outputAccumulators[k] += x0 * k0; - } - } - } - - // write accumulators to memory - var q = 0; - var oIndex = n * onMult + y * oyMult + x * oxMult; - for (; q < kKernelCount - (unrollSize - 1); q += unrollSize) - { - oPtr[oIndex + 0] = outputAccumulators[q + 0] + bPtr[q + 0]; - oPtr[oIndex + 1] = outputAccumulators[q + 1] + bPtr[q + 1]; - oPtr[oIndex + 2] = outputAccumulators[q + 2] + bPtr[q + 2]; - oPtr[oIndex + 3] = outputAccumulators[q + 3] + bPtr[q + 3]; - oPtr[oIndex + 4] = outputAccumulators[q + 4] + bPtr[q + 4]; - oPtr[oIndex + 5] = outputAccumulators[q + 5] + bPtr[q + 5]; - oPtr[oIndex + 6] = outputAccumulators[q + 6] + bPtr[q + 6]; - oPtr[oIndex + 7] = outputAccumulators[q + 7] + bPtr[q + 7]; - oIndex += unrollSize; - } - for (; q < kKernelCount; q++) - { - oPtr[oIndex++ ] = outputAccumulators[q ] + bPtr[q ]; - } - } - - UnsafeUtility.Free(outputAccumulators, Allocator.TempJob); - }); - } - - /// - protected override Tensor CopyAndReshape(Tensor X, TensorShape shape) - { - Assert.AreEqual(X.length, shape.length); - var O = NewOutputTensor(X.dataType, shape); - var pinO = Pin(O, uploadCache: false); - BarracudaArray.Copy(Pin(X).array, Pin(X).offset, pinO.array, pinO.offset, X.length); - return O; - } - - private bool AreAnyTensorsHalf(Tensor[] tensors) - { - for (int i = 0; i != tensors.Length; ++i) - { - if (tensors[i].dataType == DataType.Half) - return true; - } - return false; - } - - private bool AreAnyTensorsHalf(Tensor tensor0, Tensor tensor1 = null, Tensor tensor2 = null, Tensor tensor3 = null) - { - if (tensor0.dataType == DataType.Half) - return true; - if (tensor1 != null && tensor1.dataType == DataType.Half) - return true; - if (tensor2 != null && tensor2.dataType == DataType.Half) - return true; - if (tensor3 != null && tensor3.dataType == DataType.Half) - return true; - - return false; - } - - /// - public override Tensor ScaleBias(Tensor X, Tensor S, Tensor B) - { - if (!X.shape.Is4D() || AreAnyTensorsHalf(X,S,B)) - return base.ScaleBias(X, S, B); - - Assert.AreEqual(X.channels, B.channels); Assert.AreEqual(X.channels, S.channels); - Assert.AreEqual(B.length, B.channels); Assert.AreEqual(S.length, S.channels); - - // f(x) = x for x >= 0, f(x) = slope*x for x <= 0 - var O = NewTensorLike(X, AllocScope.LayerOutput); - var end = X.length; - const int unrollSize = 4; - - unsafe - { - float* xPtr = Pin(X).array.AddressAt(Pin(X).offset); - float* oPtr = Pin(O, uploadCache: false).array.AddressAt(Pin(O, uploadCache: false).offset); - float* sPtr = Pin(S).array.AddressAt(Pin(S).offset); - float* bPtr = Pin(B).array.AddressAt(Pin(B).offset); - { - ScaleBiasInnerLoop(end, unrollSize, xPtr, X.length, oPtr, sPtr, S.length, bPtr, B.length); - - // Remainder - for (int i = (end / unrollSize) * unrollSize; i < end; ++i) - { - float v = xPtr[i]; - float scale = sPtr[i % S.length]; - float bias = bPtr[i % B.length]; - v = v * scale + bias; - oPtr[i] = v; - } - } - } - - return O; - } - - private unsafe void ScaleBiasInnerLoop(int length, int unrollSize, float* xPtr, int xLen, float* oPtr, float* sPtr, int sLen, float* bPtr, int bLen) - { - Assert.AreEqual(unrollSize, 4); - - m_InnerLoop.SetState(unrollSize, oPtr, xPtr, xLen, sPtr, sLen, bPtr, bLen); - - Parallel_For(0L, length / unrollSize, m_InnerLoop.m_scaleBiasInnerLoopDelegate); - } - - /// - public override Tensor Prepare(Tensor X) - { - Pin(X); - return X; - } - - /// - public override Tensor PrepareNoAlloc(Tensor X) - { - Pin(X, uploadCache: false); - return X; - } -} - - internal unsafe class InnerLoop - { - private int unrollSize; - private float* oPtr; - private float* xPtr; - private int xLen; - private float* sPtr; - private int sLen; - private float* bPtr; - private int bLen; - private float alpha; - private float beta; - private int prePadX; - private int prePadY; - - private TensorShape oShape; - private TensorShape xShape; - private TensorShape sShape; - private TensorShape bShape; - - public Action m_tanhInnerLoopDelegate; - public Action m_expInnerLoopDelegate; - public Action m_sqrtInnerLoopDelegate; - public Action m_swishInnerLoopDelegate; - public Action m_softplusInnerLoopDelegate; - public Action m_sigmoidInnerLoopDelegate; - public Action m_hardsigmoidInnerLoopDelegate; - public Action m_negInnerLoopDelegate; - public Action m_eluInnerLoopDelegate; - public Action m_reluInnerLoopDelegate; - public Action m_relu6InnerLoopDelegate; - public Action m_leakyReluInnerLoopDelegate; - public Action m_preluInnerLoopDelegate; - public Action m_acosInnerLoopDelegate; - public Action m_acoshInnerLoopDelegate; - public Action m_asinInnerLoopDelegate; - public Action m_asinhInnerLoopDelegate; - public Action m_atanInnerLoopDelegate; - public Action m_atanhInnerLoopDelegate; - public Action m_cosInnerLoopDelegate; - public Action m_coshInnerLoopDelegate; - public Action m_sinInnerLoopDelegate; - public Action m_sinhInnerLoopDelegate; - public Action m_tanInnerLoopDelegate; - public Action m_erfInnerLoopDelegate; - public Action m_maxInnerLoopDelegate; - public Action m_minInnerLoopDelegate; - public Action m_divInnerLoopDelegate; - public Action m_mulInnerLoopDelegate; - public Action m_subInnerLoopDelegate; - public Action m_addInnerLoopDelegate; - public Action m_greaterInnerLoopDelegate; - public Action m_greaterEqualInnerLoopDelegate; - public Action m_lessInnerLoopDelegate; - public Action m_lessEqualInnerLoopDelegate; - public Action m_equalInnerLoopDelegate; - public Action m_logicalAndInnerLoopDelegate; - public Action m_logicalOrInnerLoopDelegate; - public Action m_logicalXorInnerLoopDelegate; - public Action m_logicalNotInnerLoopDelegate; - public Action m_signInnerLoopDelegate; - public Action m_whereInnerLoopDelegate; - public Action m_maxInnerLoopDelegateNoBroadcast; - public Action m_minInnerLoopDelegateNoBroadcast; - public Action m_divInnerLoopDelegateNoBroadcast; - public Action m_mulInnerLoopDelegateNoBroadcast; - public Action m_subInnerLoopDelegateNoBroadcast; - public Action m_addInnerLoopDelegateNoBroadcast; - public Action m_greaterInnerLoopDelegateNoBroadcast; - public Action m_greaterEqualInnerLoopDelegateNoBroadcast; - public Action m_lessInnerLoopDelegateNoBroadcast; - public Action m_lessEqualInnerLoopDelegateNoBroadcast; - public Action m_equalInnerLoopDelegateNoBroadcast; - public Action m_logicalAndInnerLoopDelegateNoBroadcast; - public Action m_logicalOrInnerLoopDelegateNoBroadcast; - public Action m_logicalXorInnerLoopDelegateNoBroadcast; - public Action m_whereInnerLoopDelegateNoBroadcast; - public Action m_scaleBiasInnerLoopDelegate; - - public Func m_maxOpDelegate; - public Func m_minOpDelegate; - public Func m_divOpDelegate; - public Func m_mulOpDelegate; - public Func m_subOpDelegate; - public Func m_addOpDelegate; - public Func m_greaterOpDelegate; - public Func m_greaterEqualOpDelegate; - public Func m_lessOpDelegate; - public Func m_lessEqualOpDelegate; - public Func m_equalOpDelegate; - public Func m_logicalAndOpDelegate; - public Func m_logicalOrOpDelegate; - public Func m_logicalXorOpDelegate; - public Func m_logicalNotOpDelegate; - public Func m_signOpDelegate; - - public InnerLoop() - { - //Store delegates to avoid GC allocation because of repeated cast from functions to delegate at runtime - m_tanhInnerLoopDelegate = TanhInnerLoop; - m_expInnerLoopDelegate = ExpInnerLoop; - m_sqrtInnerLoopDelegate = SqrtInnerLoop; - m_swishInnerLoopDelegate = SwishInnerLoop; - m_softplusInnerLoopDelegate = SoftplusInnerLoop; - m_sigmoidInnerLoopDelegate = SigmoidInnerLoop; - m_hardsigmoidInnerLoopDelegate = HardSigmoidInnerLoop; - m_negInnerLoopDelegate = NegInnerLoop; - m_eluInnerLoopDelegate = EluInnerLoop; - m_reluInnerLoopDelegate = ReluInnerLoop; - m_relu6InnerLoopDelegate = Relu6InnerLoop; - m_leakyReluInnerLoopDelegate = LeakyReluInnerLoop; - m_preluInnerLoopDelegate = PReluInnerLoop; - m_acosInnerLoopDelegate = AcosInnerLoop; - m_acoshInnerLoopDelegate = AcoshInnerLoop; - m_asinInnerLoopDelegate = AsinInnerLoop; - m_asinhInnerLoopDelegate = AsinhInnerLoop; - m_atanInnerLoopDelegate = AtanInnerLoop; - m_atanhInnerLoopDelegate = AtanhInnerLoop; - m_cosInnerLoopDelegate = CosInnerLoop; - m_coshInnerLoopDelegate = CoshInnerLoop; - m_sinInnerLoopDelegate = SinInnerLoop; - m_sinhInnerLoopDelegate = SinhInnerLoop; - m_tanInnerLoopDelegate = TanInnerLoop; - m_erfInnerLoopDelegate = ErfInnerLoop; - m_maxInnerLoopDelegate = MaxInnerLoop; - m_minInnerLoopDelegate = MinInnerLoop; - m_divInnerLoopDelegate = DivInnerLoop; - m_mulInnerLoopDelegate = MulInnerLoop; - m_subInnerLoopDelegate = SubInnerLoop; - m_addInnerLoopDelegate = AddInnerLoop; - m_greaterInnerLoopDelegate = GreaterInnerLoop; - m_greaterEqualInnerLoopDelegate = GreaterEqualInnerLoop; - m_lessInnerLoopDelegate = LessInnerLoop; - m_lessEqualInnerLoopDelegate = LessEqualInnerLoop; - m_equalInnerLoopDelegate = EqualInnerLoop; - m_logicalAndInnerLoopDelegate = LogicalAndInnerLoop; - m_logicalOrInnerLoopDelegate = LogicalOrInnerLoop; - m_logicalXorInnerLoopDelegate = LogicalXorInnerLoop; - m_logicalNotInnerLoopDelegate = LogicalNotInnerLoop; - m_signInnerLoopDelegate = SignInnerLoop; - m_whereInnerLoopDelegate = WhereInnerLoop; - m_maxInnerLoopDelegateNoBroadcast = MaxInnerLoopNoBroadcast; - m_minInnerLoopDelegateNoBroadcast = MinInnerLoopNoBroadcast; - m_divInnerLoopDelegateNoBroadcast = DivInnerLoopNoBroadcast; - m_mulInnerLoopDelegateNoBroadcast = MulInnerLoopNoBroadcast; - m_subInnerLoopDelegateNoBroadcast = SubInnerLoopNoBroadcast; - m_addInnerLoopDelegateNoBroadcast = AddInnerLoopNoBroadcast; - m_greaterInnerLoopDelegateNoBroadcast = GreaterInnerLoopNoBroadcast; - m_greaterEqualInnerLoopDelegateNoBroadcast = GreaterEqualInnerLoopNoBroadcast; - m_lessInnerLoopDelegateNoBroadcast = LessInnerLoopNoBroadcast; - m_lessEqualInnerLoopDelegateNoBroadcast = LessEqualInnerLoopNoBroadcast; - m_equalInnerLoopDelegateNoBroadcast = EqualInnerLoopNoBroadcast; - m_logicalAndInnerLoopDelegateNoBroadcast = LogicalAndInnerLoopNoBroadcast; - m_logicalOrInnerLoopDelegateNoBroadcast = LogicalOrInnerLoopNoBroadcast; - m_logicalXorInnerLoopDelegateNoBroadcast = LogicalXorInnerLoopNoBroadcast; - m_whereInnerLoopDelegateNoBroadcast = WhereInnerLoopNoBroadcast; - m_scaleBiasInnerLoopDelegate = ScaleBiasInnerLoop; - m_maxOpDelegate = Max; - m_minOpDelegate = Min; - m_divOpDelegate = Div; - m_mulOpDelegate = Mul; - m_subOpDelegate = Sub; - m_addOpDelegate = Add; - m_greaterOpDelegate = Greater; - m_greaterEqualOpDelegate = GreaterEqual; - m_lessOpDelegate = Less; - m_lessEqualOpDelegate = LessEqual; - m_equalOpDelegate = Equal; - m_logicalAndOpDelegate = LogicalAnd; - m_logicalOrOpDelegate = LogicalOr; - m_logicalXorOpDelegate = LogicalXor; - m_logicalNotOpDelegate = LogicalNot; - m_signOpDelegate = Sign; - } - - public void SetState(int unrollSize, float* oPtr, float* xPtr, float* sPtr, float* bPtr, TensorShape oShape, TensorShape xShape, TensorShape sShape, TensorShape bShape) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.oShape = oShape; - this.xPtr = xPtr; - this.xShape = xShape; - this.xLen = xShape.length; - this.sPtr = sPtr; - this.sShape = sShape; - this.sLen = sShape.length; - this.bPtr = bPtr; - this.bShape = bShape; - this.bLen = bShape.length; - } - - public void SetState(int unrollSize, float* oPtr, float* xPtr, float* bPtr, TensorShape oShape, TensorShape xShape, TensorShape bShape) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.oShape = oShape; - this.xPtr = xPtr; - this.xShape = xShape; - this.xLen = xShape.length; - this.bPtr = bPtr; - this.bShape = bShape; - this.bLen = bShape.length; - } - - public void SetState(int unrollSize, float* oPtr, float* xPtr, int xLen, float* sPtr, int sLen, float* bPtr, int bLen) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.xPtr = xPtr; - this.xLen = xLen; - this.sPtr = sPtr; - this.sLen = sLen; - this.bPtr = bPtr; - this.bLen = bLen; - } - - public void SetState(int unrollSize, float* oPtr, float* xPtr, int xLen, float* bPtr, int bLen) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.xPtr = xPtr; - this.xLen = xLen; - this.bPtr = bPtr; - this.bLen = bLen; - } - - public void SetState(int unrollSize, float* xPtr, float* oPtr) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.xPtr = xPtr; - } - - public void SetState(int unrollSize, float* xPtr, float* oPtr, float* sPtr, float* bPtr) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.xPtr = xPtr; - this.sPtr = sPtr; - this.bPtr = bPtr; - } - - public void SetState(int unrollSize, float* xPtr, float* oPtr, float* bPtr) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.xPtr = xPtr; - this.bPtr = bPtr; - } - - public void SetState(int unrollSize, float* xPtr, float* oPtr, float alpha) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.xPtr = xPtr; - this.alpha = alpha; - } - - public void SetState(int unrollSize, float* xPtr, float* oPtr, float alpha, float beta) - { - this.unrollSize = unrollSize; - this.oPtr = oPtr; - this.xPtr = xPtr; - this.alpha = alpha; - this.beta = beta; - } - - public void SetState(float* oPtr, float* xPtr, TensorShape oShape, TensorShape xShape, float constant, int prePadX, int prePadY) - { - this.oPtr = oPtr; - this.xPtr = xPtr; - this.oShape = oShape; - this.xShape = xShape; - this.alpha = constant; - this.prePadX = prePadX; - this.prePadY = prePadY; - } - - private void NegInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = -v0; - v1 = -v1; - v2 = -v2; - v3 = -v3; - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void ReluInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - float v4 = baseXPtr[4 ]; - float v5 = baseXPtr[5 ]; - float v6 = baseXPtr[6 ]; - float v7 = baseXPtr[7 ]; - float v8 = baseXPtr[8 ]; - float v9 = baseXPtr[9 ]; - float v10 = baseXPtr[10]; - float v11 = baseXPtr[11]; - float v12 = baseXPtr[12]; - float v13 = baseXPtr[13]; - float v14 = baseXPtr[14]; - float v15 = baseXPtr[15]; - float v16 = baseXPtr[16]; - float v17 = baseXPtr[17]; - float v18 = baseXPtr[18]; - float v19 = baseXPtr[19]; - float v20 = baseXPtr[20]; - float v21 = baseXPtr[21]; - float v22 = baseXPtr[22]; - float v23 = baseXPtr[23]; - float v24 = baseXPtr[24]; - float v25 = baseXPtr[25]; - float v26 = baseXPtr[26]; - float v27 = baseXPtr[27]; - float v28 = baseXPtr[28]; - float v29 = baseXPtr[29]; - float v30 = baseXPtr[30]; - float v31 = baseXPtr[31]; - float v32 = baseXPtr[32]; - float v33 = baseXPtr[33]; - float v34 = baseXPtr[34]; - float v35 = baseXPtr[35]; - float v36 = baseXPtr[36]; - float v37 = baseXPtr[37]; - float v38 = baseXPtr[38]; - float v39 = baseXPtr[39]; - float v40 = baseXPtr[40]; - float v41 = baseXPtr[41]; - float v42 = baseXPtr[42]; - float v43 = baseXPtr[43]; - float v44 = baseXPtr[44]; - float v45 = baseXPtr[45]; - float v46 = baseXPtr[46]; - float v47 = baseXPtr[47]; - float v48 = baseXPtr[48]; - float v49 = baseXPtr[49]; - float v50 = baseXPtr[50]; - float v51 = baseXPtr[51]; - float v52 = baseXPtr[52]; - float v53 = baseXPtr[53]; - float v54 = baseXPtr[54]; - float v55 = baseXPtr[55]; - float v56 = baseXPtr[56]; - float v57 = baseXPtr[57]; - float v58 = baseXPtr[58]; - float v59 = baseXPtr[59]; - float v60 = baseXPtr[60]; - float v61 = baseXPtr[61]; - float v62 = baseXPtr[62]; - float v63 = baseXPtr[63]; - - v0 = 0.5f * (v0 + Math.Abs(v0 )); - v1 = 0.5f * (v1 + Math.Abs(v1 )); - v2 = 0.5f * (v2 + Math.Abs(v2 )); - v3 = 0.5f * (v3 + Math.Abs(v3 )); - v4 = 0.5f * (v4 + Math.Abs(v4 )); - v5 = 0.5f * (v5 + Math.Abs(v5 )); - v6 = 0.5f * (v6 + Math.Abs(v6 )); - v7 = 0.5f * (v7 + Math.Abs(v7 )); - v8 = 0.5f * (v8 + Math.Abs(v8 )); - v9 = 0.5f * (v9 + Math.Abs(v9 )); - v10 = 0.5f * (v10 + Math.Abs(v10)); - v11 = 0.5f * (v11 + Math.Abs(v11)); - v12 = 0.5f * (v12 + Math.Abs(v12)); - v13 = 0.5f * (v13 + Math.Abs(v13)); - v14 = 0.5f * (v14 + Math.Abs(v14)); - v15 = 0.5f * (v15 + Math.Abs(v15)); - v16 = 0.5f * (v16 + Math.Abs(v16)); - v17 = 0.5f * (v17 + Math.Abs(v17)); - v18 = 0.5f * (v18 + Math.Abs(v18)); - v19 = 0.5f * (v19 + Math.Abs(v19)); - v20 = 0.5f * (v20 + Math.Abs(v20)); - v21 = 0.5f * (v21 + Math.Abs(v21)); - v22 = 0.5f * (v22 + Math.Abs(v22)); - v23 = 0.5f * (v23 + Math.Abs(v23)); - v24 = 0.5f * (v24 + Math.Abs(v24)); - v25 = 0.5f * (v25 + Math.Abs(v25)); - v26 = 0.5f * (v26 + Math.Abs(v26)); - v27 = 0.5f * (v27 + Math.Abs(v27)); - v28 = 0.5f * (v28 + Math.Abs(v28)); - v29 = 0.5f * (v29 + Math.Abs(v29)); - v30 = 0.5f * (v30 + Math.Abs(v30)); - v31 = 0.5f * (v31 + Math.Abs(v31)); - v32 = 0.5f * (v32 + Math.Abs(v32)); - v33 = 0.5f * (v33 + Math.Abs(v33)); - v34 = 0.5f * (v34 + Math.Abs(v34)); - v35 = 0.5f * (v35 + Math.Abs(v35)); - v36 = 0.5f * (v36 + Math.Abs(v36)); - v37 = 0.5f * (v37 + Math.Abs(v37)); - v38 = 0.5f * (v38 + Math.Abs(v38)); - v39 = 0.5f * (v39 + Math.Abs(v39)); - v40 = 0.5f * (v40 + Math.Abs(v40)); - v41 = 0.5f * (v41 + Math.Abs(v41)); - v42 = 0.5f * (v42 + Math.Abs(v42)); - v43 = 0.5f * (v43 + Math.Abs(v43)); - v44 = 0.5f * (v44 + Math.Abs(v44)); - v45 = 0.5f * (v45 + Math.Abs(v45)); - v46 = 0.5f * (v46 + Math.Abs(v46)); - v47 = 0.5f * (v47 + Math.Abs(v47)); - v48 = 0.5f * (v48 + Math.Abs(v48)); - v49 = 0.5f * (v49 + Math.Abs(v49)); - v50 = 0.5f * (v50 + Math.Abs(v50)); - v51 = 0.5f * (v51 + Math.Abs(v51)); - v52 = 0.5f * (v52 + Math.Abs(v52)); - v53 = 0.5f * (v53 + Math.Abs(v53)); - v54 = 0.5f * (v54 + Math.Abs(v54)); - v55 = 0.5f * (v55 + Math.Abs(v55)); - v56 = 0.5f * (v56 + Math.Abs(v56)); - v57 = 0.5f * (v57 + Math.Abs(v57)); - v58 = 0.5f * (v58 + Math.Abs(v58)); - v59 = 0.5f * (v59 + Math.Abs(v59)); - v60 = 0.5f * (v60 + Math.Abs(v60)); - v61 = 0.5f * (v61 + Math.Abs(v61)); - v62 = 0.5f * (v62 + Math.Abs(v62)); - v63 = 0.5f * (v63 + Math.Abs(v63)); - - baseOPtr[0 ] = v0 ; - baseOPtr[1 ] = v1 ; - baseOPtr[2 ] = v2 ; - baseOPtr[3 ] = v3 ; - baseOPtr[4 ] = v4 ; - baseOPtr[5 ] = v5 ; - baseOPtr[6 ] = v6 ; - baseOPtr[7 ] = v7 ; - baseOPtr[8 ] = v8 ; - baseOPtr[9 ] = v9 ; - baseOPtr[10] = v10; - baseOPtr[11] = v11; - baseOPtr[12] = v12; - baseOPtr[13] = v13; - baseOPtr[14] = v14; - baseOPtr[15] = v15; - baseOPtr[16] = v16; - baseOPtr[17] = v17; - baseOPtr[18] = v18; - baseOPtr[19] = v19; - baseOPtr[20] = v20; - baseOPtr[21] = v21; - baseOPtr[22] = v22; - baseOPtr[23] = v23; - baseOPtr[24] = v24; - baseOPtr[25] = v25; - baseOPtr[26] = v26; - baseOPtr[27] = v27; - baseOPtr[28] = v28; - baseOPtr[29] = v29; - baseOPtr[30] = v30; - baseOPtr[31] = v31; - baseOPtr[32] = v32; - baseOPtr[33] = v33; - baseOPtr[34] = v34; - baseOPtr[35] = v35; - baseOPtr[36] = v36; - baseOPtr[37] = v37; - baseOPtr[38] = v38; - baseOPtr[39] = v39; - baseOPtr[40] = v40; - baseOPtr[41] = v41; - baseOPtr[42] = v42; - baseOPtr[43] = v43; - baseOPtr[44] = v44; - baseOPtr[45] = v45; - baseOPtr[46] = v46; - baseOPtr[47] = v47; - baseOPtr[48] = v48; - baseOPtr[49] = v49; - baseOPtr[50] = v50; - baseOPtr[51] = v51; - baseOPtr[52] = v52; - baseOPtr[53] = v53; - baseOPtr[54] = v54; - baseOPtr[55] = v55; - baseOPtr[56] = v56; - baseOPtr[57] = v57; - baseOPtr[58] = v58; - baseOPtr[59] = v59; - baseOPtr[60] = v60; - baseOPtr[61] = v61; - baseOPtr[62] = v62; - baseOPtr[63] = v63; - } - - private void Relu6InnerLoop(long n) - { - // f(x) = min(max(x, 0), 6) - // "Convolutional Deep Belief Networks on CIFAR-10", A Krizhevsky, 2010 - // http://www.cs.utoronto.ca/~kriz/conv-cifar10-aug2010.pdf - - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0 ]; - float v1 = baseXPtr[1 ]; - float v2 = baseXPtr[2 ]; - float v3 = baseXPtr[3 ]; - float v4 = baseXPtr[4 ]; - float v5 = baseXPtr[5 ]; - float v6 = baseXPtr[6 ]; - float v7 = baseXPtr[7 ]; - float v8 = baseXPtr[8 ]; - float v9 = baseXPtr[9 ]; - float v10 = baseXPtr[10]; - float v11 = baseXPtr[11]; - float v12 = baseXPtr[12]; - float v13 = baseXPtr[13]; - float v14 = baseXPtr[14]; - float v15 = baseXPtr[15]; - float v16 = baseXPtr[16]; - float v17 = baseXPtr[17]; - float v18 = baseXPtr[18]; - float v19 = baseXPtr[19]; - float v20 = baseXPtr[20]; - float v21 = baseXPtr[21]; - float v22 = baseXPtr[22]; - float v23 = baseXPtr[23]; - float v24 = baseXPtr[24]; - float v25 = baseXPtr[25]; - float v26 = baseXPtr[26]; - float v27 = baseXPtr[27]; - float v28 = baseXPtr[28]; - float v29 = baseXPtr[29]; - float v30 = baseXPtr[30]; - float v31 = baseXPtr[31]; - float v32 = baseXPtr[32]; - float v33 = baseXPtr[33]; - float v34 = baseXPtr[34]; - float v35 = baseXPtr[35]; - float v36 = baseXPtr[36]; - float v37 = baseXPtr[37]; - float v38 = baseXPtr[38]; - float v39 = baseXPtr[39]; - float v40 = baseXPtr[40]; - float v41 = baseXPtr[41]; - float v42 = baseXPtr[42]; - float v43 = baseXPtr[43]; - float v44 = baseXPtr[44]; - float v45 = baseXPtr[45]; - float v46 = baseXPtr[46]; - float v47 = baseXPtr[47]; - float v48 = baseXPtr[48]; - float v49 = baseXPtr[49]; - float v50 = baseXPtr[50]; - float v51 = baseXPtr[51]; - float v52 = baseXPtr[52]; - float v53 = baseXPtr[53]; - float v54 = baseXPtr[54]; - float v55 = baseXPtr[55]; - float v56 = baseXPtr[56]; - float v57 = baseXPtr[57]; - float v58 = baseXPtr[58]; - float v59 = baseXPtr[59]; - float v60 = baseXPtr[60]; - float v61 = baseXPtr[61]; - float v62 = baseXPtr[62]; - float v63 = baseXPtr[63]; - - v0 = 0.5f * (-Math.Abs(v0 - 6f) + Math.Abs(v0) + 6f); - v1 = 0.5f * (-Math.Abs(v1 - 6f) + Math.Abs(v1) + 6f); - v2 = 0.5f * (-Math.Abs(v2 - 6f) + Math.Abs(v2) + 6f); - v3 = 0.5f * (-Math.Abs(v3 - 6f) + Math.Abs(v3) + 6f); - v4 = 0.5f * (-Math.Abs(v4 - 6f) + Math.Abs(v4) + 6f); - v5 = 0.5f * (-Math.Abs(v5 - 6f) + Math.Abs(v5) + 6f); - v6 = 0.5f * (-Math.Abs(v6 - 6f) + Math.Abs(v6) + 6f); - v7 = 0.5f * (-Math.Abs(v7 - 6f) + Math.Abs(v7) + 6f); - v8 = 0.5f * (-Math.Abs(v8 - 6f) + Math.Abs(v8) + 6f); - v9 = 0.5f * (-Math.Abs(v9 - 6f) + Math.Abs(v9) + 6f); - v10 = 0.5f * (-Math.Abs(v10 - 6f) + Math.Abs(v10) + 6f); - v11 = 0.5f * (-Math.Abs(v11 - 6f) + Math.Abs(v11) + 6f); - v12 = 0.5f * (-Math.Abs(v12 - 6f) + Math.Abs(v12) + 6f); - v13 = 0.5f * (-Math.Abs(v13 - 6f) + Math.Abs(v13) + 6f); - v14 = 0.5f * (-Math.Abs(v14 - 6f) + Math.Abs(v14) + 6f); - v15 = 0.5f * (-Math.Abs(v15 - 6f) + Math.Abs(v15) + 6f); - v16 = 0.5f * (-Math.Abs(v16 - 6f) + Math.Abs(v16) + 6f); - v17 = 0.5f * (-Math.Abs(v17 - 6f) + Math.Abs(v17) + 6f); - v18 = 0.5f * (-Math.Abs(v18 - 6f) + Math.Abs(v18) + 6f); - v19 = 0.5f * (-Math.Abs(v19 - 6f) + Math.Abs(v19) + 6f); - v20 = 0.5f * (-Math.Abs(v20 - 6f) + Math.Abs(v20) + 6f); - v21 = 0.5f * (-Math.Abs(v21 - 6f) + Math.Abs(v21) + 6f); - v22 = 0.5f * (-Math.Abs(v22 - 6f) + Math.Abs(v22) + 6f); - v23 = 0.5f * (-Math.Abs(v23 - 6f) + Math.Abs(v23) + 6f); - v24 = 0.5f * (-Math.Abs(v24 - 6f) + Math.Abs(v24) + 6f); - v25 = 0.5f * (-Math.Abs(v25 - 6f) + Math.Abs(v25) + 6f); - v26 = 0.5f * (-Math.Abs(v26 - 6f) + Math.Abs(v26) + 6f); - v27 = 0.5f * (-Math.Abs(v27 - 6f) + Math.Abs(v27) + 6f); - v28 = 0.5f * (-Math.Abs(v28 - 6f) + Math.Abs(v28) + 6f); - v29 = 0.5f * (-Math.Abs(v29 - 6f) + Math.Abs(v29) + 6f); - v30 = 0.5f * (-Math.Abs(v30 - 6f) + Math.Abs(v30) + 6f); - v31 = 0.5f * (-Math.Abs(v31 - 6f) + Math.Abs(v31) + 6f); - v32 = 0.5f * (-Math.Abs(v32 - 6f) + Math.Abs(v32) + 6f); - v33 = 0.5f * (-Math.Abs(v33 - 6f) + Math.Abs(v33) + 6f); - v34 = 0.5f * (-Math.Abs(v34 - 6f) + Math.Abs(v34) + 6f); - v35 = 0.5f * (-Math.Abs(v35 - 6f) + Math.Abs(v35) + 6f); - v36 = 0.5f * (-Math.Abs(v36 - 6f) + Math.Abs(v36) + 6f); - v37 = 0.5f * (-Math.Abs(v37 - 6f) + Math.Abs(v37) + 6f); - v38 = 0.5f * (-Math.Abs(v38 - 6f) + Math.Abs(v38) + 6f); - v39 = 0.5f * (-Math.Abs(v39 - 6f) + Math.Abs(v39) + 6f); - v40 = 0.5f * (-Math.Abs(v40 - 6f) + Math.Abs(v40) + 6f); - v41 = 0.5f * (-Math.Abs(v41 - 6f) + Math.Abs(v41) + 6f); - v42 = 0.5f * (-Math.Abs(v42 - 6f) + Math.Abs(v42) + 6f); - v43 = 0.5f * (-Math.Abs(v43 - 6f) + Math.Abs(v43) + 6f); - v44 = 0.5f * (-Math.Abs(v44 - 6f) + Math.Abs(v44) + 6f); - v45 = 0.5f * (-Math.Abs(v45 - 6f) + Math.Abs(v45) + 6f); - v46 = 0.5f * (-Math.Abs(v46 - 6f) + Math.Abs(v46) + 6f); - v47 = 0.5f * (-Math.Abs(v47 - 6f) + Math.Abs(v47) + 6f); - v48 = 0.5f * (-Math.Abs(v48 - 6f) + Math.Abs(v48) + 6f); - v49 = 0.5f * (-Math.Abs(v49 - 6f) + Math.Abs(v49) + 6f); - v50 = 0.5f * (-Math.Abs(v50 - 6f) + Math.Abs(v50) + 6f); - v51 = 0.5f * (-Math.Abs(v51 - 6f) + Math.Abs(v51) + 6f); - v52 = 0.5f * (-Math.Abs(v52 - 6f) + Math.Abs(v52) + 6f); - v53 = 0.5f * (-Math.Abs(v53 - 6f) + Math.Abs(v53) + 6f); - v54 = 0.5f * (-Math.Abs(v54 - 6f) + Math.Abs(v54) + 6f); - v55 = 0.5f * (-Math.Abs(v55 - 6f) + Math.Abs(v55) + 6f); - v56 = 0.5f * (-Math.Abs(v56 - 6f) + Math.Abs(v56) + 6f); - v57 = 0.5f * (-Math.Abs(v57 - 6f) + Math.Abs(v57) + 6f); - v58 = 0.5f * (-Math.Abs(v58 - 6f) + Math.Abs(v58) + 6f); - v59 = 0.5f * (-Math.Abs(v59 - 6f) + Math.Abs(v59) + 6f); - v60 = 0.5f * (-Math.Abs(v60 - 6f) + Math.Abs(v60) + 6f); - v61 = 0.5f * (-Math.Abs(v61 - 6f) + Math.Abs(v61) + 6f); - v62 = 0.5f * (-Math.Abs(v62 - 6f) + Math.Abs(v62) + 6f); - v63 = 0.5f * (-Math.Abs(v63 - 6f) + Math.Abs(v63) + 6f); - - baseOPtr[0 ] = v0 ; - baseOPtr[1 ] = v1 ; - baseOPtr[2 ] = v2 ; - baseOPtr[3 ] = v3 ; - baseOPtr[4 ] = v4 ; - baseOPtr[5 ] = v5 ; - baseOPtr[6 ] = v6 ; - baseOPtr[7 ] = v7 ; - baseOPtr[8 ] = v8 ; - baseOPtr[9 ] = v9 ; - baseOPtr[10] = v10; - baseOPtr[11] = v11; - baseOPtr[12] = v12; - baseOPtr[13] = v13; - baseOPtr[14] = v14; - baseOPtr[15] = v15; - baseOPtr[16] = v16; - baseOPtr[17] = v17; - baseOPtr[18] = v18; - baseOPtr[19] = v19; - baseOPtr[20] = v20; - baseOPtr[21] = v21; - baseOPtr[22] = v22; - baseOPtr[23] = v23; - baseOPtr[24] = v24; - baseOPtr[25] = v25; - baseOPtr[26] = v26; - baseOPtr[27] = v27; - baseOPtr[28] = v28; - baseOPtr[29] = v29; - baseOPtr[30] = v30; - baseOPtr[31] = v31; - baseOPtr[32] = v32; - baseOPtr[33] = v33; - baseOPtr[34] = v34; - baseOPtr[35] = v35; - baseOPtr[36] = v36; - baseOPtr[37] = v37; - baseOPtr[38] = v38; - baseOPtr[39] = v39; - baseOPtr[40] = v40; - baseOPtr[41] = v41; - baseOPtr[42] = v42; - baseOPtr[43] = v43; - baseOPtr[44] = v44; - baseOPtr[45] = v45; - baseOPtr[46] = v46; - baseOPtr[47] = v47; - baseOPtr[48] = v48; - baseOPtr[49] = v49; - baseOPtr[50] = v50; - baseOPtr[51] = v51; - baseOPtr[52] = v52; - baseOPtr[53] = v53; - baseOPtr[54] = v54; - baseOPtr[55] = v55; - baseOPtr[56] = v56; - baseOPtr[57] = v57; - baseOPtr[58] = v58; - baseOPtr[59] = v59; - baseOPtr[60] = v60; - baseOPtr[61] = v61; - baseOPtr[62] = v62; - baseOPtr[63] = v63; - } - - private void LeakyReluInnerLoop(long n) - { - // f(x) = alpha * x for x < 0, f(x) = x for x >= 0. - // "Rectifier Nonlinearities Improve Neural Network Acoustic Models". AL Maas, 2013 - // http://web.stanford.edu/~awni/papers/relu_hybrid_icml2013_final.pdf - - // from Theano impl - // https://github.com/Theano/theano/blob/d395439aec5a6ddde8ef5c266fd976412a5c5695/theano/tensor/nnet/nnet.py#L2209-L2251 - float f1 = 0.5f * (1f + alpha); - float f2 = 0.5f * (1f - alpha); - - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0 ]; - float v1 = baseXPtr[1 ]; - float v2 = baseXPtr[2 ]; - float v3 = baseXPtr[3 ]; - float v4 = baseXPtr[4 ]; - float v5 = baseXPtr[5 ]; - float v6 = baseXPtr[6 ]; - float v7 = baseXPtr[7 ]; - float v8 = baseXPtr[8 ]; - float v9 = baseXPtr[9 ]; - float v10 = baseXPtr[10]; - float v11 = baseXPtr[11]; - float v12 = baseXPtr[12]; - float v13 = baseXPtr[13]; - float v14 = baseXPtr[14]; - float v15 = baseXPtr[15]; - float v16 = baseXPtr[16]; - float v17 = baseXPtr[17]; - float v18 = baseXPtr[18]; - float v19 = baseXPtr[19]; - float v20 = baseXPtr[20]; - float v21 = baseXPtr[21]; - float v22 = baseXPtr[22]; - float v23 = baseXPtr[23]; - float v24 = baseXPtr[24]; - float v25 = baseXPtr[25]; - float v26 = baseXPtr[26]; - float v27 = baseXPtr[27]; - float v28 = baseXPtr[28]; - float v29 = baseXPtr[29]; - float v30 = baseXPtr[30]; - float v31 = baseXPtr[31]; - float v32 = baseXPtr[32]; - float v33 = baseXPtr[33]; - float v34 = baseXPtr[34]; - float v35 = baseXPtr[35]; - float v36 = baseXPtr[36]; - float v37 = baseXPtr[37]; - float v38 = baseXPtr[38]; - float v39 = baseXPtr[39]; - float v40 = baseXPtr[40]; - float v41 = baseXPtr[41]; - float v42 = baseXPtr[42]; - float v43 = baseXPtr[43]; - float v44 = baseXPtr[44]; - float v45 = baseXPtr[45]; - float v46 = baseXPtr[46]; - float v47 = baseXPtr[47]; - float v48 = baseXPtr[48]; - float v49 = baseXPtr[49]; - float v50 = baseXPtr[50]; - float v51 = baseXPtr[51]; - float v52 = baseXPtr[52]; - float v53 = baseXPtr[53]; - float v54 = baseXPtr[54]; - float v55 = baseXPtr[55]; - float v56 = baseXPtr[56]; - float v57 = baseXPtr[57]; - float v58 = baseXPtr[58]; - float v59 = baseXPtr[59]; - float v60 = baseXPtr[60]; - float v61 = baseXPtr[61]; - float v62 = baseXPtr[62]; - float v63 = baseXPtr[63]; - - v0 = f1 * v0 + f2 * Math.Abs(v0) ; - v1 = f1 * v1 + f2 * Math.Abs(v1) ; - v2 = f1 * v2 + f2 * Math.Abs(v2) ; - v3 = f1 * v3 + f2 * Math.Abs(v3) ; - v4 = f1 * v4 + f2 * Math.Abs(v4) ; - v5 = f1 * v5 + f2 * Math.Abs(v5) ; - v6 = f1 * v6 + f2 * Math.Abs(v6) ; - v7 = f1 * v7 + f2 * Math.Abs(v7) ; - v8 = f1 * v8 + f2 * Math.Abs(v8) ; - v9 = f1 * v9 + f2 * Math.Abs(v9) ; - v10 = f1 * v10 + f2 * Math.Abs(v10); - v11 = f1 * v11 + f2 * Math.Abs(v11); - v12 = f1 * v12 + f2 * Math.Abs(v12); - v13 = f1 * v13 + f2 * Math.Abs(v13); - v14 = f1 * v14 + f2 * Math.Abs(v14); - v15 = f1 * v15 + f2 * Math.Abs(v15); - v16 = f1 * v16 + f2 * Math.Abs(v16); - v17 = f1 * v17 + f2 * Math.Abs(v17); - v18 = f1 * v18 + f2 * Math.Abs(v18); - v19 = f1 * v19 + f2 * Math.Abs(v19); - v20 = f1 * v20 + f2 * Math.Abs(v20); - v21 = f1 * v21 + f2 * Math.Abs(v21); - v22 = f1 * v22 + f2 * Math.Abs(v22); - v23 = f1 * v23 + f2 * Math.Abs(v23); - v24 = f1 * v24 + f2 * Math.Abs(v24); - v25 = f1 * v25 + f2 * Math.Abs(v25); - v26 = f1 * v26 + f2 * Math.Abs(v26); - v27 = f1 * v27 + f2 * Math.Abs(v27); - v28 = f1 * v28 + f2 * Math.Abs(v28); - v29 = f1 * v29 + f2 * Math.Abs(v29); - v30 = f1 * v30 + f2 * Math.Abs(v30); - v31 = f1 * v31 + f2 * Math.Abs(v31); - v32 = f1 * v32 + f2 * Math.Abs(v32); - v33 = f1 * v33 + f2 * Math.Abs(v33); - v34 = f1 * v34 + f2 * Math.Abs(v34); - v35 = f1 * v35 + f2 * Math.Abs(v35); - v36 = f1 * v36 + f2 * Math.Abs(v36); - v37 = f1 * v37 + f2 * Math.Abs(v37); - v38 = f1 * v38 + f2 * Math.Abs(v38); - v39 = f1 * v39 + f2 * Math.Abs(v39); - v40 = f1 * v40 + f2 * Math.Abs(v40); - v41 = f1 * v41 + f2 * Math.Abs(v41); - v42 = f1 * v42 + f2 * Math.Abs(v42); - v43 = f1 * v43 + f2 * Math.Abs(v43); - v44 = f1 * v44 + f2 * Math.Abs(v44); - v45 = f1 * v45 + f2 * Math.Abs(v45); - v46 = f1 * v46 + f2 * Math.Abs(v46); - v47 = f1 * v47 + f2 * Math.Abs(v47); - v48 = f1 * v48 + f2 * Math.Abs(v48); - v49 = f1 * v49 + f2 * Math.Abs(v49); - v50 = f1 * v50 + f2 * Math.Abs(v50); - v51 = f1 * v51 + f2 * Math.Abs(v51); - v52 = f1 * v52 + f2 * Math.Abs(v52); - v53 = f1 * v53 + f2 * Math.Abs(v53); - v54 = f1 * v54 + f2 * Math.Abs(v54); - v55 = f1 * v55 + f2 * Math.Abs(v55); - v56 = f1 * v56 + f2 * Math.Abs(v56); - v57 = f1 * v57 + f2 * Math.Abs(v57); - v58 = f1 * v58 + f2 * Math.Abs(v58); - v59 = f1 * v59 + f2 * Math.Abs(v59); - v60 = f1 * v60 + f2 * Math.Abs(v60); - v61 = f1 * v61 + f2 * Math.Abs(v61); - v62 = f1 * v62 + f2 * Math.Abs(v62); - v63 = f1 * v63 + f2 * Math.Abs(v63); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - baseOPtr[4 ] = v4 ; - baseOPtr[5 ] = v5 ; - baseOPtr[6 ] = v6 ; - baseOPtr[7 ] = v7 ; - baseOPtr[8 ] = v8 ; - baseOPtr[9 ] = v9 ; - baseOPtr[10] = v10; - baseOPtr[11] = v11; - baseOPtr[12] = v12; - baseOPtr[13] = v13; - baseOPtr[14] = v14; - baseOPtr[15] = v15; - baseOPtr[16] = v16; - baseOPtr[17] = v17; - baseOPtr[18] = v18; - baseOPtr[19] = v19; - baseOPtr[20] = v20; - baseOPtr[21] = v21; - baseOPtr[22] = v22; - baseOPtr[23] = v23; - baseOPtr[24] = v24; - baseOPtr[25] = v25; - baseOPtr[26] = v26; - baseOPtr[27] = v27; - baseOPtr[28] = v28; - baseOPtr[29] = v29; - baseOPtr[30] = v30; - baseOPtr[31] = v31; - baseOPtr[32] = v32; - baseOPtr[33] = v33; - baseOPtr[34] = v34; - baseOPtr[35] = v35; - baseOPtr[36] = v36; - baseOPtr[37] = v37; - baseOPtr[38] = v38; - baseOPtr[39] = v39; - baseOPtr[40] = v40; - baseOPtr[41] = v41; - baseOPtr[42] = v42; - baseOPtr[43] = v43; - baseOPtr[44] = v44; - baseOPtr[45] = v45; - baseOPtr[46] = v46; - baseOPtr[47] = v47; - baseOPtr[48] = v48; - baseOPtr[49] = v49; - baseOPtr[50] = v50; - baseOPtr[51] = v51; - baseOPtr[52] = v52; - baseOPtr[53] = v53; - baseOPtr[54] = v54; - baseOPtr[55] = v55; - baseOPtr[56] = v56; - baseOPtr[57] = v57; - baseOPtr[58] = v58; - baseOPtr[59] = v59; - baseOPtr[60] = v60; - baseOPtr[61] = v61; - baseOPtr[62] = v62; - baseOPtr[63] = v63; - } - - private void EluInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - if (v0 <= 0) - v0 = alpha * (Mathf.Exp(v0) - 1f); - if (v1 <= 0) - v1 = alpha * (Mathf.Exp(v1) - 1f); - if (v2 <= 0) - v2 = alpha * (Mathf.Exp(v2) - 1f); - if (v3 <= 0) - v3 = alpha * (Mathf.Exp(v3) - 1f); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void PReluInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float* baseBPtr = bPtr + (n * unrollSize) % bLen; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - float s0 = baseBPtr[0 % bLen]; - float s1 = baseBPtr[1 % bLen]; - float s2 = baseBPtr[2 % bLen]; - float s3 = baseBPtr[3 % bLen]; - - if (v0 <= 0) - v0 = s0 * v0; - if (v1 <= 0) - v1 = s1 * v1; - if (v2 <= 0) - v2 = s2 * v2; - if (v3 <= 0) - v3 = s3 * v3; - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void SoftplusInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Log(Mathf.Exp(v0) + 1f); - v1 = Mathf.Log(Mathf.Exp(v1) + 1f); - v2 = Mathf.Log(Mathf.Exp(v2) + 1f); - v3 = Mathf.Log(Mathf.Exp(v3) + 1f); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void SigmoidInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = 1f / (1f + Mathf.Exp(-v0)); - v1 = 1f / (1f + Mathf.Exp(-v1)); - v2 = 1f / (1f + Mathf.Exp(-v2)); - v3 = 1f / (1f + Mathf.Exp(-v3)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void HardSigmoidInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Max(0.0f, Mathf.Min(1.0f, alpha * v0 + beta)); - v1 = Mathf.Max(0.0f, Mathf.Min(1.0f, alpha * v1 + beta)); - v2 = Mathf.Max(0.0f, Mathf.Min(1.0f, alpha * v2 + beta)); - v3 = Mathf.Max(0.0f, Mathf.Min(1.0f, alpha * v3 + beta)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void SwishInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = v0 / (1f + Mathf.Exp(-v0)); - v1 = v1 / (1f + Mathf.Exp(-v1)); - v2 = v2 / (1f + Mathf.Exp(-v2)); - v3 = v3 / (1f + Mathf.Exp(-v3)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void ExpInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Exp(v0); - v1 = Mathf.Exp(v1); - v2 = Mathf.Exp(v2); - v3 = Mathf.Exp(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void SqrtInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Sqrt(v0); - v1 = Mathf.Sqrt(v1); - v2 = Mathf.Sqrt(v2); - v3 = Mathf.Sqrt(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void TanhInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = MathfEx.Tanh(v0); - v1 = MathfEx.Tanh(v1); - v2 = MathfEx.Tanh(v2); - v3 = MathfEx.Tanh(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void AcosInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Acos(v0); - v1 = Mathf.Acos(v1); - v2 = Mathf.Acos(v2); - v3 = Mathf.Acos(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void AcoshInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Log(v0 + Mathf.Sqrt(v0 * v0 - 1.0f)); - v1 = Mathf.Log(v1 + Mathf.Sqrt(v1 * v1 - 1.0f)); - v2 = Mathf.Log(v2 + Mathf.Sqrt(v2 * v2 - 1.0f)); - v3 = Mathf.Log(v3 + Mathf.Sqrt(v3 * v3 - 1.0f)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void AsinInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Asin(v0); - v1 = Mathf.Asin(v1); - v2 = Mathf.Asin(v2); - v3 = Mathf.Asin(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void AsinhInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Log(v0 + Mathf.Sqrt(v0 * v0 + 1.0f)); - v1 = Mathf.Log(v1 + Mathf.Sqrt(v1 * v1 + 1.0f)); - v2 = Mathf.Log(v2 + Mathf.Sqrt(v2 * v2 + 1.0f)); - v3 = Mathf.Log(v3 + Mathf.Sqrt(v3 * v3 + 1.0f)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void AtanInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Atan(v0); - v1 = Mathf.Atan(v1); - v2 = Mathf.Atan(v2); - v3 = Mathf.Atan(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void AtanhInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = 0.5f * Mathf.Log((1.0f + v0) / (1.0f - v0)); - v1 = 0.5f * Mathf.Log((1.0f + v1) / (1.0f - v1)); - v2 = 0.5f * Mathf.Log((1.0f + v2) / (1.0f - v2)); - v3 = 0.5f * Mathf.Log((1.0f + v3) / (1.0f - v3)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void CosInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Cos(v0); - v1 = Mathf.Cos(v1); - v2 = Mathf.Cos(v2); - v3 = Mathf.Cos(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void CoshInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = 0.5f * (Mathf.Exp(v0) + Mathf.Exp(-v0)); - v1 = 0.5f * (Mathf.Exp(v1) + Mathf.Exp(-v1)); - v2 = 0.5f * (Mathf.Exp(v2) + Mathf.Exp(-v2)); - v3 = 0.5f * (Mathf.Exp(v3) + Mathf.Exp(-v3)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void SinInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Sin(v0); - v1 = Mathf.Sin(v1); - v2 = Mathf.Sin(v2); - v3 = Mathf.Sin(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void SinhInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = 0.5f * (Mathf.Exp(v0) - Mathf.Exp(-v0)); - v1 = 0.5f * (Mathf.Exp(v1) - Mathf.Exp(-v1)); - v2 = 0.5f * (Mathf.Exp(v2) - Mathf.Exp(-v2)); - v3 = 0.5f * (Mathf.Exp(v3) - Mathf.Exp(-v3)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void TanInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - v0 = Mathf.Tan(v0); - v1 = Mathf.Tan(v1); - v2 = Mathf.Tan(v2); - v3 = Mathf.Tan(v3); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void ErfInnerLoop(long n) - { - float* baseXPtr = xPtr + n * unrollSize; - float* baseOPtr = oPtr + n * unrollSize; - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x0 = Mathf.Abs(v0); - float x1 = Mathf.Abs(v1); - float x2 = Mathf.Abs(v2); - float x3 = Mathf.Abs(v3); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t0 = 1.0f / (1.0f + p * x0); - float t1 = 1.0f / (1.0f + p * x1); - float t2 = 1.0f / (1.0f + p * x2); - float t3 = 1.0f / (1.0f + p * x3); - - v0 = Mathf.Sign(v0) * (1 - (a1 * (t0) + a2 * (t0*t0) + a3 * (t0*t0*t0) + a4 * (t0*t0*t0*t0) + a5 * (t0*t0*t0*t0*t0)) * Mathf.Exp(-x0 * x0)); - v1 = Mathf.Sign(v1) * (1 - (a1 * (t1) + a2 * (t1*t1) + a3 * (t1*t1*t1) + a4 * (t1*t1*t1*t1) + a5 * (t1*t1*t1*t1*t1)) * Mathf.Exp(-x1 * x1)); - v2 = Mathf.Sign(v2) * (1 - (a1 * (t2) + a2 * (t2*t2) + a3 * (t2*t2*t2) + a4 * (t2*t2*t2*t2) + a5 * (t2*t2*t2*t2*t2)) * Mathf.Exp(-x2 * x2)); - v3 = Mathf.Sign(v3) * (1 - (a1 * (t3) + a2 * (t3*t3) + a3 * (t3*t3*t3) + a4 * (t3*t3*t3*t3) + a5 * (t3*t3*t3*t3*t3)) * Mathf.Exp(-x3 * x3)); - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private void AddInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] + bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]; - oPtr[i + 1] = xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] + bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]; - oPtr[i + 2] = xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] + bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]; - oPtr[i + 3] = xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] + bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]; - } - - private void SubInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] - bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]; - oPtr[i + 1] = xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] - bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]; - oPtr[i + 2] = xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] - bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]; - oPtr[i + 3] = xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] - bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]; - } - - private void MulInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] * bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]; - oPtr[i + 1] = xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] * bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]; - oPtr[i + 2] = xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] * bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]; - oPtr[i + 3] = xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] * bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]; - } - - private void DivInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] / bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]; - oPtr[i + 1] = xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] / bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]; - oPtr[i + 2] = xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] / bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]; - oPtr[i + 3] = xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] / bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]; - } - - private void MinInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = Mathf.Min( xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] , bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)] ); - oPtr[i + 1] = Mathf.Min( xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] , bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)] ); - oPtr[i + 2] = Mathf.Min( xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] , bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)] ); - oPtr[i + 3] = Mathf.Min( xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] , bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)] ); - } - - private void MaxInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = Mathf.Max(xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)], bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]); - oPtr[i + 1] = Mathf.Max(xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)], bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]); - oPtr[i + 2] = Mathf.Max(xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)], bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]); - oPtr[i + 3] = Mathf.Max(xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)], bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]); - } - - private void GreaterInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = (xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] > bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] > bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] > bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] > bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]) ? 1.0f : 0.0f; - } - - private void GreaterEqualInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = (xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] >= bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] >= bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] >= bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] >= bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]) ? 1.0f : 0.0f; - } - - private void LessInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = (xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] < bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] < bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] < bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] < bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]) ? 1.0f : 0.0f; - } - - private void LessEqualInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = (xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] <= bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] <= bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] <= bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] <= bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]) ? 1.0f : 0.0f; - } - - private void EqualInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = (xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)] == bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)] == bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)] == bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)] == bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]) ? 1.0f : 0.0f; - } - - private void LogicalOrInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)]) || Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)])) ? 1.0f : 0.0f; - oPtr[i + 1] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)]) || Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)])) ? 1.0f : 0.0f; - oPtr[i + 2] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)]) || Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)])) ? 1.0f : 0.0f; - oPtr[i + 3] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)]) || Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)])) ? 1.0f : 0.0f; - } - - private void LogicalAndInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)]) && Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)])) ? 1.0f : 0.0f; - oPtr[i + 1] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)]) && Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)])) ? 1.0f : 0.0f; - oPtr[i + 2] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)]) && Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)])) ? 1.0f : 0.0f; - oPtr[i + 3] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)]) && Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)])) ? 1.0f : 0.0f; - } - - private void LogicalXorInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)]) ^ Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)])) ? 1.0f : 0.0f; - oPtr[i + 1] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)]) ^ Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)])) ? 1.0f : 0.0f; - oPtr[i + 2] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)]) ^ Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)])) ? 1.0f : 0.0f; - oPtr[i + 3] = (Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)]) ^ Convert.ToBoolean(bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)])) ? 1.0f : 0.0f; - } - - private void WhereInnerLoop(long n) - { - int i = (int)n * unrollSize; - - int b0 = 0, h0 = 0, w0 = 0, ch0 = 0; - int b1 = 0, h1 = 0, w1 = 0, ch1 = 0; - int b2 = 0, h2 = 0, w2 = 0, ch2 = 0; - int b3 = 0, h3 = 0, w3 = 0, ch3 = 0; - oShape.GetPositionsFromIndex(i + 0, ref b0, ref h0, ref w0, ref ch0); - oShape.GetPositionsFromIndex(i + 1, ref b1, ref h1, ref w1, ref ch1); - oShape.GetPositionsFromIndex(i + 2, ref b2, ref h2, ref w2, ref ch2); - oShape.GetPositionsFromIndex(i + 3, ref b3, ref h3, ref w3, ref ch3); - - oPtr[i + 0] = Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b0, h0, w0, ch0)]) ? sPtr[sShape.IndexWithBroadcast(b0, h0, w0, ch0)] : bPtr[bShape.IndexWithBroadcast(b0, h0, w0, ch0)]; - oPtr[i + 1] = Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b1, h1, w1, ch1)]) ? sPtr[sShape.IndexWithBroadcast(b1, h1, w1, ch1)] : bPtr[bShape.IndexWithBroadcast(b1, h1, w1, ch1)]; - oPtr[i + 2] = Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b2, h2, w2, ch2)]) ? sPtr[sShape.IndexWithBroadcast(b2, h2, w2, ch2)] : bPtr[bShape.IndexWithBroadcast(b2, h2, w2, ch2)]; - oPtr[i + 3] = Convert.ToBoolean(xPtr[xShape.IndexWithBroadcast(b3, h3, w3, ch3)]) ? sPtr[sShape.IndexWithBroadcast(b3, h3, w3, ch3)] : bPtr[bShape.IndexWithBroadcast(b3, h3, w3, ch3)]; - } - - private void AddInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = xPtr[(i + 0) % xLen] + bPtr[(i + 0) % bLen]; - oPtr[i + 1] = xPtr[(i + 1) % xLen] + bPtr[(i + 1) % bLen]; - oPtr[i + 2] = xPtr[(i + 2) % xLen] + bPtr[(i + 2) % bLen]; - oPtr[i + 3] = xPtr[(i + 3) % xLen] + bPtr[(i + 3) % bLen]; - } - - private void SubInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = xPtr[(i + 0) % xLen] - bPtr[(i + 0) % bLen]; - oPtr[i + 1] = xPtr[(i + 1) % xLen] - bPtr[(i + 1) % bLen]; - oPtr[i + 2] = xPtr[(i + 2) % xLen] - bPtr[(i + 2) % bLen]; - oPtr[i + 3] = xPtr[(i + 3) % xLen] - bPtr[(i + 3) % bLen]; - } - - private void MulInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = xPtr[(i + 0) % xLen] * bPtr[(i + 0) % bLen]; - oPtr[i + 1] = xPtr[(i + 1) % xLen] * bPtr[(i + 1) % bLen]; - oPtr[i + 2] = xPtr[(i + 2) % xLen] * bPtr[(i + 2) % bLen]; - oPtr[i + 3] = xPtr[(i + 3) % xLen] * bPtr[(i + 3) % bLen]; - } - - private void DivInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = xPtr[(i + 0) % xLen] / bPtr[(i + 0) % bLen]; - oPtr[i + 1] = xPtr[(i + 1) % xLen] / bPtr[(i + 1) % bLen]; - oPtr[i + 2] = xPtr[(i + 2) % xLen] / bPtr[(i + 2) % bLen]; - oPtr[i + 3] = xPtr[(i + 3) % xLen] / bPtr[(i + 3) % bLen]; - } - - private void MinInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = Mathf.Min(xPtr[(i + 0) % xLen], bPtr[(i + 0) % bLen]); - oPtr[i + 1] = Mathf.Min(xPtr[(i + 1) % xLen], bPtr[(i + 1) % bLen]); - oPtr[i + 2] = Mathf.Min(xPtr[(i + 2) % xLen], bPtr[(i + 2) % bLen]); - oPtr[i + 3] = Mathf.Min(xPtr[(i + 3) % xLen], bPtr[(i + 3) % bLen]); - } - - private void MaxInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = Mathf.Max(xPtr[(i + 0) % xLen], bPtr[(i + 0) % bLen]); - oPtr[i + 1] = Mathf.Max(xPtr[(i + 1) % xLen], bPtr[(i + 1) % bLen]); - oPtr[i + 2] = Mathf.Max(xPtr[(i + 2) % xLen], bPtr[(i + 2) % bLen]); - oPtr[i + 3] = Mathf.Max(xPtr[(i + 3) % xLen], bPtr[(i + 3) % bLen]); - } - - private void GreaterInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (xPtr[(i + 0) % xLen] > bPtr[(i + 0) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[(i + 1) % xLen] > bPtr[(i + 1) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[(i + 2) % xLen] > bPtr[(i + 2) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[(i + 3) % xLen] > bPtr[(i + 3) % bLen]) ? 1.0f : 0.0f; - } - - private void GreaterEqualInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (xPtr[(i + 0) % xLen] >= bPtr[(i + 0) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[(i + 1) % xLen] >= bPtr[(i + 1) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[(i + 2) % xLen] >= bPtr[(i + 2) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[(i + 3) % xLen] >= bPtr[(i + 3) % bLen]) ? 1.0f : 0.0f; - } - - private void LessInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (xPtr[(i + 0) % xLen] < bPtr[(i + 0) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[(i + 1) % xLen] < bPtr[(i + 1) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[(i + 2) % xLen] < bPtr[(i + 2) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[(i + 3) % xLen] < bPtr[(i + 3) % bLen]) ? 1.0f : 0.0f; - } - - private void LessEqualInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (xPtr[(i + 0) % xLen] <= bPtr[(i + 0) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[(i + 1) % xLen] <= bPtr[(i + 1) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[(i + 2) % xLen] <= bPtr[(i + 2) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[(i + 3) % xLen] <= bPtr[(i + 3) % bLen]) ? 1.0f : 0.0f; - } - - private void EqualInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (xPtr[(i + 0) % xLen] == bPtr[(i + 0) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 1] = (xPtr[(i + 1) % xLen] == bPtr[(i + 1) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 2] = (xPtr[(i + 2) % xLen] == bPtr[(i + 2) % bLen]) ? 1.0f : 0.0f; - oPtr[i + 3] = (xPtr[(i + 3) % xLen] == bPtr[(i + 3) % bLen]) ? 1.0f : 0.0f; - } - - private void LogicalOrInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (Convert.ToBoolean(xPtr[(i + 0) % xLen]) || Convert.ToBoolean(bPtr[(i + 0) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 1] = (Convert.ToBoolean(xPtr[(i + 1) % xLen]) || Convert.ToBoolean(bPtr[(i + 1) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 2] = (Convert.ToBoolean(xPtr[(i + 2) % xLen]) || Convert.ToBoolean(bPtr[(i + 2) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 3] = (Convert.ToBoolean(xPtr[(i + 3) % xLen]) || Convert.ToBoolean(bPtr[(i + 3) % bLen])) ? 1.0f : 0.0f; - } - - private void LogicalAndInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (Convert.ToBoolean(xPtr[(i + 0) % xLen]) && Convert.ToBoolean(bPtr[(i + 0) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 1] = (Convert.ToBoolean(xPtr[(i + 1) % xLen]) && Convert.ToBoolean(bPtr[(i + 1) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 2] = (Convert.ToBoolean(xPtr[(i + 2) % xLen]) && Convert.ToBoolean(bPtr[(i + 2) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 3] = (Convert.ToBoolean(xPtr[(i + 3) % xLen]) && Convert.ToBoolean(bPtr[(i + 3) % bLen])) ? 1.0f : 0.0f; - } - - private void LogicalXorInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (Convert.ToBoolean(xPtr[(i + 0) % xLen]) ^ Convert.ToBoolean(bPtr[(i + 0) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 1] = (Convert.ToBoolean(xPtr[(i + 1) % xLen]) ^ Convert.ToBoolean(bPtr[(i + 1) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 2] = (Convert.ToBoolean(xPtr[(i + 2) % xLen]) ^ Convert.ToBoolean(bPtr[(i + 2) % bLen])) ? 1.0f : 0.0f; - oPtr[i + 3] = (Convert.ToBoolean(xPtr[(i + 3) % xLen]) ^ Convert.ToBoolean(bPtr[(i + 3) % bLen])) ? 1.0f : 0.0f; - } - - private void LogicalNotInnerLoop(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = Convert.ToBoolean(xPtr[i + 0]) ? 0.0f : 1.0f; - oPtr[i + 1] = Convert.ToBoolean(xPtr[i + 1]) ? 0.0f : 1.0f; - oPtr[i + 2] = Convert.ToBoolean(xPtr[i + 2]) ? 0.0f : 1.0f; - oPtr[i + 3] = Convert.ToBoolean(xPtr[i + 3]) ? 0.0f : 1.0f; - } - - private void SignInnerLoop(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = (xPtr[i + 0] > 0) ? 1.0f : ((xPtr[i + 0] < 0) ? -1.0f : 0.0f); - oPtr[i + 1] = (xPtr[i + 1] > 0) ? 1.0f : ((xPtr[i + 1] < 0) ? -1.0f : 0.0f); - oPtr[i + 2] = (xPtr[i + 2] > 0) ? 1.0f : ((xPtr[i + 2] < 0) ? -1.0f : 0.0f); - oPtr[i + 3] = (xPtr[i + 3] > 0) ? 1.0f : ((xPtr[i + 3] < 0) ? -1.0f : 0.0f); - } - - private void WhereInnerLoopNoBroadcast(long n) - { - int i = (int)n * unrollSize; - - oPtr[i + 0] = Convert.ToBoolean(xPtr[(i + 0) % xLen]) ? sPtr[(i + 0) % bLen] : bPtr[(i + 0) % bLen]; - oPtr[i + 1] = Convert.ToBoolean(xPtr[(i + 1) % xLen]) ? sPtr[(i + 1) % bLen] : bPtr[(i + 1) % bLen]; - oPtr[i + 2] = Convert.ToBoolean(xPtr[(i + 2) % xLen]) ? sPtr[(i + 2) % bLen] : bPtr[(i + 2) % bLen]; - oPtr[i + 3] = Convert.ToBoolean(xPtr[(i + 3) % xLen]) ? sPtr[(i + 3) % bLen] : bPtr[(i + 3) % bLen]; - } - - private void ScaleBiasInnerLoop(long n) - { - var offset = n * unrollSize; - float* baseXPtr = xPtr + offset; - float* baseOPtr = oPtr + offset; - - float v0 = baseXPtr[0]; - float v1 = baseXPtr[1]; - float v2 = baseXPtr[2]; - float v3 = baseXPtr[3]; - - float s0 = sPtr[(offset + 0) % sLen]; - float s1 = sPtr[(offset + 1) % sLen]; - float s2 = sPtr[(offset + 2) % sLen]; - float s3 = sPtr[(offset + 3) % sLen]; - - float b0 = bPtr[(offset + 0) % bLen]; - float b1 = bPtr[(offset + 1) % bLen]; - float b2 = bPtr[(offset + 2) % bLen]; - float b3 = bPtr[(offset + 3) % bLen]; - - v0 = s0 * v0 + b0; - v1 = s1 * v1 + b1; - v2 = s2 * v2 + b2; - v3 = s3 * v3 + b3; - - baseOPtr[0] = v0; - baseOPtr[1] = v1; - baseOPtr[2] = v2; - baseOPtr[3] = v3; - } - - private float Add(float a, float b) - { - return a + b; - } - private float Sub(float a, float b) - { - return a - b; - } - private float Mul(float a, float b) - { - return a * b; - } - private float Div(float a, float b) - { - return a / b; - } - private float Min(float a, float b) - { - return Mathf.Min(a, b); - } - private float Max(float a, float b) - { - return Mathf.Max(a, b); - } - private float Greater(float a, float b) - { - return Convert.ToSingle(a > b); - } - private float GreaterEqual(float a, float b) - { - return Convert.ToSingle(a >= b); - } - private float Less(float a, float b) - { - return Convert.ToSingle(a < b); - } - private float LessEqual(float a, float b) - { - return Convert.ToSingle(a <= b); - } - private float Equal(float a, float b) - { - return Convert.ToSingle(a == b); - } - private float LogicalOr(float a, float b) - { - return Convert.ToSingle(Convert.ToBoolean(a) || Convert.ToBoolean(b)); - } - private float LogicalAnd(float a, float b) - { - return Convert.ToSingle(Convert.ToBoolean(a) && Convert.ToBoolean(b)); - } - private float LogicalXor(float a, float b) - { - return Convert.ToSingle(Convert.ToBoolean(a) ^ Convert.ToBoolean(b)); - } - private float LogicalNot(float a) - { - return Convert.ToSingle(!Convert.ToBoolean(a)); - } - private float Sign(float a) - { - return (a > 0) ? 1.0f : ((a < 0) ? -1.0f : 0.0f); - } - private float Where(float c, float a, float b) - { - return Convert.ToBoolean(c) ? a : b; - } - } - - -} // namespace Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaUnsafeArrayCPU.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaUnsafeArrayCPU.cs.meta deleted file mode 100644 index 01a107c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/BarracudaUnsafeArrayCPU.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c077f9591cc6d4804bc89b66a2a67c0d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOps.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOps.cs deleted file mode 100644 index 9bb45d7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOps.cs +++ /dev/null @@ -1,1129 +0,0 @@ -using System.Collections.Generic; - -namespace Unity.Barracuda { - -/// -/// Compares output of two different implementations of `IOps`. Useful for debugging purposes -/// -public class CompareOps : IOps, IModelCompiler -{ - private readonly IOps m_Ops1; - private readonly IOps m_Ops2; - private readonly CompareOpsUtils.LogLevel m_DifferenceLogLevel; - private readonly float m_Epsilon; - - /// - /// Create `CompareOps` - /// - /// first `IOps` implementation - /// second `IOps` implementation - /// difference log level - /// error threshold - public CompareOps(IOps ops1, IOps ops2, CompareOpsUtils.LogLevel differenceLogLevel, float epsilon) - { - m_Ops1 = ops1; - m_Ops2 = ops2; - m_DifferenceLogLevel = differenceLogLevel; - m_Epsilon = epsilon; - } - -#if ENABLE_BARRACUDA_STATS - public IEnumerable GetTempMemoryStatistics() - { - return m_Ops1.GetTempMemoryStatistics(); - } -#endif //ENABLE_BARRACUDA_STATS - - /// - public virtual void PostLayerCleanup() - { - m_Ops1.PostLayerCleanup(); - m_Ops2.PostLayerCleanup(); - } - - /// - public virtual void PrepareModel(Model model, IDictionary inputShapes, IVars vars) - { - if (m_Ops1 is IModelCompiler) - ((IModelCompiler)m_Ops1).PrepareModel(model, inputShapes, vars); - - if (m_Ops2 is IModelCompiler) - ((IModelCompiler)m_Ops2).PrepareModel(model, inputShapes, vars); - } - - /// - public virtual void PreExecuteLayer(Layer layer, Tensor[] inputs) - { - if (m_Ops1 is IModelCompiler) - ((IModelCompiler)m_Ops1).PreExecuteLayer(layer, inputs); - - if (m_Ops2 is IModelCompiler) - ((IModelCompiler)m_Ops1).PreExecuteLayer(layer, inputs); - } - - /// - Tensor IOps.MatMul(Tensor X, int rankX, Tensor Y, int rankY) - { - var A = m_Ops1.MatMul(X, rankX, Y, rankY); - var B = m_Ops2.MatMul(X, rankX, Y, rankY); - CheckSame(A, B, Layer.Type.MatMul); - return Y; - } - - /// - Tensor IOps.MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - var A = m_Ops1.MatMul(X, xTranspose, Y, yTranspose); - var B = m_Ops2.MatMul(X, xTranspose, Y, yTranspose); - CheckSame(A, B, Layer.Type.MatMul); - return A; - } - - /// - Tensor IOps.Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - var Y = m_Ops1.Dense(X, W, B, fusedActivation); - var Z = m_Ops2.Dense(X, W, B, fusedActivation); - CheckSame(Y, Z, Layer.Type.Dense); - return Y; - } - - /// - Tensor IOps.Dense3(Tensor X, Tensor W, Tensor B) - { - var Y = m_Ops1.Dense3(X, W, B); - var Z = m_Ops2.Dense3(X, W, B); - CheckSame(Y, Z, Layer.Type.Dense3); - return Y; - } - - /// - Tensor IOps.Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - var Y = m_Ops1.Conv2D(X, K, B, stride, pad, fusedActivation); - var Z = m_Ops2.Conv2D(X, K, B, stride, pad, fusedActivation); - CheckSame(Y, Z, Layer.Type.Conv2D); - return Y; - } - - /// - Tensor IOps.Conv3D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - var Y = m_Ops1.Conv3D(X, K, B, stride, pad, fusedActivation); - var Z = m_Ops2.Conv3D(X, K, B, stride, pad, fusedActivation); - CheckSame(Y, Z, Layer.Type.Conv3D); - return Y; - } - - /// - Tensor IOps.DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - var Y = m_Ops1.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - var Z = m_Ops2.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - CheckSame(Y, Z, Layer.Type.DepthwiseConv2D); - return Y; - } - - /// - Tensor IOps.Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - var Y = m_Ops1.Conv2DTrans(X, K, B, stride, pad, outputAdjustment, fusedActivation); - var Z = m_Ops2.Conv2DTrans(X, K, B, stride, pad, outputAdjustment, fusedActivation); - CheckSame(Y, Z, Layer.Type.Conv2DTrans); - return Y; - } - - /// - Tensor IOps.Upsample2D(Tensor X, int[] scale, bool bilinear) - { - var Y = m_Ops1.Upsample2D(X, scale, bilinear); - var Z = m_Ops2.Upsample2D(X, scale, bilinear); - CheckSame(Y, Z, Layer.Type.Upsample2D); - return Y; - } - - /// - Tensor IOps.Upsample3D(Tensor X, int[] scale, bool trilinear) - { - var Y = m_Ops1.Upsample3D(X, scale, trilinear); - var Z = m_Ops2.Upsample3D(X, scale, trilinear); - CheckSame(Y, Z, Layer.Type.Upsample3D); - return Y; - } - - /// - Tensor IOps.Resample2D(Tensor X, int[] size, bool bilinear) - { - var Y = m_Ops1.Resample2D(X, size, bilinear); - var Z = m_Ops2.Resample2D(X, size, bilinear); - CheckSame(Y, Z, Layer.Type.Resample2D); - return Y; - } - - /// - Tensor IOps.DepthToSpace(Tensor X, int[] scale, Layer.DepthToSpaceMode mode) - { - var Y = m_Ops1.DepthToSpace(X, scale, mode); - var Z = m_Ops2.DepthToSpace(X, scale, mode); - CheckSame(Y, Z, Layer.Type.DepthToSpace); - return Y; - } - - /// - Tensor IOps.SpaceToDepth(Tensor X, int[] scale) - { - var Y = m_Ops1.SpaceToDepth(X, scale); - var Z = m_Ops2.SpaceToDepth(X, scale); - CheckSame(Y, Z, Layer.Type.SpaceToDepth); - return Y; - } - - /// - Tensor IOps.MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - var Y = m_Ops1.MaxPool2D(X, pool, stride, pad); - var Z = m_Ops2.MaxPool2D(X, pool, stride, pad); - CheckSame(Y, Z, Layer.Type.MaxPool2D); - return Y; - } - - /// - Tensor IOps.AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - var Y = m_Ops1.AvgPool2D(X, pool, stride, pad); - var Z = m_Ops2.AvgPool2D(X, pool, stride, pad); - CheckSame(Y, Z, Layer.Type.AvgPool2D); - return Y; - } - - /// - Tensor IOps.GlobalMaxPool2D(Tensor X) - { - var Y = m_Ops1.GlobalMaxPool2D(X); - var Z = m_Ops2.GlobalMaxPool2D(X); - CheckSame(Y, Z, Layer.Type.GlobalMaxPool2D); - return Y; - } - - /// - Tensor IOps.GlobalAvgPool2D(Tensor X) - { - var Y = m_Ops1.GlobalAvgPool2D(X); - var Z = m_Ops2.GlobalAvgPool2D(X); - CheckSame(Y, Z, Layer.Type.GlobalAvgPool2D); - return Y; - } - - /// - Tensor IOps.GlobalAvgVariancePool2D(Tensor X) - { - var Y = m_Ops1.GlobalAvgVariancePool2D(X); - var Z = m_Ops2.GlobalAvgVariancePool2D(X); - CheckSame(Y, Z, Layer.Type.GlobalAvgPool2D); - return Y; - } - - /// - Tensor IOps.Border2D(Tensor x, int[] pad, float value) - { - var Y = m_Ops1.Border2D(x, pad, value); - var Z = m_Ops2.Border2D(x, pad, value); - CheckSame(Y, Z, Layer.Type.Border2D); - return Y; - } - - /// - Tensor IOps.Border3D(Tensor x, int[] pad, float value) - { - var Y = m_Ops1.Border3D(x, pad, value); - var Z = m_Ops2.Border3D(x, pad, value); - CheckSame(Y, Z, Layer.Type.Border3D); - return Y; - } - - /// - Tensor IOps.Pad2DReflect(Tensor x, int[] pad) - { - var Y = m_Ops1.Pad2DReflect(x, pad); - var Z = m_Ops2.Pad2DReflect(x, pad); - CheckSame(Y, Z, Layer.Type.Pad2DReflect); - return Y; - } - - /// - Tensor IOps.Pad2DSymmetric(Tensor x, int[] pad) - { - var Y = m_Ops1.Pad2DSymmetric(x, pad); - var Z = m_Ops2.Pad2DSymmetric(x, pad); - CheckSame(Y, Z, Layer.Type.Pad2DSymmetric); - return Y; - } - - /// - Tensor IOps.Pad2DEdge(Tensor x, int[] pad) - { - var Y = m_Ops1.Pad2DEdge(x, pad); - var Z = m_Ops2.Pad2DEdge(x, pad); - CheckSame(Y, Z, Layer.Type.Pad2DEdge); - return Y; - } - - /// - Tensor IOps.ScaleBias(Tensor X, Tensor S, Tensor B) - { - var Y = m_Ops1.ScaleBias(X, S, B); - var Z = m_Ops2.ScaleBias(X, S, B); - CheckSame(Y, Z, Layer.Type.ScaleBias); - return Y; - } - - /// - Tensor IOps.Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) - { - var Y = m_Ops1.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); - var Z = m_Ops2.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); - CheckSame(Y, Z, Layer.Type.Normalization); - return Y; - } - - /// - Tensor IOps.LRN(Tensor X, float alpha, float beta, float bias, int size) - { - var Y = m_Ops1.LRN(X, alpha, beta, bias, size); - var Z = m_Ops2.LRN(X, alpha, beta, bias, size); - CheckSame(Y, Z, Layer.Type.LRN); - return Y; - } - - /// - Tensor IOps.Dropout(Tensor X, float alpha) - { - var Y = m_Ops1.Dropout(X, alpha); - var Z = m_Ops2.Dropout(X, alpha); - CheckSame(Y, Z, Layer.Type.Dropout); - return Y; - } - - /// - Tensor IOps.RandomNormal(TensorShape s, float mean, float scale, int seed) - { - var Y = m_Ops1.RandomNormal(s, mean, scale, seed); - var Z = m_Ops2.RandomNormal(s, mean, scale, seed); - CheckSame(Y, Z, Layer.Type.RandomNormal); - return Y; - } - - /// - Tensor IOps.RandomUniform(TensorShape s, float mean, float scale, int seed) - { - var Y = m_Ops1.RandomUniform(s, mean, scale, seed); - var Z = m_Ops2.RandomUniform(s, mean, scale, seed); - CheckSame(Y, Z, Layer.Type.RandomUniform); - return Y; - } - - /// - Tensor IOps.Multinomial(Tensor X, int count, int seed) - { - var Y = m_Ops1.Multinomial(X, count, seed); - var Z = m_Ops2.Multinomial(X, count, seed); - CheckSame(Y, Z, Layer.Type.Multinomial); - return Y; - } - - /// - Tensor IOps.OneHot(Tensor X, int depth, float onValue, float offValue, int inputRank) - { - var Y = m_Ops1.OneHot(X, depth, onValue, offValue, inputRank); - var Z = m_Ops2.OneHot(X, depth, onValue, offValue, inputRank); - CheckSame(Y, Z, Layer.Type.OneHot); - return Y; - } - - /// - Tensor IOps.RoiAlign(Tensor X, Tensor rois, Tensor indices, int outputHeight, int outputWidth, int samplingRatio, float spatialScale) - { - var Y = m_Ops1.RoiAlign(X, rois, indices, outputHeight, outputWidth, samplingRatio, spatialScale); - var Z = m_Ops2.RoiAlign(X, rois, indices, outputHeight, outputWidth, samplingRatio, spatialScale); - CheckSame(Y, Z, Layer.Type.RoiAlign); - return Y; - } - - /// - Tensor IOps.TopKIndices(Tensor X, int k, int axis, bool largest, bool sorted) - { - var Y = m_Ops1.TopKIndices(X, k, axis, largest, sorted); - var Z = m_Ops2.TopKIndices(X, k, axis, largest, sorted); - CheckSame(Y, Z, Layer.Type.TopKIndices); - return Y; - } - - /// - public Tensor TopKValues(Tensor X, Tensor I, int axis) - { - var Y = m_Ops1.TopKValues(X, I, axis); - var Z = m_Ops2.TopKValues(X, I, axis); - CheckSame(Y, Z, Layer.Type.TopKValues); - return Y; - } - - /// - public Tensor NonZero(Tensor X) - { - var Y = m_Ops1.NonZero(X); - var Z = m_Ops2.NonZero(X); - CheckSame(Y, Z, Layer.Type.NonZero); - return Y; - } - - /// - Tensor IOps.Relu(Tensor X) - { - var Y = m_Ops1.Relu(X); - var Z = m_Ops2.Relu(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Relu); - return Y; - } - - /// - Tensor IOps.Softmax(Tensor X, int axis) - { - var Y = m_Ops1.Softmax(X, axis); - var Z = m_Ops2.Softmax(X, axis); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Softmax); - return Y; - } - - /// - Tensor IOps.LogSoftmax(Tensor X, int axis) - { - var Y = m_Ops1.LogSoftmax(X, axis); - var Z = m_Ops2.LogSoftmax(X, axis); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.LogSoftmax); - return Y; - } - - /// - Tensor IOps.Tanh(Tensor X) - { - var Y = m_Ops1.Tanh(X); - var Z = m_Ops2.Tanh(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Tanh); - return Y; - } - - /// - Tensor IOps.Softplus(Tensor X) - { - var Y = m_Ops1.Softplus(X); - var Z = m_Ops2.Softplus(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Softplus); - return Y; - } - - /// - Tensor IOps.Sigmoid(Tensor X) - { - var Y = m_Ops1.Sigmoid(X); - var Z = m_Ops2.Sigmoid(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Sigmoid); - return Y; - } - - /// - Tensor IOps.HardSigmoid(Tensor X, float alpha, float beta) - { - var Y = m_Ops1.HardSigmoid(X, alpha, beta); - var Z = m_Ops2.HardSigmoid(X, alpha, beta); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.HardSigmoid); - return Y; - } - - /// - Tensor IOps.Elu(Tensor X, float alpha) - { - var Y = m_Ops1.Elu(X, alpha); - var Z = m_Ops2.Elu(X, alpha); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Elu); - return Y; - } - - /// - Tensor IOps.Relu6(Tensor X) - { - var Y = m_Ops1.Relu6(X); - var Z = m_Ops2.Relu6(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Relu6); - return Y; - } - - /// - Tensor IOps.LeakyRelu(Tensor X, float alpha) - { - var Y = m_Ops1.LeakyRelu(X, alpha); - var Z = m_Ops2.LeakyRelu(X, alpha); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.LeakyRelu); - return Y; - } - - /// - Tensor IOps.Selu(Tensor X, float alpha, float gamma) - { - var Y = m_Ops1.Selu(X, alpha, gamma); - var Z = m_Ops2.Selu(X, alpha, gamma); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Selu); - return Y; - } - - /// - Tensor IOps.PRelu(Tensor X, Tensor S) - { - var Y = m_Ops1.PRelu(X, S); - var Z = m_Ops2.PRelu(X, S); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.PRelu); - return Y; - } - - /// - Tensor IOps.Swish(Tensor X) - { - var Y = m_Ops1.Swish(X); - var Z = m_Ops2.Swish(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Swish); - return Y; - } - - /// - Tensor IOps.Abs(Tensor X) - { - var Y = m_Ops1.Abs(X); - var Z = m_Ops2.Abs(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Abs); - return Y; - } - - /// - Tensor IOps.Neg(Tensor X) - { - var Y = m_Ops1.Neg(X); - var Z = m_Ops2.Neg(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Neg); - return Y; - } - - /// - Tensor IOps.Ceil(Tensor X) - { - var Y = m_Ops1.Ceil(X); - var Z = m_Ops2.Ceil(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Ceil); - return Y; - } - - /// - Tensor IOps.Clip(Tensor X, float min, float max) - { - var Y = m_Ops1.Clip(X, min, max); - var Z = m_Ops2.Clip(X, min, max); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Clip); - return Y; - } - - /// - Tensor IOps.Floor(Tensor X) - { - var Y = m_Ops1.Floor(X); - var Z = m_Ops2.Floor(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Floor); - return Y; - } - - /// - Tensor IOps.Round(Tensor X) - { - var Y = m_Ops1.Round(X); - var Z = m_Ops2.Round(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Round); - return Y; - } - - /// - Tensor IOps.Reciprocal(Tensor X) - { - var Y = m_Ops1.Reciprocal(X); - var Z = m_Ops2.Reciprocal(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Reciprocal); - return Y; - } - - /// - Tensor IOps.Pow(Tensor X, float alpha) - { - var Y = m_Ops1.Pow(X, alpha); - var Z = m_Ops2.Pow(X, alpha); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Pow); - return Y; - } - - /// - Tensor IOps.Exp(Tensor X) - { - var Y = m_Ops1.Exp(X); - var Z = m_Ops2.Exp(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Exp); - return Y; - } - - /// - Tensor IOps.Log(Tensor X) - { - var Y = m_Ops1.Log(X); - var Z = m_Ops2.Log(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Log); - return Y; - } - - /// - Tensor IOps.Sqrt(Tensor X) - { - var Y = m_Ops1.Sqrt(X); - var Z = m_Ops2.Sqrt(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Sqrt); - return Y; - } - - /// - Tensor IOps.Acos(Tensor X) - { - var Y = m_Ops1.Acos(X); - var Z = m_Ops2.Acos(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Acos); - return Y; - } - - /// - Tensor IOps.Acosh(Tensor X) - { - var Y = m_Ops1.Acosh(X); - var Z = m_Ops2.Acosh(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Acosh); - return Y; - } - - /// - Tensor IOps.Asin(Tensor X) - { - var Y = m_Ops1.Asin(X); - var Z = m_Ops2.Asin(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Asin); - return Y; - } - - /// - Tensor IOps.Asinh(Tensor X) - { - var Y = m_Ops1.Asinh(X); - var Z = m_Ops2.Asinh(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Asinh); - return Y; - } - - /// - Tensor IOps.Atan(Tensor X) - { - var Y = m_Ops1.Atan(X); - var Z = m_Ops2.Atan(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Atan); - return Y; - } - - /// - Tensor IOps.Atanh(Tensor X) - { - var Y = m_Ops1.Atanh(X); - var Z = m_Ops2.Atanh(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Atanh); - return Y; - } - - /// - Tensor IOps.Cos(Tensor X) - { - var Y = m_Ops1.Cos(X); - var Z = m_Ops2.Cos(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Cos); - return Y; - } - - /// - Tensor IOps.Cosh(Tensor X) - { - var Y = m_Ops1.Cosh(X); - var Z = m_Ops2.Cosh(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Cosh); - return Y; - } - - /// - Tensor IOps.Sin(Tensor X) - { - var Y = m_Ops1.Sin(X); - var Z = m_Ops2.Sin(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Sin); - return Y; - } - - /// - Tensor IOps.Sinh(Tensor X) - { - var Y = m_Ops1.Sinh(X); - var Z = m_Ops2.Sinh(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Sinh); - return Y; - } - - /// - Tensor IOps.Tan(Tensor X) - { - var Y = m_Ops1.Tan(X); - var Z = m_Ops2.Tan(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Tan); - return Y; - } - - /// - Tensor IOps.Erf(Tensor X) - { - var Y = m_Ops1.Erf(X); - var Z = m_Ops2.Erf(X); - CheckSame(Y, Z, Layer.Type.Activation + " " + Layer.Activation.Erf); - return Y; - } - - /// - Tensor IOps.Add(Tensor[] tensors) - { - var Y = m_Ops1.Add(tensors); - var Z = m_Ops2.Add(tensors); - CheckSame(Y, Z, Layer.Type.Add); - return Y; - } - - /// - Tensor IOps.Sub(Tensor[] tensors) - { - var Y = m_Ops1.Sub(tensors); - var Z = m_Ops2.Sub(tensors); - CheckSame(Y, Z, Layer.Type.Sub); - return Y; - } - - /// - Tensor IOps.Mul(Tensor[] tensors) - { - var Y = m_Ops1.Mul(tensors); - var Z = m_Ops2.Mul(tensors); - CheckSame(Y, Z, Layer.Type.Mul, tensors); - return Y; - } - - /// - Tensor IOps.Div(Tensor[] tensors) - { - var Y = m_Ops1.Div(tensors); - var Z = m_Ops2.Div(tensors); - CheckSame(Y, Z, Layer.Type.Div); - return Y; - } - - /// - Tensor IOps.Pow(Tensor[] tensors) - { - var Y = m_Ops1.Pow(tensors); - var Z = m_Ops2.Pow(tensors); - CheckSame(Y, Z, Layer.Type.Pow); - return Y; - } - - /// - Tensor IOps.Min(Tensor[] tensors) - { - var Y = m_Ops1.Min(tensors); - var Z = m_Ops2.Min(tensors); - CheckSame(Y, Z, Layer.Type.Min); - return Y; - } - - /// - Tensor IOps.Max(Tensor[] tensors) - { - var Y = m_Ops1.Max(tensors); - var Z = m_Ops2.Max(tensors); - CheckSame(Y, Z, Layer.Type.Max); - return Y; - } - - /// - Tensor IOps.Mean(Tensor[] tensors) - { - var Y = m_Ops1.Mean(tensors); - var Z = m_Ops2.Mean(tensors); - CheckSame(Y, Z, Layer.Type.Mean); - return Y; - } - - /// - Tensor IOps.ArgMax(Tensor X, int axis) - { - var Y = m_Ops1.ArgMax(X, axis); - var Z = m_Ops2.ArgMax(X, axis); - CheckSame(Y, Z, Layer.Type.ArgMax); - return Y; - } - - /// - Tensor IOps.ArgMin(Tensor X, int axis) - { - var Y = m_Ops1.ArgMin(X, axis); - var Z = m_Ops2.ArgMin(X, axis); - CheckSame(Y, Z, Layer.Type.ArgMin); - return Y; - } - - /// - Tensor IOps.ReduceMax(Tensor X, int axis) - { - var Y = m_Ops1.ReduceMax(X, axis); - var Z = m_Ops2.ReduceMax(X, axis); - CheckSame(Y, Z, Layer.Type.ReduceMax); - return Y; - } - - /// - Tensor IOps.ReduceMean(Tensor X, int axis) - { - var Y = m_Ops1.ReduceMean(X, axis); - var Z = m_Ops2.ReduceMean(X, axis); - CheckSame(Y, Z, Layer.Type.ReduceMean); - return Y; - } - - /// - Tensor IOps.ReduceMin(Tensor X, int axis) - { - var Y = m_Ops1.ReduceMin(X, axis); - var Z = m_Ops2.ReduceMin(X, axis); - CheckSame(Y, Z, Layer.Type.ReduceMin); - return Y; - } - - /// - Tensor IOps.ReduceProd(Tensor X, int axis) - { - var Y = m_Ops1.ReduceProd(X, axis); - var Z = m_Ops2.ReduceProd(X, axis); - CheckSame(Y, Z, Layer.Type.ReduceProd); - return Y; - } - - /// - Tensor IOps.ReduceSum(Tensor X, int axis) - { - var Y = m_Ops1.ReduceSum(X, axis); - var Z = m_Ops2.ReduceSum(X, axis); - CheckSame(Y, Z, Layer.Type.ReduceSum); - return Y; - } - - /// - Tensor IOps.Greater(Tensor a, Tensor b) - { - var Y = m_Ops1.Greater(a, b); - var Z = m_Ops2.Greater(a, b); - CheckSame(Y, Z, Layer.Type.Greater); - return Y; - } - - /// - Tensor IOps.GreaterEqual(Tensor a, Tensor b) - { - var Y = m_Ops1.GreaterEqual(a, b); - var Z = m_Ops2.GreaterEqual(a, b); - CheckSame(Y, Z, Layer.Type.GreaterEqual); - return Y; - } - - /// - Tensor IOps.Less(Tensor a, Tensor b) - { - var Y = m_Ops1.Less(a, b); - var Z = m_Ops2.Less(a, b); - CheckSame(Y, Z, Layer.Type.Less); - return Y; - - } - - /// - Tensor IOps.LessEqual(Tensor a, Tensor b) - { - var Y = m_Ops1.LessEqual(a, b); - var Z = m_Ops2.LessEqual(a, b); - CheckSame(Y, Z, Layer.Type.LessEqual); - return Y; - } - - /// - Tensor IOps.Equal(Tensor a, Tensor b) - { - var Y = m_Ops1.Equal(a, b); - var Z = m_Ops2.Equal(a, b); - CheckSame(Y, Z, Layer.Type.Equal); - return Y; - } - - /// - Tensor IOps.LogicalOr(Tensor a, Tensor b) - { - var Y = m_Ops1.LogicalOr(a, b); - var Z = m_Ops2.LogicalOr(a, b); - CheckSame(Y, Z, Layer.Type.LogicalOr); - return Y; - } - - /// - Tensor IOps.LogicalAnd(Tensor a, Tensor b) - { - var Y = m_Ops1.LogicalAnd(a, b); - var Z = m_Ops2.LogicalAnd(a, b); - CheckSame(Y, Z, Layer.Type.LogicalAnd); - return Y; - } - - /// - Tensor IOps.LogicalXor(Tensor a, Tensor b) - { - var Y = m_Ops1.LogicalXor(a, b); - var Z = m_Ops2.LogicalXor(a, b); - CheckSame(Y, Z, Layer.Type.LogicalXor); - return Y; - } - - /// - Tensor IOps.LogicalNot(Tensor x) - { - var Y = m_Ops1.LogicalNot(x); - var Z = m_Ops2.LogicalNot(x); - CheckSame(Y, Z, Layer.Type.LogicalNot); - return Y; - } - - /// - Tensor IOps.Sign(Tensor x) - { - var Y = m_Ops1.Sign(x); - var Z = m_Ops2.Sign(x); - CheckSame(Y, Z, Layer.Type.Sign); - return Y; - } - - /// - Tensor IOps.Where(Tensor c, Tensor a, Tensor b) - { - var Y = m_Ops1.Where(c, a, b); - var Z = m_Ops2.Where(c, a, b); - CheckSame(Y, Z, Layer.Type.Where); - return Y; - } - - /// - Tensor IOps.Flatten(Tensor X) - { - var Y = m_Ops1.Flatten(X); - var Z = m_Ops2.Flatten(X); - CheckSame(Y, Z, Layer.Type.Flatten); - return Y; - } - - /// - Tensor IOps.Reshape(Tensor X, TensorShape shape) - { - var Y = m_Ops1.Reshape(X, shape); - var Z = m_Ops2.Reshape(X, shape); - CheckSame(Y, Z, Layer.Type.Reshape); - return Y; - } - - /// - Tensor IOps.Expand(Tensor X, TensorShape shape) - { - var Y = m_Ops1.Expand(X, shape); - var Z = m_Ops2.Expand(X, shape); - CheckSame(Y, Z, Layer.Type.Expand); - return Y; - } - - /// - Tensor IOps.Transpose(Tensor X) - { - var Y = m_Ops1.Transpose(X); - var Z = m_Ops2.Transpose(X); - CheckSame(Y, Z, Layer.Type.Transpose); - return Y; - } - - /// - Tensor IOps.Transpose(Tensor X, int[] permutations) - { - var Y = m_Ops1.Transpose(X, permutations); - var Z = m_Ops2.Transpose(X, permutations); - CheckSame(Y, Z, Layer.Type.Transpose); - return Y; - } - - /// - Tensor IOps.Gather(Tensor[] tensors, int axis) - { - var Y = m_Ops1.Gather(tensors, axis); - var Z = m_Ops2.Gather(tensors, axis); - CheckSame(Y, Z, Layer.Type.Gather); - return Y; - } - - // - Tensor IOps.ScatterND(Tensor X, Tensor indices, Tensor updates, Layer.ScatterNDReductionMode reduction) - { - var Y = m_Ops1.ScatterND(X, indices, updates, reduction); - var Z = m_Ops2.ScatterND(X, indices, updates, reduction); - CheckSame(Y, Z, Layer.Type.ScatterND); - return Y; - } - - /// - Tensor IOps.NonMaxSuppression(Tensor[] tensors, int maxOutputBoxesPerClass, float iouThreshold, float scoreThreshold, int centerPointBox) - { - var Y = m_Ops1.NonMaxSuppression(tensors, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, centerPointBox); - var Z = m_Ops2.NonMaxSuppression(tensors, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, centerPointBox); - CheckSame(Y, Z, Layer.Type.NonMaxSuppression); - return Y; - } - - /// - public Tensor[] LSTM(Tensor X, Tensor[] W, Tensor[] R, Tensor[] Wb, Tensor[] Rb, Tensor hidden, Tensor cell) - { - var Y = m_Ops1.LSTM(X, W, R, Wb, Rb, hidden, cell); - var Z = m_Ops2.LSTM(X, W, R, Wb, Rb, hidden, cell); - for (int i = 0; i < Y.Length; i++) - { - CheckSame(Y[i], Z[i], Layer.Type.LSTM); - } - - return Y; - } - - /// - Tensor IOps.Concat(Tensor[] tensors, int axis) - { - var Y = m_Ops1.Concat(tensors, axis); - var Z = m_Ops2.Concat(tensors, axis); - CheckSame(Y, Z, Layer.Type.Concat); - return Y; - } - - /// - Tensor IOps.StridedSlice(Tensor X, int[] starts, int[] ends, int[] strides) - { - var Y = m_Ops1.StridedSlice(X, starts, ends, strides); - var Z = m_Ops2.StridedSlice(X, starts, ends, strides); - CheckSame(Y, Z, Layer.Type.StridedSlice); - return Y; - } - - /// - Tensor IOps.Tile(Tensor X, int[] repeats) - { - var Y = m_Ops1.Tile(X, repeats); - var Z = m_Ops2.Tile(X, repeats); - CheckSame(Y, Z, Layer.Type.Tile); - return Y; - } - - /// - Tensor IOps.Shape(Tensor X, int axis) - { - var Y = m_Ops1.Shape(X, axis); - var Z = m_Ops2.Shape(X, axis); - CheckSame(Y, Z, Layer.Type.Shape); - return Y; - } - - /// - Tensor IOps.ConstantOfShape(TensorShape X, DataType type, float value) - { - var Y = m_Ops1.ConstantOfShape(X, type, value); - var Z = m_Ops2.ConstantOfShape(X, type, value); - CheckSame(Y, Z, Layer.Type.ConstantOfShape); - return Y; - } - - /// - Tensor IOps.Copy(Tensor x) - { - var Y = m_Ops1.Copy(x); - var Z = m_Ops2.Copy(x); - CheckSame(Y, Z, "Copy"); - return Y; - } - - /// - Tensor IOps.Prepare(Tensor X) - { - var Y = m_Ops1.Prepare(X); - var Z = m_Ops2.Prepare(X); - CheckSame(Y, Z, "Prepare"); - return Y; - } - - - /// - - Tensor IOps.PrepareNoAlloc(Tensor X) - { - var Y = m_Ops1.PrepareNoAlloc(X); - var Z = m_Ops2.PrepareNoAlloc(X); - CheckSame(Y, Z, "PrepareNoAlloc"); - return Y; - } - - /// - void IOps.ResetAllocator(bool keepCachedMemory) - { - m_Ops1.ResetAllocator(keepCachedMemory); - m_Ops2.ResetAllocator(keepCachedMemory); - } - - /// - void IOps.SetModelExecutionsReporter(IModelExecutionsReporter executionsReporter) - { - m_Ops1.SetModelExecutionsReporter(executionsReporter); - m_Ops2.SetModelExecutionsReporter(null); - } - - /// - IModelExecutionsReporter IOps.GetModelExecutionsReporter() - { - return m_Ops1.GetModelExecutionsReporter(); - } - - private void CheckSame(Tensor X, Tensor Y, Layer.Type layerType, params Tensor[] inputs) - { - CompareOpsUtils.CheckSame(X, Y, layerType, m_DifferenceLogLevel, m_Epsilon, inputs); - } - - private void CheckSame(Tensor X, Tensor Y, string opName, params Tensor[] inputs) - { - CompareOpsUtils.CheckSame(X, Y, opName, m_DifferenceLogLevel, m_Epsilon, inputs); - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOps.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOps.cs.meta deleted file mode 100644 index c28cf09..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOps.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 3d3848101f7774555899e75a86641621 -timeCreated: 1506427659 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOpsUtils.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOpsUtils.cs deleted file mode 100644 index 35203b5..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOpsUtils.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace Unity.Barracuda { - - /// - /// `CompareOps` utilities - /// -public class CompareOpsUtils -{ - /// - /// `CompareOps` log level enum - /// - public enum LogLevel - { - /// - /// Warning - /// - Warning, - - /// - /// Error - /// - Error - } - - static internal void CheckSame(Tensor X, Tensor Y, Layer.Type type, LogLevel logLevel, float epsilon=0.0001f, params Tensor[] inputs) - { - CheckSame(X, Y, type.ToString(), logLevel, epsilon, inputs); - } - - static internal void CheckSame(Tensor X, Tensor Y, string opName, LogLevel logLevel, float epsilon=0.0001f, params Tensor[] inputs) - { - if (!X.Approximately(Y, epsilon)) - { - if (logLevel == LogLevel.Error) - { - string mainLogMessage = $"Tensors not equal after {opName}, epsilon {epsilon}"; - D.LogError(mainLogMessage); - } - else - { - string mainLogMessage = $"Tensors not equal after {opName} max error: {X.MaxDifference(Y)}"; - D.LogWarning(mainLogMessage); - - D.Log("First: " + X.shape); - D.Log("Second:" + Y.shape); - - X.PrintDataPart(X.channels * X.width * 2); - Y.PrintDataPart(Y.channels * Y.width * 2); - - for (var i = 0; i < inputs.Length; i++) - { - inputs[i].PrintDataPart(32, "input_" + i); - } - } - - - } - if (X.tensorOnDevice != Y.tensorOnDevice) - Y.Dispose(); - } - - static internal bool CheckApproximately(Tensor X, Tensor Y, int count, float epsilon, Layer.Type type, LogLevel logLevel) - { - return CheckApproximately(X, Y, count, epsilon, type.ToString(), logLevel); - } - - static internal bool CheckApproximately(Tensor X, Tensor Y, int count, float epsilon, string opName, LogLevel logLevel) - { - if (!X.Approximately(Y, epsilon, count)) - { - string mainLogMessage = $"Tensors not equal after {opName}"; - if (logLevel == LogLevel.Error) - D.LogError(mainLogMessage); - else - D.LogWarning(mainLogMessage); - - D.Log("First: " + X.shape); - D.Log("Second:" + Y.shape); - - if (count < 0) - count = X.channels * X.width * 2; - X.PrintDataPart(count); - Y.PrintDataPart(count); - return false; - } - if (X.tensorOnDevice != Y.tensorOnDevice) - Y.Dispose(); - - return true; - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOpsUtils.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOpsUtils.cs.meta deleted file mode 100644 index 8e63adf..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/CompareOpsUtils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5e3e5424b979b5c43997409257895b6b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeInfo.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeInfo.cs deleted file mode 100644 index cdf1242..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeInfo.cs +++ /dev/null @@ -1,132 +0,0 @@ -using UnityEngine; -using UnityEngine.Rendering; - -namespace Unity.Barracuda -{ - /// - /// GPU compute info - /// - public class ComputeInfo - { - /// - /// Channel order enum - /// - public enum ChannelsOrder - { - /// - /// Channels last - /// - NHWC, - - /// - /// Channels first - /// - NCHW - } - - /// - /// GPU supports shared memory - /// - public static bool supportsComputeSharedMemory = true; - - /// - /// GPU supports Dense 32x32 kernels - /// - public static bool supportsDense32x32 = true; - - /// - /// GPU supports Dense 64x64 kernels - /// - public static bool supportsDense64x64 = true; - - /// - /// GPU supports compute - /// - public static bool supportsCompute = true; - - /// - /// Max compute work group size supported by GPU - /// - public static uint maxComputeWorkGroupSize = 1024; - - /// - /// GPU vendor - /// - public static string graphicsDeviceVendor = ""; - - /// - /// Helper for hardware selection - /// - public static bool IsMobileGPU() { return - (Application.platform == RuntimePlatform.Android) || - (Application.platform == RuntimePlatform.IPhonePlayer) || - graphicsDeviceVendor.Contains("Intel"); - } - public static bool IsiPhoneGPU() { return - (Application.platform == RuntimePlatform.IPhonePlayer); - } - public static bool IsQualcommGPU() { return - (Application.platform == RuntimePlatform.Android) && graphicsDeviceVendor.Contains("Qualcomm"); - } - public static bool IsARMGPU() { return - (Application.platform == RuntimePlatform.Android) && graphicsDeviceVendor.Contains("ARM"); - } - - /// - /// EXPERIMENTAL: Select Channel order of the compute backends. - /// Production code should stick to default (NHWC) for now. - /// - public static ChannelsOrder channelsOrder = ChannelsOrder.NHWC; - - /// - /// Static constructor, initializes and caches data - /// - static ComputeInfo() - { - string[] args = System.Environment.GetCommandLineArgs (); - for (int i = 0; i < args.Length; i++) { - if (args [i] == "-barracuda-compute-use-nchw") - { - channelsOrder = ChannelsOrder.NCHW; - } - } - - supportsCompute = SystemInfo.supportsComputeShaders; - - graphicsDeviceVendor = SystemInfo.graphicsDeviceVendor; - - // TODO switch to SystemInfo.maxComputeWorkGroupSize when we bump min spec to 2019.3 - if (Application.platform == RuntimePlatform.Android) - { - maxComputeWorkGroupSize = (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Vulkan) ? 256u : 128u; - - var gpuName = SystemInfo.graphicsDeviceName ?? ""; - var osName = SystemInfo.operatingSystem ?? ""; - - // Known issue with Adreno Vulkan drivers on Android 8.x - if (gpuName.Contains("Adreno") && osName.StartsWith("Android OS 8") && - SystemInfo.graphicsDeviceType == GraphicsDeviceType.Vulkan) - maxComputeWorkGroupSize = 128u; - } - else if (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.tvOS) - { - var gpuName = SystemInfo.graphicsDeviceName; - if (gpuName != null && gpuName.StartsWith("Apple A")) - { - int gpuNumber = 0, idx = "Apple A".Length; - while (idx < gpuName.Length && '0' <= gpuName[idx] && gpuName[idx] <= '9') - { - gpuNumber = gpuNumber * 10 + gpuName[idx++] - '0'; - } - - // TODO check on lower end iOS devices - maxComputeWorkGroupSize = (gpuNumber <= 10) ? 224u : 256u; - } - else - { - maxComputeWorkGroupSize = 256u; - } - } - } -} -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeInfo.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeInfo.cs.meta deleted file mode 100644 index 5dd78e1..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeInfo.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 96aee99fc4154e2a991ac0edd6056c2b -timeCreated: 1558541124 \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeShaderSingleton.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeShaderSingleton.cs deleted file mode 100644 index d5a7ec6..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeShaderSingleton.cs +++ /dev/null @@ -1,404 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Profiling; - -namespace Unity.Barracuda -{ - - internal enum ComputeShaderContext - { - Reference, - Optimized - } - - /// - /// Stores compute kernel cache for GPU compute backends - /// - public sealed class ComputeShaderSingleton - { - /// - /// Enable kernel usage tracking - /// - public bool EnableDebug = false; - - private static readonly ComputeShaderSingleton instance = new ComputeShaderSingleton (); - - // Maps kernel name -> shader name - private Dictionary mKernelToShaderName = new Dictionary(); - - // Maps shader name -> ComputeShader - private Dictionary mShaderNameToComputeShader = new Dictionary(); - - private HashSet mUsedOptimizedKernels = new HashSet(); - private HashSet mUsedReferenceKernels = new HashSet(); - - private ComputeShaderSingleton() - { - RegisterKernels("Barracuda/TextureUtils", - new[] {"TextureToTensor", "TensorToTextureNoLUT", "TensorToTexture3DLUT"}); - - RegisterKernels("Barracuda/ActivationA", - new[] - { - "Relu_Flat", "Relu_FlatStrict", "Relu_Loop", "Relu6_Flat", "Relu6_FlatStrict", "Relu6_Loop", - "Tanh_Flat", "Tanh_FlatStrict", "Tanh_Loop", "Swish_Flat", "Swish_FlatStrict", "Swish_Loop", - "Sigmoid_Flat", "Sigmoid_FlatStrict", "Sigmoid_Loop", "LeakyRelu_Flat", "LeakyRelu_FlatStrict", - "LeakyRelu_Loop", "Clip_Flat", "Clip_FlatStrict", "Clip_Loop", "PRelu_Flat", "PRelu_Loop" - }); - - RegisterKernels("Barracuda/ActivationB", - new[] - { - "Reciprocal_Flat", "Reciprocal_FlatStrict", "Reciprocal_Loop", "Sqrt_Flat", "Sqrt_FlatStrict", - "Sqrt_Loop", "HardSigmoid_Flat", "HardSigmoid_FlatStrict", "HardSigmoid_Loop" - }); - - RegisterKernels("Barracuda/ActivationBase", - new string[] - { - "Abs_Flat", "Abs_FlatStrict", "Abs_Loop", "Neg_Flat", "Neg_FlatStrict", "Neg_Loop", "Ceil_Flat", - "Ceil_FlatStrict", "Ceil_Loop", "Floor_Flat", "Floor_FlatStrict", "Floor_Loop", - "Round_Flat", "Round_FlatStrict", "Round_Loop", "Selu_Flat", - "Selu_FlatStrict", "Selu_Loop", "Softplus_Flat", "Softplus_FlatStrict", "Softplus_Loop", "Elu_Flat", - "Elu_FlatStrict", "Elu_Loop", "Exp_Flat", "Exp_FlatStrict", "Exp_Loop", "Log_Flat", - "Log_FlatStrict", "Log_Loop", "Pow_Flat", "Pow_FlatStrict", "Pow_Loop", "LogicalNot_Flat", - "LogicalNot_FlatStrict", "LogicalNot_Loop", "Sign_Flat", "Sign_FlatStrict", "Sign_Loop", - "Acos_Flat", "Acos_FlatStrict", "Acos_Loop", - "Acosh_Flat", "Acosh_FlatStrict", "Acosh_Loop", "Asin_Flat", "Asin_FlatStrict", "Asin_Loop", - "Asinh_Flat", "Asinh_FlatStrict", "Asinh_Loop", "Atan_Flat", "Atan_FlatStrict", "Atan_Loop", - "Atanh_Flat", "Atanh_FlatStrict", "Atanh_Loop", "Cos_Flat", "Cos_FlatStrict", "Cos_Loop", - "Cosh_Flat", "Cosh_FlatStrict", "Cosh_Loop", "Sin_Flat", "Sin_FlatStrict", "Sin_Loop", "Sinh_Flat", - "Sinh_FlatStrict", "Sinh_Loop", "Tan_Flat", "Tan_FlatStrict", "Tan_Loop", "Erf_Flat", "Erf_FlatStrict", "Erf_Loop", - "Relu_NHWC", "Relu_NCHW", "Relu_CNyx_NHWC", "Relu_Nyxc_NHWC", "Relu6_NHWC", "Relu6_NCHW", "Relu6_CNyx_NHWC", - "Relu6_Nyxc_NHWC", "PRelu_NHWC", "PRelu_NCHW", "PRelu_CNyx2_NHWC", "Selu_NHWC", "Selu_NCHW", - "Selu_CNyx_NHWC", "Selu_Nyxc_NHWC", "Tanh_NHWC", "Tanh_NCHW", "Tanh_CNyx_NHWC", "Tanh_Nyxc_NHWC", - "Swish_NHWC", "Swish_NCHW", "Swish_CNyx_NHWC", "Swish_Nyxc_NHWC", "Softplus_NHWC", "Softplus_NCHW", - "Softplus_CNyx_NHWC", "Softplus_Nyxc_NHWC", "Sigmoid_NHWC", "Sigmoid_NCHW", "Sigmoid_CNyx_NHWC", - "Sigmoid_Nyxc_NHWC", "HardSigmoid_NHWC", "HardSigmoid_NCHW", "HardSigmoid_CNyx_NHWC", "HardSigmoid_Nyxc_NHWC", - "Elu_NHWC", "Elu_NCHW", "Elu_CNyx_NHWC", "Elu_Nyxc_NHWC", "LeakyRelu_NHWC", - "LeakyRelu_NCHW", "LeakyRelu_CNyx_NHWC", "LeakyRelu_Nyxc_NHWC", "Exp_NHWC", "Exp_NCHW", - "Exp_CNyx_NHWC", "Exp_Nyxc_NHWC", "Log_NHWC", "Log_NCHW", "Log_CNyx_NHWC", "Log_Nyxc_NHWC", - "Sqrt_NHWC", "Sqrt_NCHW", "Sqrt_CNyx_NHWC", "Sqrt_Nyxc_NHWC", "Pow_NHWC", "Pow_NCHW", - "Pow_CNyx_NHWC", "Pow_Nyxc_NHWC", - "Clip_NHWC", "Clip_NCHW", "Clip_CNyx_NHWC", "Clip_Nyxc_NHWC", "Acos_NHWC", - "Acos_NCHW", "Acos_CNyx_NHWC", "Acos_Nyxc_NHWC", "Acosh_NHWC", "Acosh_NCHW", "Acosh_CNyx_NHWC", - "Acosh_Nyxc_NHWC", "Asin_NHWC", "Asin_NCHW", "Asin_CNyx_NHWC", "Asin_Nyxc_NHWC", "Asinh_NHWC", - "Asinh_NCHW", "Asinh_CNyx_NHWC", "Asinh_Nyxc_NHWC", "Atan_NHWC", "Atan_NCHW", "Atan_CNyx_NHWC", - "Atan_Nyxc_NHWC", "Atanh_NHWC", "Atanh_NCHW", "Atanh_CNyx_NHWC", "Atanh_Nyxc_NHWC", "Cos_NHWC", - "Cos_NCHW", "Cos_CNyx_NHWC", "Cos_Nyxc_NHWC", "Cosh_NHWC", "Cosh_NCHW", "Cosh_CNyx_NHWC", - "Cosh_Nyxc_NHWC", "Sin_NHWC", "Sin_NCHW", "Sin_CNyx_NHWC", "Sin_Nyxc_NHWC", "Sinh_NHWC", - "Sinh_NCHW", "Sinh_CNyx_NHWC", "Sinh_Nyxc_NHWC", "Tan_NHWC", "Tan_NCHW", "Tan_CNyx_NHWC", - "Tan_Nyxc_NHWC", "Erf_NHWC", "Erf_NCHW", "Erf_CNyx_NHWC", "Erf_Nyxc_NHWC" - }); - - RegisterKernels("Barracuda/Broadcast_NHWC", - new[] - { - "BroadcastAdd_NHWC", "BroadcastSub_NHWC", "BroadcastMul_NHWC", "BroadcastDiv_NHWC", - "BroadcastPow_NHWC", "BroadcastMin_NHWC", "BroadcastMax_NHWC", "BroadcastMean_NHWC", - "BroadcastGreater_NHWC", "BroadcastGreaterEqual_NHWC", "BroadcastLess_NHWC", - "BroadcastLessEqual_NHWC", "BroadcastEqual_NHWC", "BroadcastLogicalOr_NHWC", - "BroadcastLogicalAnd_NHWC", "BroadcastLogicalXor_NHWC", "BroadcastWhere_NHWC", - "BroadcastDivExpSub_NHWC", "LogSoftmaxEnd_NHWC" - }); - - RegisterKernels("Barracuda/Broadcast_NCHW", - new[] - { - "BroadcastAdd_NCHW", "BroadcastSub_NCHW", "BroadcastMul_NCHW", "BroadcastDiv_NCHW", - "BroadcastPow_NCHW", "BroadcastMin_NCHW", "BroadcastMax_NCHW", "BroadcastMean_NCHW", - "BroadcastGreater_NCHW", "BroadcastGreaterEqual_NCHW", "BroadcastLess_NCHW", - "BroadcastLessEqual_NCHW", "BroadcastEqual_NCHW", "BroadcastLogicalOr_NCHW", - "BroadcastLogicalAnd_NCHW", "BroadcastLogicalXor_NCHW", "BroadcastWhere_NCHW", - "BroadcastDivExpSub_NCHW", "LogSoftmaxEnd_NCHW" - }); - - RegisterKernels("Barracuda/Conv2dA_NHWC", - new[] - { - "Conv2D_NHWC", "Conv2D_RegisterBlock4x2_NHWC", "DepthwiseConv2D_NHWC", - "Conv2DKernelKxK_StrictC16K64_T16x16_R4x4_NHWC", "Conv2DKernelKxK_T16x16_R4x4_NHWC", - "Conv2DKernel1x1_StrictC16K64_T16x16_R4x4_NHWC" - }); - - RegisterKernels("Barracuda/Conv2dA_NCHW", - new[] - { - "Conv2D_NCHW", "Conv2D_RegisterBlock4x2_NCHW", "DepthwiseConv2D_NCHW", - "Conv2DKernelKxK_StrictC16K64_T16x16_R4x4_NCHW", "Conv2DKernelKxK_T16x16_R4x4_NCHW", - "Conv2DKernel1x1_StrictC16K64_T16x16_R4x4_NCHW" - }); - - RegisterKernels("Barracuda/Conv2dBase", - new[] - { - "Conv2DKernelKxK_StrictC16StrictK64_T8x8_R8x8_NHWC", - "Conv2DKernelKxK_StrictC16StrictK64_T8x8_R8x8_NCHW", - "Conv2DKernelKxK_StrictC16LaxK64_T8x8_R8x8_NHWC", "Conv2DKernelKxK_StrictC16LaxK64_T8x8_R8x8_NCHW", - "Conv2DKernelKxK_StrictC4StrictK16_T2x32_R8x8_NHWC", - "Conv2DKernelKxK_StrictC4StrictK16_T2x32_R8x8_NCHW", - "Conv2DKernelKxK_LaxC4StrictK16_T2x32_R8x8_NHWC", "Conv2DKernelKxK_LaxC4StrictK16_T2x32_R8x8_NCHW", - "Conv2DKernelKxK_StrictC4LaxK16_T2x32_R8x8_NHWC", "Conv2DKernelKxK_StrictC4LaxK16_T2x32_R8x8_NCHW", - "Conv2DTrans_NHWC", "Conv2DTrans_NCHW", "Conv2DTrans_KernelCached_K5x5_T16x16_NHWC", - "Conv2DTrans_KernelCached_K5x5_T16x16_NCHW", "Conv2DTransFlipKernel", "Conv2DTransPadFill_NHWC", - "Conv2DTransPadFill_NCHW", "KernelWinograd_3x3", - "Conv2DWinograd_2x2_Kernel3x3_StrictC8StrictK16_T16x16_R4x4_NCHW", - "Conv2DWinograd_2x2_Kernel3x3_StrictC8LaxK16_T16x16_R4x4_NCHW" - }); - RegisterKernels("Barracuda/Conv2dMobile", - new[] - { - //"Conv2D_Default_T8x8_R4x4_NHWC", - //"Conv2D_Default_T8x8_R4x4_NHWC", - "Conv2D_Winograd_2x2_Kernel3x3_LDS_NHWC", - "Conv2D_Winograd_2x2_Kernel3x3_LDS_NHWC", - //"Conv2D_Winograd_2x2_Kernel3x3_NHWC", - //"Conv2D_Winograd_2x2_Kernel3x3_NHWC", - //"Conv2D_Kernel1x1_1x4x4_NHWC", - //"Conv2D_Kernel1x1_1x4x4_NCHW", - "Conv2D_KernelKxK_T16x16_R4x4_NHWC", - "Conv2D_KernelKxK_T16x16_R4x4_NCHW", - "Conv2D_Kernel1x1_T16x16_R4x4_NHWC", - "Conv2D_Kernel1x1_T16x16_R4x4_NCHW", - "Conv2D_KernelKxK_T8x8_R4x4_NHWC", - "Conv2D_KernelKxK_T8x8_R4x4_NCHW", - "Conv2D_Kernel1x1_T8x8_R4x4_NHWC", - "Conv2D_Kernel1x1_T8x8_R4x4_NCHW", - "DepthwiseConv2D_Default_NHWC", - "DepthwiseConv2D_Default_NCHW", - "DepthwiseConv2D_Winograd_2x2_Kernel3x3_NHWC", - "DepthwiseConv2D_Winograd_2x2_Kernel3x3_NCHW", - //"DepthwiseConv2D_Winograd_2x2_Kernel5x5_NHWC", - //"DepthwiseConv2D_Winograd_2x2_Kernel5x5_NCHW", - //"KernelWinograd_5x5" - }); - - RegisterKernels("Barracuda/Conv3d", - new[] - { - "Conv3D_NHWC", "Conv3D_NCHW", "Conv3DKernelKxK_LaxC8LaxK32_T8x16_R4x4_NHWC", - "Conv3DKernelKxK_LaxC8LaxK32_T8x16_R4x4_NCHW", "Conv3DKernelKxK_StrictC8LaxK32_T8x16_R4x4_NHWC", - "Conv3DKernelKxK_StrictC8LaxK32_T8x16_R4x4_NCHW", - "Conv3DKernelKxK_StrictC8StrictK32_T8x16_R4x4_NHWC", - "Conv3DKernelKxK_StrictC8StrictK32_T8x16_R4x4_NCHW" - }); - - RegisterKernels("Barracuda/Dense", - new[] - { - "Dense_L1Cached64", "DenseTiled16x16", "DenseTiled32x32", "DenseTiled64x64", "Dense_T8x8_R4x4", - "Dense_T16x16_R4x4", "Dense_Tilled2x2_Cached", "Dense_Tilled4x4_Cached", "MatMulPackB0Bias", - "Dense_V_L1Cached64" - }); - - RegisterKernels("Barracuda/MatMul", - new[] - { - "MultidimMatMul_T16x16_R4x4_AR3_BR2_NHWC", "MultidimMatMul_T16x16_R4x4_AR3_BR2_NCHW", - "MultidimMatMul_T8x8_R8x8_AR3_BR2_NHWC", "MultidimMatMul_T8x8_R8x8_AR3_BR2_NCHW", - "MultidimMatMul_L1Cached64_AR3_BR2_NHWC", "MultidimMatMul_L1Cached64_AR3_BR2_NCHW" - }); - - RegisterKernels("Barracuda/Dense3", - new[] - { - "Dense3_T8x8_R8x8_NHWC", "Dense3_T8x8_R8x8_NCHW", - "Dense3_T8x16_R4x4_NHWC", "Dense3_T8x16_R4x4_NCHW", - "Dense3_L1Cached64_NHWC", "Dense3_L1Cached64_NCHW" - }); - - RegisterKernels("Barracuda/Generic", - new[] - { - "ScaleBias_NHWC", "ScaleBias_NCHW", "ScaleBias_CNyx_NHWC", "ScaleBias_CNyx2_NHWC", - "ScaleBias_Flat_NHWC", "ScaleBias_Flat_NCHW", "ScaleBias_Loop_NHWC", "ScaleBias_Loop_NCHW", - "InstanceNormTail_CNyx2_NHWC", "InstanceNormTail_Flat_NHWC", "InstanceNormTail_Flat_NCHW", - "InstanceNormTail_Loop_NHWC", "InstanceNormTail_Loop_NCHW", "Upsample2D_NHWC", "Upsample2D_NCHW", - "UpsampleBilinear2D_NHWC", "UpsampleBilinear2D_NCHW", "UpsampleBilinear2D_2x2_NHWC", - "UpsampleBilinear2D_2x2_NCHW", "Copy_NHWC", "Copy_NCHW", "ReshapeFromNHWCModel_Flat_NCHW", - "ReshapeFromNHWCModel_Loop_NCHW", "TransposeToChannelFirst" - }); - - RegisterKernels("Barracuda/Pad", - new[] - { - "Border2D_NHWC", "Border2D_NCHW", "Pad2DEdge_NHWC", "Pad2DEdge_NCHW", "Pad2DReflect_NHWC", - "Pad2DReflect_NCHW", "Pad2DSymmetric_NHWC", "Pad2DSymmetric_NCHW" - }); - - RegisterKernels("Barracuda/Transpose", - new[] - { - "Transpose2D_NHWC","Transpose2D_NCHW","Transpose_NHWC","Transpose_NCHW","Transpose8D" - }); - - RegisterKernels("Barracuda/Pool_NHWC", - new[] - { - "AvgPool2D_NHWC", "MaxPool2D_NHWC", "AvgPool2DReduce_NHWC", "MaxPool2DReduce_NHWC", - "GlobalAvgPool2D_NHWC", "GlobalMaxPool2D_NHWC", "AvgVariancePool2DReduce_NHWC", - "GlobalAvgVariancePool2D_NHWC" - }); - - RegisterKernels("Barracuda/Pool_NCHW", - new[] - { - "AvgPool2D_NCHW", "MaxPool2D_NCHW", "AvgPool2DReduce_NCHW", "MaxPool2DReduce_NCHW", - "GlobalAvgPool2D_NCHW", "GlobalMaxPool2D_NCHW", "AvgVariancePool2DReduce_NCHW", - "GlobalAvgVariancePool2D_NCHW" - }); - - RegisterKernels("Barracuda/Reduce", - new[] - { - "PartialReduceMin", "PartialReduceMin_Loop", - "GlobalReduceMin", "GlobalReduceMin_Loop", - - "PartialReduceMax", "PartialReduceMax_Loop", - "GlobalReduceMax", "GlobalReduceMax_Loop", - - "PartialReduceSum", "PartialReduceSum_Loop", - "GlobalReduceSum", "GlobalReduceSum_Loop", - - "PartialReduceMean", "PartialReduceMean_Loop", - "GlobalReduceMean", "GlobalReduceMean_Loop", - - "PartialReduceProd", "PartialReduceProd_Loop", - "GlobalReduceProd", "GlobalReduceProd_Loop", - - "PartialReduceExpBias", "PartialReduceExpBias_Loop", - "GlobalReduceExpBias", "GlobalReduceExpBias_Loop" - }); - RegisterKernels("Barracuda/ReduceSlow", - new[] - { - "ArgMax_NHWC", "ArgMax_NCHW", "ArgMin_NHWC", "ArgMin_NCHW" - }); - } - - private void RegisterKernels(string shaderName, string[] kernels) - { - foreach (var kernel in kernels) - { - mKernelToShaderName[kernel] = shaderName; - } - } - - internal ComputeShader FindComputeShader(ComputeShaderContext ctx, string kernelName) - { - if (ctx == ComputeShaderContext.Optimized) - return FindOptimizedComputeShader(kernelName); - - return FindReferenceComputeShader(kernelName); - } - - private ComputeShader FindReferenceComputeShader(string kernelName) - { - if (EnableDebug) mUsedReferenceKernels.Add(kernelName); - - return FindComputeShader("Barracuda/BarracudaReferenceImpl"); - } - - private ComputeShader FindOptimizedComputeShader(string kernelName) - { - string shaderName = null; - mKernelToShaderName.TryGetValue(kernelName, out shaderName); - - // Kernel not found - if (shaderName == null) - return null; - - if (EnableDebug) mUsedOptimizedKernels.Add(kernelName); - - return FindComputeShader(shaderName); - } - - private ComputeShader FindComputeShader(string shaderName) - { - if (!mShaderNameToComputeShader.ContainsKey(shaderName)) - { - Profiler.BeginSample(shaderName); - mShaderNameToComputeShader[shaderName] = Resources.Load(shaderName); - Profiler.EndSample(); - } - - return mShaderNameToComputeShader[shaderName]; - } - - /// - /// Warmup reference kernels - /// - /// list of kernels to warm up - /// IEnumerator - public IEnumerator WarmupReferenceKernels(List kernels) - { - if (kernels?.Count > 0) - FindComputeShader("Barracuda/BarracudaReferenceImpl"); - - yield break; - } - - /// - /// Warmup optimized kernels - /// - /// list of kernels to warm up - /// IEnumerator - public IEnumerator WarmupOptimizedKernels(List kernels) - { - foreach (var kernel in kernels) - { - var shader = mKernelToShaderName[kernel]; - if (!mShaderNameToComputeShader.ContainsKey(shader)) - { - FindComputeShader(shader); - yield return null; - } - } - yield break; - } - - /// - /// Get used reference kernels list - /// - /// list of kernels - public List GetUsedReferenceKernels() - { - if (!EnableDebug) - { - D.LogWarning("List of used kernels was requested while ComputeShaderSingleton.EnableDebug == false"); - return null; - } - - return mUsedReferenceKernels.ToList(); - } - - /// - /// Get used optimized kernels list - /// - /// list of kernels - public List GetUsedOptimizedKernels() - { - if (!EnableDebug) - { - D.LogWarning("List of used kernels was requested while ComputeShaderSingleton.EnableDebug == false"); - return null; - } - - return mUsedOptimizedKernels.ToList(); - } - - /// - /// Singleton - /// - public static ComputeShaderSingleton Instance { - get { return instance; } - } - - /// - /// Check if GPU compute is supported - /// - public bool supported { get { return SystemInfo.supportsComputeShaders; } } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeShaderSingleton.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeShaderSingleton.cs.meta deleted file mode 100644 index 28eae9f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ComputeShaderSingleton.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 815b6432da283415d87dabe9ef715cd9 -timeCreated: 1495620775 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/GenericWorker.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/GenericWorker.cs deleted file mode 100644 index df1c225..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/GenericWorker.cs +++ /dev/null @@ -1,1881 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; - -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Unity.Barracuda.PerformanceTests")] -[assembly: InternalsVisibleTo("Unity.Barracuda.Tests")] - -namespace Unity.Barracuda -{ - -/// -/// Generic `IWorker` implementation -/// -public class GenericWorker : IWorker -{ - private Model m_Model; - private string m_DefaultInputName; - private string m_DefaultOutputName; - private Dictionary m_InputShapes = new Dictionary(); - private DataType m_ActivationsDataType = DataType.Float; - private IOps m_Ops; - private IVars m_Vars; - private IModelCompiler m_ModelCompiler; - private Tensor m_DummyInput; - - private bool m_AllocatorIsStale = false; - private bool m_AllocatorIsOccupied = false; - private bool m_Verbose; - private bool m_TakeoverWeights; - private float m_Progress = 0f; - - private Tensor m_SyncTensor; - - // Heuristic size for a small tensor. Small tensors are more likely to be accessed on CPU, - // thus PeekOutput() for such small tensor will auto schedule non-blocking download from GPU/NPU to CPU - const int m_MaxBatchThatAutoTriggersAsyncDownload = 64; - const int m_MaxFlatWidthThatAutoTriggersAsyncDownload = 1000; - - /// - /// Create `GenericWorker` for specified `model` and `ops` - /// - /// `Model` - /// `IOps` - /// `IVars` - /// verbose execution flag - /// takeover weights execution flag - public GenericWorker(Model model, IOps ops, IVars vars, bool verbose = false, bool takeoverWeights = false) - { - m_Model = model; - m_DefaultInputName = ModelAnalyzer.GetDefaultInputName(model); - m_DefaultOutputName = ModelAnalyzer.GetDefaultOutputName(model); - m_Ops = ops; - m_Vars = vars; - m_ModelCompiler = ops as IModelCompiler; - m_DummyInput = new Tensor(); - m_Verbose = verbose; - m_TakeoverWeights = takeoverWeights; - - m_AllocatorIsStale = true; - - SetupTensorLeaksTracking(); - } - - private void SetupTensorLeaksTracking() - { - //Reference backends are not targeting optimal memory usage - //and should not be tracked for tensor leaks - - //Note: duplicate test (considering inheritance) for clarity - bool isProductionBackend = - m_Ops is UnsafeArrayCPUOps || m_Ops is BurstCPUOps || - m_Ops is ComputeOps || m_Ops is PrecompiledComputeOps; - - var genericVarsWithPreallocation = m_Vars as GenericVarsWithPreallocation; - if (genericVarsWithPreallocation != null) - { - genericVarsWithPreallocation.ShouldTrackTensorLeaks = isProductionBackend; - } - } - - /// - /// Finalizer - /// - ~GenericWorker() - { - Dispose(); - } - - internal void OccupyAllocator() - { - m_AllocatorIsOccupied = true; - } - - internal void ResetAllocatorIfStale() - { - if (m_AllocatorIsStale) - { - m_Ops.ResetAllocator(); - m_AllocatorIsStale = false; - m_AllocatorIsOccupied = false; - } - } - - internal void ResetAllocatorIfStaleAndNotOccupied() - { - if (!m_AllocatorIsOccupied) - ResetAllocatorIfStale(); - } - - /// - /// Dispose all internal storage structures - /// - public virtual void Dispose() - { - m_Vars?.Dispose(); - m_Ops?.ResetAllocator(false); // clear allocator's memory - m_InputShapes?.Clear(); - m_DummyInput?.Dispose(); - - m_Vars = null; - m_Ops = null; - m_InputShapes = null; - } - - /// - public virtual void PrepareForInput(IDictionary inputShapes, DataType dataType) - { - m_InputShapes.Clear(); - foreach (var input in inputShapes) - m_InputShapes.Add(input.Key, input.Value); - m_ActivationsDataType = dataType;//TODO fp16. for now all activations are expected to share the same data type - m_Vars.PrepareStorage(m_Model, m_Ops, m_InputShapes, m_TakeoverWeights, m_ActivationsDataType); - } - - /// - public virtual void SetInput(string name, Tensor x) - { - ResetAllocatorIfStale(); - OccupyAllocator(); - - m_Ops.Prepare(x); - m_Vars.SetInput(name, x); - - // if single input network, then we have enough information to prepare network for execution - if (m_Model.inputs.Count <= 1 && name == m_DefaultInputName) - { - m_ActivationsDataType = x.dataType; - PrepareForInput(new Dictionary { { name, x.shape } }, m_ActivationsDataType); // @TODO: get rid of allocation - } - - m_InputShapes[name] = x.shape; - } - - /// - public virtual void SetInput(Tensor x) - { - SetInput(m_DefaultInputName, x); - } - - /// - public virtual IWorker Execute(IDictionary inputs) - { - foreach (var entry in inputs) - SetInput(entry.Key, entry.Value); - return Execute(); - } - - /// - public virtual IWorker Execute(Tensor input) - { - SetInput(input); - return Execute(); - } - - /// - public virtual IWorker Execute() - { - Profiler.BeginSample ("Barracuda.Execute"); - var enumerator = StartManualSchedule(); - while (enumerator.MoveNext()) {}; - Profiler.EndSample (); - return this; - } - - /// - public virtual IEnumerator StartManualSchedule(IDictionary inputs) - { - foreach (var entry in inputs) - SetInput(entry.Key, entry.Value); - return StartManualSchedule(); - } - - /// - public virtual void FlushSchedule(bool blocking) - { - // force execution of scheduled ops by requesting results of the intermediate tensor from the device - m_SyncTensor.PrepareCacheForAccess(blocking); - } - - /// - public virtual IEnumerator StartManualSchedule(Tensor input) - { - SetInput(input); - return StartManualSchedule(); - } - - /// - public virtual float scheduleProgress - { - get - { - return m_Progress; - } - } - - private static Layer.FusedActivation GetAndVerifyFusedActivation(Layer l) - { - Assert.IsTrue(ModelOptimizer.IsLayerSupportingActivationFusing(l.type)); - if (!ModelOptimizer.IsActivationFusable(l.activation)) - throw new NotImplementedException("This activation function is not implemented as a fusable one yet! Check Layer.FusedActivation for supported ones."); - - return (Layer.FusedActivation) l.activation; - } - - /// - public virtual IEnumerator StartManualSchedule() - { - ResetAllocatorIfStaleAndNotOccupied(); - m_AllocatorIsStale = true; - -#if ENABLE_BARRACUDA_STATS - m_Ops.GetModelExecutionsReporter()?.ModelExecutionStarted(); - m_Ops.GetModelExecutionsReporter()?.TakeMemorySnapshot(m_Ops, m_Vars, "Before model execution, step1: After Allocator reset"); -#endif //ENABLE_BARRACUDA_STATS - - m_Vars.PrepareStorage(m_Model, m_Ops, m_InputShapes, m_TakeoverWeights, m_ActivationsDataType); - - if (m_ModelCompiler != null) - m_ModelCompiler.PrepareModel(m_Model, m_InputShapes, m_Vars); - -#if ENABLE_BARRACUDA_STATS - m_Ops.GetModelExecutionsReporter()?.TakeMemorySnapshot(m_Ops, m_Vars, "Before model execution, step2: After Model preparation"); -#endif //ENABLE_BARRACUDA_STATS - - int idx = 0; - foreach (var l in m_Model.layers) - { - idx++; - - m_Progress = idx / (float)m_Model.layers.Count; - -#if ENABLE_BARRACUDA_STATS - m_Ops.GetModelExecutionsReporter()?.LayerExecutionStarted(l); -#endif //ENABLE_BARRACUDA_STATS - - Profiler.BeginSample(l.name); - - var inputs = m_Vars.GatherInputs(l); - - Tensor X = inputs.Length > 0 ? inputs[0] : m_DummyInput; - - if (m_Verbose) - D.Log("Layer: " + l.type + ((l.type == Layer.Type.Activation) ? ("." + l.activation) : "") + " " + l.name ); - - m_Vars.PrepareStorage(l); - if (m_ModelCompiler != null) - m_ModelCompiler.PreExecuteLayer(l, inputs); - - // No operation, identity - if (l.type == Layer.Type.Nop) - { - Profiler.BeginSample ("Barracuda.Nop"); - X = m_Ops.Copy(X); - } - // Load const - else if (l.type == Layer.Type.Load) - { - Profiler.BeginSample ("Barracuda.Load"); - } - // GEMM - else if (l.type == Layer.Type.Dense) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample ("Barracuda.Dense"); - X = m_Ops.Dense(X, inputs[1], inputs[2], GetAndVerifyFusedActivation(l)); - } - // GEMM - optimized rank3 path - else if (l.type == Layer.Type.Dense3) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample ("Barracuda.Dense3"); - X = m_Ops.Dense3(X, inputs[1], inputs[2]); - } - // MatMul - else if (l.type == Layer.Type.MatMul) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample ("Barracuda.MatMul"); - - if (l.pool == null || l.pool.Length == 0) - X = m_Ops.MatMul(X, -1, inputs[1], -1); - else - X = m_Ops.MatMul(X, l.pool[0], inputs[1], l.pool[1]); - } - // 2D - else if (l.type == Layer.Type.Conv2D) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample ("Barracuda.Conv2D"); - var pad = X.AdjustPadToKernel(inputs[1], l.stride, l.pad); - X = m_Ops.Conv2D(X, inputs[1], inputs[2], l.stride, pad, GetAndVerifyFusedActivation(l)); - } - else if (l.type == Layer.Type.DepthwiseConv2D) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample ("Barracuda.DepthwiseConv2D"); - var pad = X.AdjustPadToKernel(inputs[1], l.stride, l.pad); - X = m_Ops.DepthwiseConv2D(X, inputs[1], inputs[2], l.stride, pad, GetAndVerifyFusedActivation(l)); - } - else if (l.type == Layer.Type.Conv2DTrans) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample ("Barracuda.Conv2DTrans"); - // pool size is treated as output_adjustment aka output_padding here - var outputAdjustment = l.pool; - var pad = X.AdjustPadToKernel(inputs[1], l.stride, l.pad); - X = m_Ops.Conv2DTrans(X, inputs[1], inputs[2], l.stride, pad, outputAdjustment, GetAndVerifyFusedActivation(l)); - } - else if (l.type == Layer.Type.Upsample2D) - { - Profiler.BeginSample ("Barracuda.Upsample2D"); - // pool size is treated as upsample scale coefficient here - var scale = l.pool; - // axis is treated as upsample point/bilinear flag - var bilinear = l.axis > 0; - if (scale.Length == 0 && inputs.Length > 1) - { - var scaleTensor = inputs[1]; - Assert.AreEqual(scaleTensor.length, 4); - scale = new int[] {(int)scaleTensor[2], (int)scaleTensor[1]}; - } - X = m_Ops.Upsample2D(X, scale, bilinear); - } - else if (l.type == Layer.Type.Resample2D) - { - Profiler.BeginSample("Barracuda.Resample2D"); - // pool size is treated as resample size here - var size = l.pool; - // axis is treated as upsample point/bilinear flag - var bilinear = l.axis > 0; - if (inputs.Length > 1) - { - var sizeTensor = inputs[1]; - Assert.IsTrue(sizeTensor.length == 4 || sizeTensor.length == 8); - if (sizeTensor.length == 4) - size = new int[] {(int)sizeTensor[2], (int)sizeTensor[1]}; - else - size = new int[] {(int)sizeTensor[6], (int)sizeTensor[5]}; - } - X = m_Ops.Resample2D(X, size, bilinear); - } - else if (l.type == Layer.Type.DepthToSpace) - { - Profiler.BeginSample("Barracuda.DepthToSpace"); - // pool size is treated as blocksize - var blocksize = l.pool; - // axis is treated as mode enum - var mode = (Layer.DepthToSpaceMode) l.axis; - X = m_Ops.DepthToSpace(X, blocksize, mode); - } - else if (l.type == Layer.Type.SpaceToDepth) - { - Profiler.BeginSample("Barracuda.SpaceToDepth"); - // pool size is treated as blocksize - var blocksize = l.pool; - X = m_Ops.SpaceToDepth(X, blocksize); - } - else if (l.type == Layer.Type.MaxPool2D) - { - Profiler.BeginSample ("Barracuda.MaxPool2D"); - var pad = X.AdjustPadToPool(l.pool, l.stride, l.pad); - X = m_Ops.MaxPool2D(X, l.pool, l.stride, pad); - } - else if (l.type == Layer.Type.AvgPool2D) - { - Profiler.BeginSample ("Barracuda.AvgPool2D"); - var pad = X.AdjustPadToPool(l.pool, l.stride, l.pad); - X = m_Ops.AvgPool2D(X, l.pool, l.stride, pad); - } - else if (l.type == Layer.Type.GlobalMaxPool2D) - { - Profiler.BeginSample ("Barracuda.GlobalMaxPool2D"); - X = m_Ops.GlobalMaxPool2D(X); - } - else if (l.type == Layer.Type.GlobalAvgPool2D) - { - Profiler.BeginSample ("Barracuda.GlobalAvgPool2D"); - X = m_Ops.GlobalAvgPool2D(X); - } - else if (l.type == Layer.Type.Border3D) - { - Profiler.BeginSample ("Barracuda.Border3D"); - - Assert.IsNotNull(l.pad); - // NOTE: beta is used to retrieve fillin value - // because beta is 0 by default (while alpha is 1 by default) - // 0 value is more inline with zero padding - float fillValue = l.beta; - // legacy support - if (l.pad.Length == 6) - X = m_Ops.Border3D(X, new[] { l.pad[0], l.pad[1], l.pad[2], 0, l.pad[3], l.pad[4], l.pad[5], 0 }, fillValue); - else - X = m_Ops.Border3D(X, l.pad, fillValue); - } - else if (l.type == Layer.Type.Border2D) - { - Profiler.BeginSample ("Barracuda.Border2D"); - - Assert.IsNotNull(l.pad); - // NOTE: beta is used to retrieve filling value - // because beta is 0 by default (while alpha is 1 by default) - // 0 value is more inline with zero padding - float fillValue = l.beta; - - // legacy support - if(l.pad.Length == 4) - X = m_Ops.Border2D(X, new[] { l.pad[0], l.pad[1], 0, l.pad[2], l.pad[3], 0 }, fillValue); - else - X = m_Ops.Border2D(X, l.pad, fillValue); - } - else if (l.type == Layer.Type.Pad2DReflect) - { - Profiler.BeginSample ("Barracuda.Pad2DReflect"); - - Assert.IsNotNull(l.pad); - - // legacy support - if(l.pad.Length == 4) - X = m_Ops.Pad2DReflect(X, new[] { l.pad[0], l.pad[1], 0, l.pad[2], l.pad[3], 0 }); - else - X = m_Ops.Pad2DReflect(X, l.pad); - } - else if (l.type == Layer.Type.Pad2DSymmetric) - { - Profiler.BeginSample ("Barracuda.Pad2DSymmetric"); - - Assert.IsNotNull(l.pad); - - // legacy support - if(l.pad.Length == 4) - X = m_Ops.Pad2DSymmetric(X, new[] { l.pad[0], l.pad[1], 0, l.pad[2], l.pad[3], 0 }); - else - X = m_Ops.Pad2DSymmetric(X, l.pad); - } - else if (l.type == Layer.Type.Pad2DEdge) - { - Profiler.BeginSample ("Barracuda.Pad2DEdge"); - - Assert.IsNotNull(l.pad); - - // legacy support - if(l.pad.Length == 4) - X = m_Ops.Pad2DEdge(X, new[] { l.pad[0], l.pad[1], 0, l.pad[2], l.pad[3], 0 }); - else - X = m_Ops.Pad2DEdge(X, l.pad); - } - // 3D - else if (l.type == Layer.Type.Upsample3D) - { - Profiler.BeginSample ("Barracuda.Upsample3D"); - // pool size is treated as upsample scale coefficient here - var scale = l.pool; - // axis is treated as upsample point/bilinear flag - var trilinear = l.axis > 0; - if (scale.Length == 0 && inputs.Length > 1) - { - var scaleTensor = inputs[1]; - Assert.AreEqual(scaleTensor.length, 5); - scale = new int[] {(int)scaleTensor[3], (int)scaleTensor[2], (int)scaleTensor[1]}; - } - X = m_Ops.Upsample3D(X, scale, trilinear); - } - else if (l.type == Layer.Type.Conv3D) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample ("Barracuda.Conv3D"); - var pad = X.AdjustPadToKernel(inputs[1], l.stride, l.pad); - X = m_Ops.Conv3D(X, inputs[1], inputs[2], l.stride, pad, GetAndVerifyFusedActivation(l)); - } - else if (l.type == Layer.Type.Conv3DTrans || - l.type == Layer.Type.MaxPool3D || - l.type == Layer.Type.AvgPool3D || - l.type == Layer.Type.GlobalMaxPool3D || - l.type == Layer.Type.GlobalAvgPool3D || - l.type == Layer.Type.Border3D) - { - throw new NotImplementedException($"{l.type} operations are not implemented yet!"); - } - else if (l.type == Layer.Type.ScaleBias) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample ("Barracuda.ScaleBias"); - X = m_Ops.ScaleBias(X, inputs[1], inputs[2]); - } - else if (l.type == Layer.Type.Normalization) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample ("Barracuda.Normalization"); - // @TODO: support other types of Normalization at test time. - // Currently supported only pool=1 (InstanceNormalization) - - // NOTE: beta is used to retrieve epsilon value - // because beta is 0 by default (while alpha is 1 by default) - // 0 value is more inline with very small epsilon - var epsilon = l.beta; - if (epsilon == 0) - epsilon = Mathf.Epsilon; // safety check to prevent division by zero - - X = m_Ops.Normalization(X, inputs[1], inputs[2], 1, l.axis, epsilon, GetAndVerifyFusedActivation(l)); - } - else if (l.type == Layer.Type.LRN) - { - Profiler.BeginSample ("Barracuda.LRN"); - - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 1); - int count = l.pool[0]; - float bias = (l.weights.Length > 0) ? l.weights[l.datasets[0].offset + 0] : 1.0f; - X = m_Ops.LRN(X, l.alpha, l.beta, bias, count); - } - // Stochastic layers - else if (l.type == Layer.Type.Dropout) - { - Profiler.BeginSample ("Barracuda.Dropout"); - - X = m_Ops.Dropout(X, l.alpha); - } - else if (l.type == Layer.Type.RandomNormal) - { - Profiler.BeginSample ("Barracuda.RandomNormal"); - - Assert.IsNotNull(l.pool); - // pool size is treated as shape constant, if not empty - // otherwise shape of the previous tensor is used - var shape = X.shape; - if (l.pool.Length > 0) - shape = new TensorShape(l.pool); - - int seed = (l.pad.Length > 0) ? l.pad[0] : 1337; - seed = seed == 0 ? 1337 : seed; - float scale = l.alpha, mean = l.beta; - X = m_Ops.RandomNormal(shape, mean, scale, seed); - } - else if (l.type == Layer.Type.RandomUniform) - { - Profiler.BeginSample ("Barracuda.RandomUniform"); - - Assert.IsNotNull(l.pool); - // pool size is treated as shape constant, if not empty - // otherwise shape of the previous tensor is used - var shape = X.shape; - if (l.pool.Length > 0) - shape = new TensorShape(l.pool); - - int seed = (l.pad.Length > 0) ? l.pad[0] : 1337; - seed = seed == 0 ? 1337 : seed; - float scale = l.alpha, mean = l.beta; - X = m_Ops.RandomUniform(shape, mean, scale, seed); - } - else if (l.type == Layer.Type.Multinomial) - { - Profiler.BeginSample ("Barracuda.Multinomial"); - - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 1); - - int count = l.pool[0]; - int seed = (l.pad.Length > 0) ? l.pad[0] : 1337; - seed = seed == 0 ? 1337 : seed; - X = m_Ops.Multinomial(X, count, seed); - } - else if (l.type == Layer.Type.OneHot) - { - Profiler.BeginSample ("Barracuda.OneHot"); - - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 1); - int depth = l.pool[0]; - float on = l.alpha, off = l.beta; - int inputRank = l.axis; - inputRank = inputRank < 0 ? X.dimensions : inputRank; - X = m_Ops.OneHot(X, depth, on, off, inputRank); - } - else if (l.type == Layer.Type.RoiAlign) - { - Profiler.BeginSample ("Barracuda.RoiAlign"); - - X = m_Ops.RoiAlign(X, inputs[1], inputs[2], l.pool[0], l.pool[1], l.axis, l.alpha); - } - else if (l.type == Layer.Type.TopKIndices) - { - Profiler.BeginSample ("Barracuda.TopKIndices"); - - bool largest = (l.pad[0] == 1); - bool sorted = (l.pad[1] == 1); - - X = m_Ops.TopKIndices(X, (int)inputs[1][0], l.axis, largest, sorted); - } - else if (l.type == Layer.Type.TopKValues) - { - Profiler.BeginSample ("Barracuda.TopKValues"); - - X = m_Ops.TopKValues(X, inputs[1], l.axis); - } - else if (l.type == Layer.Type.NonZero) - { - Profiler.BeginSample ("Barracuda.NonZero"); - - X = m_Ops.NonZero(X); - } - // Broadcast layers - else if (l.type == Layer.Type.Add) - { - Profiler.BeginSample ("Barracuda.Add"); - - X = m_Ops.Add(inputs); - } - else if (l.type == Layer.Type.Sub) - { - Profiler.BeginSample ("Barracuda.Sub"); - - X = m_Ops.Sub(inputs); - } - else if (l.type == Layer.Type.Mul) - { - Profiler.BeginSample ("Barracuda.Mul"); - - X = m_Ops.Mul(inputs); - } - else if (l.type == Layer.Type.Div) - { - Profiler.BeginSample ("Barracuda.Div"); - - X = m_Ops.Div(inputs); - } - else if (l.type == Layer.Type.Pow) - { - Profiler.BeginSample ("Barracuda.Pow"); - - X = m_Ops.Pow(inputs); - } - else if (l.type == Layer.Type.Min) - { - Profiler.BeginSample ("Barracuda.Min"); - - X = m_Ops.Min(inputs); - } - else if (l.type == Layer.Type.Max) - { - Profiler.BeginSample ("Barracuda.Max"); - - X = m_Ops.Max(inputs); - } - else if (l.type == Layer.Type.Mean) - { - Profiler.BeginSample ("Barracuda.Mean"); - - X = m_Ops.Mean(inputs); - } - // Reduction layers - else if (l.type == Layer.Type.ReduceMax || - l.type == Layer.Type.ReduceMean || - l.type == Layer.Type.ReduceMin || - l.type == Layer.Type.ReduceProd || - l.type == Layer.Type.ReduceSum || - l.type == Layer.Type.ArgMax || - l.type == Layer.Type.ArgMin) - { - Profiler.BeginSample ("Barracuda.Reduce"); - switch (l.type) - { - case Layer.Type.ReduceMax: - X = m_Ops.ReduceMax(X, l.axis); - break; - case Layer.Type.ReduceMean: - X = m_Ops.ReduceMean(X, l.axis); - break; - case Layer.Type.ReduceMin: - X = m_Ops.ReduceMin(X, l.axis); - break; - case Layer.Type.ReduceProd: - X = m_Ops.ReduceProd(X, l.axis); - break; - case Layer.Type.ReduceSum: - X = m_Ops.ReduceSum(X, l.axis); - break; - case Layer.Type.ArgMax: - X = m_Ops.ArgMax(X, l.axis); - break; - case Layer.Type.ArgMin: - X = m_Ops.ArgMin(X, l.axis); - break; - } - } - else if ( - l.type == Layer.Type.ReduceL1 || - l.type == Layer.Type.ReduceL2 || - l.type == Layer.Type.ReduceLogSum || - l.type == Layer.Type.ReduceLogSumExp || - l.type == Layer.Type.ReduceSumSquare) - { - throw new NotImplementedException("This reduction operation is not implemented yet!"); - } - // Logical operators with broadcast - else if (l.type == Layer.Type.Greater) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample ("Barracuda.Greater"); - X = m_Ops.Greater(X, inputs[1]); - } - else if (l.type == Layer.Type.GreaterEqual) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample("Barracuda.GreaterEqual"); - X = m_Ops.GreaterEqual(X, inputs[1]); - } - else if (l.type == Layer.Type.Less) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample("Barracuda.Less"); - X = m_Ops.Less(X, inputs[1]); - } - else if (l.type == Layer.Type.LessEqual) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample("Barracuda.LessEqual"); - X = m_Ops.LessEqual(X, inputs[1]); - } - else if (l.type == Layer.Type.Equal) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample("Barracuda.Equal"); - X = m_Ops.Equal(X, inputs[1]); - } - else if (l.type == Layer.Type.LogicalOr) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample("Barracuda.LogicalOr"); - X = m_Ops.LogicalOr(X, inputs[1]); - } - else if (l.type == Layer.Type.LogicalAnd) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample("Barracuda.LogicalAnd"); - X = m_Ops.LogicalAnd(X, inputs[1]); - } - else if (l.type == Layer.Type.LogicalXor) - { - Assert.AreEqual(inputs.Length, 2); - Profiler.BeginSample("Barracuda.LogicalXor"); - X = m_Ops.LogicalXor(X, inputs[1]); - } - else if (l.type == Layer.Type.LogicalNot) - { - Profiler.BeginSample("Barracuda.LogicalNot"); - X = m_Ops.LogicalNot(X); - } - else if (l.type == Layer.Type.Sign) - { - Profiler.BeginSample("Barracuda.Sign"); - X = m_Ops.Sign(X); - } - else if (l.type == Layer.Type.Where) - { - Assert.AreEqual(inputs.Length, 3); - Profiler.BeginSample("Barracuda.Where"); - X = m_Ops.Where(X, inputs[1], inputs[2]); - } - // Shape affecting layers - else if (l.type == Layer.Type.Flatten) - { - Profiler.BeginSample ("Barracuda.Flatten"); - X = m_Ops.Flatten(X); - } - else if (l.type == Layer.Type.Reshape) - { - Profiler.BeginSample ("Barracuda.Reshape"); - - // pool is treated as the shape, if not empty - var size = l.pool; - - Assert.IsNotNull(size); - if (size.Length == 0 && inputs.Length > 1) - { - switch (l.axis) - { - // Legacy - use the shape of the input tensor as the shape - case -1: - size = inputs[1].shape.ToArray(); - break; - - // Use the tensor values as the shape - case 1: - Tensor shapeTensor = inputs[1]; - size = new [] { 1, 1, 1, 1 }; - for (var i = 0; i < shapeTensor.length; i++) - { - size[i] = (int)shapeTensor[i]; - } - break; - } - } - - var newShape = X.shape.Reshape(size); - X = m_Ops.Reshape(X, newShape); - } - else if (l.type == Layer.Type.Expand) - { - Profiler.BeginSample("Barracuda.Expand"); - - var shape = l.pool; - if (inputs.Length == 1) - { - // pool size is treated as new shape - Assert.IsNotNull(shape); - Assert.IsTrue(shape.Length == 8 || shape.Length == 4); - - if (shape.Length == 4) - shape = new[] { 1, 1, l.pool[0], 1, 1, l.pool[1], l.pool[2], l.pool[3] }; - } - else - { - // dynamic shape support: shape operations cannot be performed on padded shapes, need to expand it here - var refShape = new float[inputs[1].length]; - Array.Copy(inputs[1].ToReadOnlyArray(), refShape, inputs[1].length); - shape = Compiler.IRShapeInferenceHelper.ShapeInference.OnnxLayoutToBarracudaTensorShape(Array.ConvertAll(refShape, x => (int)x)).ToArray(); - } - - var inputShape = new[] { X.shape.sequenceLength, X.shape.numberOfDirections, X.shape.batch, X.shape.extraDimension, X.shape.depth, X.shape.height, X.shape.width, X.shape.channels }; - var tiledShape = new int[8]; - - for (int i = 0; i < 8; i++) - tiledShape[i] = Mathf.Max(shape[i], inputShape[i]); - - if (Enumerable.SequenceEqual(tiledShape, X.shape.ToArray())) - X = m_Ops.Copy(X); - else - X = m_Ops.Expand(X, new TensorShape(tiledShape)); - } - else if (l.type == Layer.Type.Shape) - { - Profiler.BeginSample("Barracuda.Shape"); - - X = m_Ops.Shape(X, l.axis); - } - else if (l.type == Layer.Type.Transpose) - { - Profiler.BeginSample ("Barracuda.Transpose"); - - var permutations = l.pool; - if (permutations == null) - X = m_Ops.Transpose(X); - else - { - // if transpose does not change internal memory layout, skip - if(ModelAnalyzer.DoesTransposeChangeTensorLayout(X.shape, permutations)) - X = m_Ops.Reshape(X, X.shape.Permute(permutations)); - else - X = m_Ops.Transpose(X, permutations); - } - } - else if (l.type == Layer.Type.Gather) - { - Profiler.BeginSample ("Barracuda.Gather"); - X = m_Ops.Gather(inputs, l.axis); - - // Gather assume flat indices, if indices has a rank > 1, we need to expand the generated tensor - if (l.pool != null && l.pool.Length == 2 && l.pool[1] > 1) - { - int xRank = l.pool[0]; - int indicesRank = l.pool[1]; - var xShape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToList(X.shape, xRank); - var indicesShape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToList(inputs[1].shape, indicesRank); - - int axis = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaAxisToTensor(l.axis, xRank); - xShape.InsertRange(axis, indicesShape); - xShape.RemoveAt(axis + indicesShape.Count); - - X = m_Ops.Reshape(X, new TensorShape(Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaLayoutToTensorShapeLayout(xShape.ToArray()))); - - // rank 2 -> 3 - if (xRank == 2 && xShape.Count == 3) - X = m_Ops.Transpose(X, new int[] {0,1,3,2}); - } - } - else if (l.type == Layer.Type.ScatterND) - { - Profiler.BeginSample ("Barracuda.ScatterND"); - - X = m_Ops.ScatterND(X, inputs[1], inputs[2], (Layer.ScatterNDReductionMode)l.axis); - } - else if (l.type == Layer.Type.NonMaxSuppression) - { - Profiler.BeginSample("Barracuda.NonMaxSuppression"); - - int maxOutputBoxesPerClass = 0; - float iouThreshold = 0f; - float scoreThreshold = 0f; - - if (l.pool.Length > 0) - { - maxOutputBoxesPerClass = l.pool[0]; - iouThreshold = l.alpha; - scoreThreshold = l.beta; - } - else - { - if (inputs.Length > 2) - maxOutputBoxesPerClass = (int)inputs[2][0]; - - if (inputs.Length > 3) - iouThreshold = inputs[3][0]; - - if (inputs.Length > 4) - scoreThreshold = inputs[4][0]; - } - - X = m_Ops.NonMaxSuppression(inputs, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, l.axis); - } - else if (l.type == Layer.Type.LSTM) - { - Profiler.BeginSample("Barracuda.LSTM"); - - bool constantWRB = l.datasets.Length > 0; - - int hidden_index; - int cell_index; - - Tensor[] w, r, wb, rb; - - using (var td = new TensorScope()) - { - TensorScope.F _ = td._; // Shorthand - - if (constantWRB) - { - w = new[] - { - l.DataSetToTensor(0), - l.DataSetToTensor(1), - l.DataSetToTensor(2), - l.DataSetToTensor(3) - }; - - r = new[] - { - l.DataSetToTensor(4), - l.DataSetToTensor(5), - l.DataSetToTensor(6), - l.DataSetToTensor(7) - }; - - wb = new[] - { - l.DataSetToTensor(8), - l.DataSetToTensor(9), - l.DataSetToTensor(10), - l.DataSetToTensor(11) - }; - - rb = new[] - { - l.DataSetToTensor(12), - l.DataSetToTensor(13), - l.DataSetToTensor(14), - l.DataSetToTensor(15) - }; - - hidden_index = 1; - cell_index = 2; - } - else - { - // Barracuda N1WC [num_directions, 4*hidden_size, input_size] -> Barracuda NC [4*hidden_size, input_size] - // (i.e. drop directions since they are unsupported) - Tensor W = _(m_Ops.Transpose(inputs[1], new[] { 2, 0, 1, 3 })); - - // Barracuda N1WC [num_directions, 4*hidden_size, hidden_size] -> Barracuda NC [4*hidden_size, input_size] - // (i.e. drop directions since they are unsupported) - Tensor R = _(m_Ops.Transpose(inputs[2], new[] { 2, 0, 1, 3 })); - Tensor B = inputs[3]; - - OpsUtils.SplitWRBForLSTM(m_Ops, W, R, B, out w, out r, out wb, out rb); - - hidden_index = 4; - cell_index = 5; - } - - // Tag for auto-disposal - for (int i = 0; i < w.Length; i++) - { - _(w[i]); - _(r[i]); - _(wb[i]); - _(rb[i]); - } - - Tensor originalHidden = inputs[hidden_index]; - Tensor originalCell = inputs[cell_index]; - - Tensor[] Y = m_Ops.LSTM(X, w, r, wb, rb, originalHidden, originalCell); - - X = Y[0]; - Tensor hiddenFinal = Y[1]; - Tensor cellFinal = Y[2]; - - // We don't support multiple outputs from layers, so set memories directly, which gets picked - // up by subsequent output layers that load memories - var memories = m_Model.memories; - for (int m = 0; m < memories.Count; m++) - { - Model.Memory memory = memories[m]; - if (l.inputs[hidden_index].Contains(memory.input)) - { - _(originalHidden); - m_Vars.SetInput(memory.input, hiddenFinal); - } - else if (l.inputs[cell_index].Contains(memory.input)) - { - _(originalCell); - m_Vars.SetInput(memory.input, cellFinal); - } - } - } - } - else if (l.type == Layer.Type.Concat) - { - Profiler.BeginSample ("Barracuda.Concat"); - X = m_Ops.Concat(inputs, l.axis); - } - else if (l.type == Layer.Type.StridedSlice) - { - Profiler.BeginSample ("Barracuda.StridedSlice"); - - Assert.IsNotNull(l.pad); - Assert.IsNotNull(l.pool); - Assert.IsNotNull(l.stride); - X = m_Ops.StridedSlice(X, l.pad, l.pool, l.stride); - } - else if (l.type == Layer.Type.Tile) - { - Profiler.BeginSample ("Barracuda.Tile"); - - var size = l.pool; - if (size.Length == 0 && inputs.Length > 1) - { - // dynamic shape support: shape operations cannot be performed on padded shapes, need to expand it here - var inputShape = new float[inputs[1].length]; - Array.Copy(inputs[1].ToReadOnlyArray(), inputShape, inputs[1].length); - size = Compiler.IRShapeInferenceHelper.ShapeInference.OnnxLayoutToBarracudaTensorShape(Array.ConvertAll(inputShape, x => (int)x)).ToArray(); - } - - X = m_Ops.Tile(X, size); - } - else if(l.type == Layer.Type.ConstantOfShape) - { - Profiler.BeginSample ("Barracuda.ConstantOfShape"); - - var size = inputs[0].shape; - if (l.axis != 1) - { - // dynamic shape support: shape operations cannot be performed on padded shapes, need to expand it here - var inputShape = new float[inputs[0].length]; - Array.Copy(inputs[0].ToReadOnlyArray(), inputShape, inputs[0].length); - size = Compiler.IRShapeInferenceHelper.ShapeInference.OnnxLayoutToBarracudaTensorShape(Array.ConvertAll(inputShape, x => (int)x)); - } - - X = m_Ops.ConstantOfShape(size, X.dataType, l.alpha); - } - // Activations - else if (l.type == Layer.Type.Activation) - { - Profiler.BeginSample ("Barracuda.Activation"); - - if (l.activation == Layer.Activation.Relu) - { - X = m_Ops.Relu(X); - } - else if (l.activation == Layer.Activation.Softmax) - { - X = m_Ops.Softmax(X, l.axis); - } - else if (l.activation == Layer.Activation.LogSoftmax) - { - X = m_Ops.LogSoftmax(X, l.axis); - } - else if (l.activation == Layer.Activation.Tanh) - { - X = m_Ops.Tanh(X); - } - else if (l.activation == Layer.Activation.Softplus) - { - X = m_Ops.Softplus(X); - } - else if (l.activation == Layer.Activation.Sigmoid) - { - X = m_Ops.Sigmoid(X); - } - else if (l.activation == Layer.Activation.HardSigmoid) - { - X = m_Ops.HardSigmoid(X, l.alpha, l.beta); - } - else if (l.activation == Layer.Activation.Relu6) - { - X = m_Ops.Relu6(X); - } - else if (l.activation == Layer.Activation.Elu) - { - X = m_Ops.Elu(X, l.alpha); - } - else if (l.activation == Layer.Activation.LeakyRelu) - { - X = m_Ops.LeakyRelu(X, l.alpha); - } - else if (l.activation == Layer.Activation.Selu) - { - X = m_Ops.Selu(X, l.alpha, l.beta); - } - else if (l.activation == Layer.Activation.Swish) - { - X = m_Ops.Swish(X); - } - else if (l.activation == Layer.Activation.PRelu) - { - Assert.AreEqual(inputs.Length, 2); - X = m_Ops.PRelu(X, inputs[1]); - } - else if ( - l.activation == Layer.Activation.Softsign || - l.activation == Layer.Activation.Hardmax) - { - throw new NotImplementedException("This activation function is not implemented yet!"); - } - else if (l.activation == Layer.Activation.Abs) - { - X = m_Ops.Abs(X); - } - else if (l.activation == Layer.Activation.Neg) - { - X = m_Ops.Neg(X); - } - else if (l.activation == Layer.Activation.Ceil) - { - X = m_Ops.Ceil(X); - } - else if (l.activation == Layer.Activation.Clip) - { - X = m_Ops.Clip(X, l.alpha, l.beta); - } - else if (l.activation == Layer.Activation.Floor) - { - X = m_Ops.Floor(X); - } - else if (l.activation == Layer.Activation.Round) - { - X = m_Ops.Round(X); - } - else if (l.activation == Layer.Activation.Reciprocal) - { - X = m_Ops.Reciprocal(X); - } - else if (l.activation == Layer.Activation.Pow) - { - X = m_Ops.Pow(X, l.alpha); - } - else if (l.activation == Layer.Activation.Exp) - { - X = m_Ops.Exp(X); - } - else if (l.activation == Layer.Activation.Log) - { - X = m_Ops.Log(X); - } - else if (l.activation == Layer.Activation.Sqrt) - { - X = m_Ops.Sqrt(X); - } - else if (l.activation == Layer.Activation.Acos) - { - X = m_Ops.Acos(X); - } - else if (l.activation == Layer.Activation.Acosh) - { - X = m_Ops.Acosh(X); - } - else if (l.activation == Layer.Activation.Asin) - { - X = m_Ops.Asin(X); - } - else if (l.activation == Layer.Activation.Asinh) - { - X = m_Ops.Asinh(X); - } - else if (l.activation == Layer.Activation.Atan) - { - X = m_Ops.Atan(X); - } - else if (l.activation == Layer.Activation.Atanh) - { - X = m_Ops.Atanh(X); - } - else if (l.activation == Layer.Activation.Cos) - { - X = m_Ops.Cos(X); - } - else if (l.activation == Layer.Activation.Cosh) - { - X = m_Ops.Cosh(X); - } - else if (l.activation == Layer.Activation.Sin) - { - X = m_Ops.Sin(X); - } - else if (l.activation == Layer.Activation.Sinh) - { - X = m_Ops.Sinh(X); - } - else if (l.activation == Layer.Activation.Tan) - { - X = m_Ops.Tan(X); - } - else if (l.activation == Layer.Activation.Erf) - { - X = m_Ops.Erf(X); - } - else - { - X = m_Ops.Copy(X); - } - } - else - { - Profiler.BeginSample ("Barracuda.NotImplemented"); - Assert.IsTrue(l.type == Layer.Type.Nop, $"Layer type {l.type} not explicitly handled"); - } - -#if ENABLE_BARRACUDA_STATS - m_Ops.GetModelExecutionsReporter()?.TakeMemorySnapshot(m_Ops, m_Vars, "After layer",l); -#endif //ENABLE_BARRACUDA_STATS - m_Vars.DisposeAfterLayer(l); - m_Vars.Store(l, X); - m_SyncTensor = X; - - // optype - Profiler.EndSample(); - - // layer.name - Profiler.EndSample(); -#if ENABLE_BARRACUDA_STATS - m_Ops.GetModelExecutionsReporter()?.LayerExecutionCompleted(); -#endif //ENABLE_BARRACUDA_STATS - - yield return null; - } - - // request ResetAllocator before next Execute() starts - m_AllocatorIsOccupied = false; - - if (m_Verbose) - D.Log(m_Vars.GetAllocator()); -#if ENABLE_BARRACUDA_STATS - m_Ops.GetModelExecutionsReporter()?.ModelExecutionCompleted(); - m_Ops.GetModelExecutionsReporter()?.TakeMemorySnapshot(m_Ops, m_Vars, "After model execution"); -#endif //ENABLE_BARRACUDA_STATS - } - - /// - public virtual Tensor PeekOutput() - { - Profiler.BeginSample("Barracuda.PeekOutput"); - var X = m_Vars.PeekOutput(m_DefaultOutputName); - - if (X.batch <= m_MaxBatchThatAutoTriggersAsyncDownload && - X.flatWidth <= m_MaxFlatWidthThatAutoTriggersAsyncDownload) // tensor is small and most likely will be accessed on CPU, - X.PrepareCacheForAccess(blocking:false); // thus schedule non-blocking download from GPU/NPU to CPU - Profiler.EndSample(); - - return X; - } - - /// - public virtual Tensor PeekOutput(string name) - { - Profiler.BeginSample("Barracuda.PeekOutput"); - var X = m_Vars.PeekOutput(name); - - if (X.batch <= m_MaxBatchThatAutoTriggersAsyncDownload && - X.flatWidth <= m_MaxFlatWidthThatAutoTriggersAsyncDownload) // tensor is small and most likely will be accessed on CPU, - X.PrepareCacheForAccess(blocking:false); // thus schedule non-blocking download from GPU/NPU to CPU - Profiler.EndSample(); - - return X; - } - - /// - public virtual Tensor[] PeekConstants(string layerName) - { - Profiler.BeginSample("Barracuda.PeekConstants"); - return m_Vars.PeekConstants(layerName); - } - - /// - /// Execution summary - /// - /// execution summary - public virtual string Summary() - { - return m_Vars.GetAllocator().ToString() + "\n" + m_Ops.ToString(); - } -} - - -internal class GenericVars : IVars, IVarsStatistics -{ - private Dictionary m_TensorsByName = new Dictionary(); - protected HashSet m_ModelTensors = new HashSet(); - protected Dictionary m_InputTensorsByLayer = new Dictionary(); - private Dictionary m_LayerNameToId = new Dictionary(); - private Dictionary> m_LayerNameToDisposeWhenDone = new Dictionary>(); - private Dictionary m_LayerIdToLayer = new Dictionary(); - protected StringCache m_StringCache = new StringCache(); - - public GenericVars() - { - } - - ~GenericVars() - { - Dispose(); - } - - public virtual void Dispose() - { - foreach (var t in m_ModelTensors) - t.Dispose(); - m_ModelTensors.Clear(); - - // don't dispose input/user-owned tensors - foreach (var ts in m_InputTensorsByLayer.Values) - foreach (var t in ts) - { - if (IsTensorOwnedByInternalAllocator(t)) - t.Dispose(); - } - m_InputTensorsByLayer.Clear(); - - m_LayerNameToId.Clear(); - m_LayerNameToDisposeWhenDone.Clear(); - m_LayerIdToLayer.Clear(); - m_StringCache.Clear(); - - m_Allocator.Dispose(); - } - - private TensorCachingAllocator m_Allocator = new DefaultTensorAllocator(); - public virtual ITensorAllocator GetAllocator() - { - return m_Allocator; - } - - public IEnumerable GetAllocatorsStatistics() - { - yield return m_Allocator; - } - - public IEnumerable GetTensorsStatistics() - { - var tensors = new SortedDictionary(); - foreach (var modelTensor in m_ModelTensors) - { - tensors[modelTensor.uniqueId] = modelTensor; - } - foreach (var inputTensors in m_InputTensorsByLayer) - { - foreach (var inputTensor in inputTensors.Value) - { - tensors[inputTensor.uniqueId] = inputTensor; - } - } - foreach (var tensorByName in m_TensorsByName) - { - tensors[tensorByName.Value.uniqueId] = tensorByName.Value; - } - - foreach (var tensor in tensors) - { - yield return tensor.Value; - } - } - - protected virtual bool IsTensorOwnedByInternalAllocator(Tensor tensor) - { - return tensor.allocator == GetAllocator(); - } - - protected bool ValidateGlobalInputs(Model model, IDictionary inputShapes) - { - bool valid = true; - foreach (var i in model.inputs) - { - if (m_TensorsByName.ContainsKey(i.name) || - (inputShapes != null && inputShapes.ContainsKey(i.name))) - continue; - - D.LogWarning("Global input is missing: " + i.name); - valid = false; - } - return valid; - } - - protected virtual Tensor[] PrepareLayerInputTensors(Model model, Layer layer, IOps ops) - { - int tensorIndex = 0; - var tensors = new Tensor[layer.inputs.Length + layer.datasets.Length]; - - foreach (var name in layer.inputs) - { - tensors[tensorIndex++] = new Tensor(1, 1, 1, 1, m_StringCache.Lookup(layer.name, "_dummy_in", tensorIndex)); - } - foreach (var arg in layer.datasets) - { - var tensor = new Tensor(arg.shape, new SharedArrayTensorData(layer.weights, arg.shape, (int)arg.offset), arg.name); - if (ops != null) - tensor = ops.Prepare(tensor); - m_ModelTensors.Add(tensor); - tensors[tensorIndex++] = tensor; - } - return tensors; - } - - public virtual void SetInput(string name, Tensor x) - { - m_TensorsByName[name] = x; - } - - public virtual void PrepareStorage(Model model, IOps ops, IDictionary inputShapes, bool takeoverWeights, DataType dataType) - { - ValidateGlobalInputs(model, inputShapes); - - m_LayerNameToId.Clear(); - m_LayerNameToDisposeWhenDone.Clear(); - m_LayerIdToLayer.Clear(); - - for (var i = 0; i < model.layers.Count; i++) - { - var layer = model.layers[i]; - - // prepare input placeholders and argument tensors only once per layer - if (m_InputTensorsByLayer.ContainsKey(layer)) - continue; - - var tensors = PrepareLayerInputTensors(model, layer, ops); - m_InputTensorsByLayer.Add(layer, tensors); - if (takeoverWeights) - layer.weights = null; - } - - foreach (var mem in model.memories) - { - if (!m_TensorsByName.ContainsKey(mem.input)) - { - // initialize memories that haven't been explicitly set - var tensor = m_Allocator.Alloc(mem.shape, AllocScope.LayerOutput, dataType); - SetInput(mem.input, tensor); - m_ModelTensors.Add(tensor); - } - } - - // For each layer we find the latest downstream layer that has said layer as input - // ex: - // 0 -> 1 -> 4 -> 5 -> 8 - // -> 2 -> 3 / | - // -> 7 ------------/ - // latestDownstreamLayer: - // 0 -> 7, 1 -> 4, 2 -> 3, 4 -> 5, 5 -> 8, 7 -> 8 - Dictionary latestDownstreamLayer = new Dictionary(); - for (var i = 0; i < model.layers.Count; i++) - { - var forLayer = model.layers[i]; - m_LayerNameToId[forLayer.name] = i; - m_LayerIdToLayer[i] = forLayer; - - for (int j = 0; j < forLayer.inputs.Length; j++) - { - string input = forLayer.inputs[j]; - if (latestDownstreamLayer.ContainsKey(input)) - latestDownstreamLayer[input] = Math.Max(latestDownstreamLayer[input], i); - else - latestDownstreamLayer[input] = i; - } - } - - // now that we have the latestDownstreamLayer, we inverse the map - // and compute when we reach a layer, what layers can I delete - // in this case - // 3 -> [2], 4 -> [1], 5 -> [4,3] , 7 -> [0], 8 -> [5,7] - - // keep layer if output or memories - var preserve = new HashSet( - model.memories.Select(mem => mem.input).Concat( - model.memories.Select(mem => mem.output)).Concat( - model.inputs.Select(i => i.name)).Concat( - model.outputs)); - - foreach (var entry in latestDownstreamLayer) - { - if(preserve.Contains(entry.Key)) - continue; - // input can be not specificed - if(!m_LayerNameToId.ContainsKey(entry.Key)) - continue; - - var forLayer = m_LayerIdToLayer[entry.Value]; - if (m_LayerNameToDisposeWhenDone.ContainsKey(forLayer.name)) - m_LayerNameToDisposeWhenDone[forLayer.name].Add(m_LayerNameToId[entry.Key]); - else - m_LayerNameToDisposeWhenDone[forLayer.name] = new List() { m_LayerNameToId[entry.Key] }; - } - } - - public virtual Tensor[] GatherInputs(Layer forLayer) - { - var tensors = m_InputTensorsByLayer[forLayer]; - - // fill in input variables - int index = 0; - foreach (var name in forLayer.inputs) - tensors[index++] = PeekOutput(name); - - return tensors; - } - - public virtual void PrepareStorage(Layer forLayer) {} - - public virtual void DisposeAfterLayer(Layer forLayer) - { - if(!m_LayerNameToDisposeWhenDone.ContainsKey(forLayer.name)) - return; - - foreach (var layerIdxToDispose in m_LayerNameToDisposeWhenDone[forLayer.name]) - { - var l = m_LayerIdToLayer[layerIdxToDispose]; - var key = l.name; - - if (!(m_TensorsByName.ContainsKey(key) && !m_ModelTensors.Contains(m_TensorsByName[key]))) - continue; - - if (IsTensorOwnedByInternalAllocator(m_TensorsByName[key])) - m_TensorsByName[key].Dispose(); - m_TensorsByName.Remove(key); - } - } - - public virtual void Store(Layer fromLayer, Tensor result) - { - // assign debug name - result.name = fromLayer.name; - - // @TODO: implement Disposal of the old tensor that is going to be overwritten with new one - // NOTE: need to make IWorker.CopyOutput to do real copy before enabling code below - // otherwise there is a risk of Disposing tensor that is already owned by the user, if one calls CopyOutput on m_TensorsByName - // if (m_TensorsByName.ContainsKey(fromLayer.name)) - // { - // var oldTensor = m_TensorsByName[fromLayer.name]; - // if (oldTensor != result && IsTensorOwnedByInternalAllocator(oldTensor)) - // oldTensor.Dispose(); - // } - - m_TensorsByName[fromLayer.name] = result; - } - - public virtual Tensor PeekOutput(string name) - { - if (!m_TensorsByName.ContainsKey(name)) - D.LogWarning("GenericVars missing variable: " + name); - - return m_TensorsByName[name]; - } - - public virtual Tensor[] PeekConstants(string layerName) - { - if (!m_LayerNameToId.ContainsKey(layerName)) - D.LogWarning("GenericVars missing layer: " + layerName); - - var layerId = m_LayerNameToId[layerName]; - var l = m_LayerIdToLayer[layerId]; - var layerTensors = m_InputTensorsByLayer[l]; - var constantsTensors = new List(); - for (int i = 0; i < layerTensors.Length; ++i) - { - if (i < l.inputs.Length) - { - string inputLayerName = l.inputs[i]; - var inputLayerId = m_LayerNameToId[inputLayerName]; - var inputLayer = m_LayerIdToLayer[inputLayerId]; - if (inputLayer.type != Layer.Type.Load) - continue; - } - - constantsTensors.Add(layerTensors[i]); - } - return constantsTensors.ToArray(); - } -} - -internal class GenericVarsWithReuse : GenericVars -{ - private Model m_CachedModel; - private bool m_LayerRequiresStorage = false; - private HashSet m_LayersWithStorage; - private Tensor m_Temporary; - private string m_TemporaryName = null; - protected IDictionary m_CachedInputShapes; - - internal bool layerRequiresStorage { get { return m_LayerRequiresStorage; } } - protected Tensor temporary { get { return m_Temporary; } } - - protected void ReleaseTemporary() - { - m_TemporaryName = null; - if (m_Temporary == null) - return; - - if (IsTensorOwnedByInternalAllocator(m_Temporary)) - m_Temporary.Dispose(); - m_Temporary = null; - } - - public override void PrepareStorage(Model model, IOps ops, IDictionary inputShapes, bool takeoverWeights, DataType dataType) - { - if(m_CachedInputShapes != inputShapes) - { - m_CachedInputShapes = inputShapes; - base.PrepareStorage(model, ops, inputShapes, takeoverWeights, dataType); - } - - ReleaseTemporary(); - - if (m_CachedModel != model) - m_LayersWithStorage = ModelAnalyzer.FindLayersThatRequireStorage(model); - m_CachedModel = model; - - Assert.AreEqual(m_Temporary, null); - } - - public override void PrepareStorage(Layer forLayer) - { - base.PrepareStorage(forLayer); - m_LayerRequiresStorage = m_LayersWithStorage.Contains(forLayer); - } - - public override void Store(Layer fromLayer, Tensor result) - { - if (result != m_Temporary) - ReleaseTemporary(); - - // assign debug name - result.name = fromLayer.name; - - if (layerRequiresStorage) - { - Assert.IsNotNull(result); - base.Store(fromLayer, result); - - m_Temporary = null; - m_TemporaryName = null; - } - else - { - Assert.IsTrue(m_Temporary == null || m_Temporary.tensorOnDevice == result.tensorOnDevice); - - m_Temporary = result; - m_TemporaryName = fromLayer.name; - } - } - - public override Tensor PeekOutput(string name) - { - if (m_TemporaryName == name) - { - Assert.IsNotNull(m_Temporary); - return m_Temporary; - } - return base.PeekOutput(name); - } -} - -internal class GenericVarsWithPreallocation : GenericVarsWithReuse, ITensorAllocator, IVarsStatistics -{ - public bool ShouldTrackTensorLeaks; - private Model m_CachedModel; - - private DefaultTensorAllocator m_InferenceScopedPingPongAllocator = new DefaultTensorAllocator(); - private DefaultTensorAllocator m_InferenceScopedStorageAllocator = new DefaultTensorAllocator(); - private DefaultTensorAllocator m_LayerScopedAllocator = new DefaultTensorAllocator(); - - public GenericVarsWithPreallocation() - { - m_InferenceScopedPingPongAllocator.name = "Inference ping pong Allocator"; - m_InferenceScopedStorageAllocator.name = "Inference storage Allocator"; - m_LayerScopedAllocator.name = "Layer scoped Allocator"; - ShouldTrackTensorLeaks = false; - } - - public new IEnumerable GetAllocatorsStatistics() - { - yield return m_InferenceScopedPingPongAllocator; - yield return m_InferenceScopedStorageAllocator; - yield return m_LayerScopedAllocator; - } - - /// - public virtual void PostLayerCleanup() - { - m_LayerScopedAllocator.Reset(keepCachedMemory:true); - - m_InferenceScopedPingPongAllocator.PostLayerCleanup(); - m_InferenceScopedStorageAllocator.PostLayerCleanup(); - m_LayerScopedAllocator.PostLayerCleanup(); - } - - public override void PrepareStorage(Model model, IOps ops, IDictionary inputShapes, bool takeoverWeights, DataType dataType) - { - base.PrepareStorage(model, ops, inputShapes, takeoverWeights, dataType); - - if (m_CachedModel != model) - { - // pre-allocate 2 buffers that can be cycled for temporaries - var allocator = m_InferenceScopedPingPongAllocator; - - var maxShape = ModelAnalyzer.FindLargestNecessaryTensorShape(model, inputShapes); - var alloc1 = allocator.Alloc(maxShape, AllocScope.LayerOutput, dataType); - var alloc2 = allocator.Alloc(maxShape, AllocScope.LayerOutput, dataType); - alloc1 = ops.PrepareNoAlloc(alloc1); - alloc2 = ops.PrepareNoAlloc(alloc2); - allocator.Release(alloc1, false); - allocator.Release(alloc2, false); - } - m_CachedModel = model; - - m_InferenceScopedPingPongAllocator.PostLayerCleanup();//reset allocation count - } - - public override void DisposeAfterLayer(Layer forLayer) - { -#if ENABLE_BARRACUDA_ERROR_ON_LEAKS - if (ShouldTrackTensorLeaks && m_InferenceScopedPingPongAllocator.NumAllocatedBufferSinceCleanup != 0) - { - D.LogError($"TensorData leak detected: {m_InferenceScopedPingPongAllocator.NumAllocatedBufferSinceCleanup} tensorData(s)" + - $" was/were allocated in the ping pong allocator during execution of layer {forLayer} of type {forLayer.type}."); - } -#endif - - PostLayerCleanup(); - - base.DisposeAfterLayer(forLayer); - } - - public override void Store(Layer fromLayer, Tensor result) - { - base.Store(fromLayer, result); - -#if ENABLE_BARRACUDA_ERROR_ON_LEAKS - if (ShouldTrackTensorLeaks && !m_InferenceScopedPingPongAllocator.IsPingPongReady) - { - D.LogError($"TensorData leak detected, one of the ping pong buffer was not released in layer {fromLayer} of type {fromLayer.type}."); - } -#endif - } - - public override ITensorAllocator GetAllocator() - { - return this; - } - protected override bool IsTensorOwnedByInternalAllocator(Tensor tensor) - { - var allocator = tensor.allocator; - return allocator == m_InferenceScopedPingPongAllocator || - allocator == m_InferenceScopedStorageAllocator || - allocator == m_LayerScopedAllocator; - } - - public virtual Tensor Alloc(TensorShape shape, AllocScope scope, DataType dataType) - { - if (scope == AllocScope.InternalToLayer) - return m_LayerScopedAllocator.Alloc(shape, scope, dataType); - - if (layerRequiresStorage) - return m_InferenceScopedStorageAllocator.Alloc(shape, scope, dataType); - else - return m_InferenceScopedPingPongAllocator.Alloc(shape, scope, dataType); - } - public virtual Tensor Alloc(TensorShape shape, ITensorData buffer, AllocScope scope, DataType dataType) - { - if (scope == AllocScope.InternalToLayer) - return m_LayerScopedAllocator.Alloc(shape, buffer, scope, dataType); - - if (layerRequiresStorage) - return m_InferenceScopedStorageAllocator.Alloc(shape, buffer, scope, dataType); - else - return m_InferenceScopedPingPongAllocator.Alloc(shape, buffer, scope, dataType); - } - public virtual void MoveToDevice(Tensor x, ITensorData newBuffer, ITensorData oldBuffer, bool disposeDetachedBufferHint) - { - x.allocator.MoveToDevice(x, newBuffer, oldBuffer, disposeDetachedBufferHint); - } - public virtual void Release(Tensor x, bool calledFromTensorDispose) - { - x.allocator.Release(x, calledFromTensorDispose); - } - public virtual void WaiveOwnership(Tensor x) - { - x.allocator.WaiveOwnership(x); - } - public virtual void Reset(bool keepCachedMemory) - { - m_InferenceScopedPingPongAllocator.Reset(keepCachedMemory); - m_InferenceScopedStorageAllocator.Reset(keepCachedMemory); - m_LayerScopedAllocator.Reset(keepCachedMemory); - } - - public override void Dispose() - { - base.Dispose(); - - m_InferenceScopedPingPongAllocator.Dispose(); - m_InferenceScopedStorageAllocator.Dispose(); - m_LayerScopedAllocator.Dispose(); - } - -#if ENABLE_BARRACUDA_STATS - public long usedBytes - { get { - return m_InferenceScopedPingPongAllocator.usedBytes + m_InferenceScopedStorageAllocator.usedBytes + m_LayerScopedAllocator.usedBytes; - } } - public long busyBytes - { get { - return m_InferenceScopedPingPongAllocator.busyBytes + m_InferenceScopedStorageAllocator.busyBytes + m_LayerScopedAllocator.busyBytes; - } } - public long freeBytes - { get { - return m_InferenceScopedPingPongAllocator.freeBytes + m_InferenceScopedStorageAllocator.freeBytes + m_LayerScopedAllocator.freeBytes; - } } - public long totalBytes - { get { - return m_InferenceScopedPingPongAllocator.totalBytes + m_InferenceScopedStorageAllocator.totalBytes + m_LayerScopedAllocator.totalBytes; - } } - public override string ToString() - { - return $"Total allocated: {totalBytes} busy: {busyBytes}"; - } -#endif //ENABLE_BARRACUDA_STATS -} - -//public class DefaultTensorAllocator : TensorOperatorNewAllocator {} -//public class DefaultTensorAllocator : TensorCachingByShapeAllocator {} -internal class DefaultTensorAllocator : TensorCachingAllocator {} - -//public class DefaultVars : GenericVars {} -//public class DefaultVars : GenericVarsWithReuse {} -internal class DefaultVars : GenericVarsWithPreallocation {} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/GenericWorker.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/GenericWorker.cs.meta deleted file mode 100644 index 27226bb..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/GenericWorker.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: f7473266805a8439287433d3dac88945 -timeCreated: 1506427659 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/LayerFusingHelper.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/LayerFusingHelper.cs deleted file mode 100644 index c685097..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/LayerFusingHelper.cs +++ /dev/null @@ -1,758 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; // ToArray(), ToDictionary() - -namespace Unity.Barracuda -{ - internal class LinearLayerFusing - { - public static bool IsLayerLinear(Layer layer, Dictionary constantLayers) - { - var constInputs = layer.inputs.Count(x => constantLayers.ContainsKey(x)); - bool allConstInputsButOne = (layer.inputs.Length - constInputs) == 1; - - return layer.type == Layer.Type.Dense || - layer.type == Layer.Type.Conv2D || //TODO Conv3D - layer.type == Layer.Type.DepthwiseConv2D || - layer.type == Layer.Type.ScaleBias || - IsLayerLinearMathOp(layer) && allConstInputsButOne; - } - - public static bool IsLayerLinearMathOp(Layer layer) - { - return layer.type == Layer.Type.Add || - layer.type == Layer.Type.Mul; - } - - public bool AreLayersFusable(Layer l0, Layer l1) - { - bool conditions = true; - if ((l0.type == Layer.Type.DepthwiseConv2D) || (l0.type == Layer.Type.Conv2D) || (l0.type == Layer.Type.ScaleBias) && - (l1.type == Layer.Type.Conv2D) || (l1.type == Layer.Type.DepthwiseConv2D)) - conditions = conditions && !l1.pad.Any(x => x != 0); // padding breaks bias merging for non-zero bias - if (IsLayerLinearMathOp(l0) && (l1.type == Layer.Type.Conv2D)) - { - if (l0.datasets == null || l0.datasets.Length != 1) - return false; - conditions = conditions && (l0.datasets[0].shape.length == 1) || - (l0.datasets[0].shape.batch == 1 && l0.datasets[0].shape.height == 1 && l0.datasets[0].shape.width == 1 && l0.datasets[0].shape.channels == l1.datasets[0].shape.kernelCount); - } - if ((l0.type == Layer.Type.Conv2D) && IsLayerLinearMathOp(l1)) - { - if (l1.datasets == null || l1.datasets.Length != 1) - return false; - conditions = conditions && (l1.datasets[0].shape.length == 1) || - (l1.datasets[0].shape.batch == 1 && l1.datasets[0].shape.height == 1 && l1.datasets[0].shape.width == 1 && l1.datasets[0].shape.channels == l0.datasets[0].shape.kernelCount); - } - - return m_LayerFusers.ContainsKey((l0.type, l1.type)) && conditions; - } - - private readonly BurstCPUOps m_Ops = new BurstCPUOps(); - - private readonly Dictionary<(Layer.Type, Layer.Type), Func> m_LayerFusers = - new Dictionary<(Layer.Type, Layer.Type), Func>(); - - private void Add((Layer.Type, Layer.Type) layersType, Func opFuseAction) - { - m_LayerFusers.Add(layersType, opFuseAction); - } - public LinearLayerFusing() - { - Add((Layer.Type.Add, Layer.Type.Add), (l0, l1) => - { - Tensor bias0 = l0.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(0); - - int rankO = Math.Max(bias0.dimensions, bias1.dimensions); - if (l0.axis >= 0 && l1.axis >= 0) // legacy tests don't store constant rank in axis - { - // broadcast rule - int rank0 = l0.axis; - List shape0 = Compiler.IRShapeInferenceHelper.ShapeInference.ShapeToOnnxLayout(bias0.shape, rank0); - rank0 = Math.Max(rank0, 1); - int rank1 = l1.axis; - List shape1 = Compiler.IRShapeInferenceHelper.ShapeInference.ShapeToOnnxLayout(bias1.shape, rank1); - rank1 = Math.Max(rank1, 1); - - rankO = Math.Max(rank0, rank1); - for (int k = 0; k < rankO - rank0; k++) - shape0.Insert(0, 1); - for (int k = 0; k < rankO - rank1; k++) - shape1.Insert(0, 1); - - bias0 = bias0.Reshape(Compiler.IRShapeInferenceHelper.ShapeInference.OnnxLayoutToTensorShape(shape0.ToArray())); - bias1 = bias1.Reshape(Compiler.IRShapeInferenceHelper.ShapeInference.OnnxLayoutToTensorShape(shape1.ToArray())); - } - - TensorShape biasShape = TensorExtensions.MaxShape(new [] { bias0, bias1 }); - - Layer lmerged = new Layer(l0.name, l0.type); - lmerged.inputs = l0.inputs; - lmerged.datasets = new Layer.DataSet[1]; - lmerged.datasets[0].name = l0.datasets[0].name; - lmerged.datasets[0].shape = biasShape; - lmerged.datasets[0].itemSizeInBytes = 4; - lmerged.datasets[0].length = biasShape.length; - lmerged.datasets[0].offset = 0; - lmerged.weights = new BarracudaArray(biasShape.length); - lmerged.axis = rankO; - - Tensor bias = m_Ops.Add(new [] { bias0, bias1 }); - - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, 0, bias.length); - - bias.Dispose(); - bias0.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Mul, Layer.Type.Mul), (l0, l1) => - { - Tensor scale0 = l0.DataSetToTensor(0); - Tensor scale1 = l1.DataSetToTensor(0); - - int rankO = Math.Max(scale0.dimensions, scale1.dimensions); - if (l0.axis >= 0 && l1.axis >= 0) // legacy tests don't store constant rank in axis - { - // broadcast rule - int rank0 = l0.axis; - List shape0 = Compiler.IRShapeInferenceHelper.ShapeInference.ShapeToOnnxLayout(scale0.shape, rank0); - rank0 = Math.Max(rank0, 1); - int rank1 = l1.axis; - List shape1 = Compiler.IRShapeInferenceHelper.ShapeInference.ShapeToOnnxLayout(scale1.shape, rank1); - rank1 = Math.Max(rank1, 1); - - rankO = Math.Max(rank0, rank1); - for (int k = 0; k < rankO - rank0; k++) - shape0.Insert(0, 1); - for (int k = 0; k < rankO - rank1; k++) - shape1.Insert(0, 1); - - scale0 = scale0.Reshape(Compiler.IRShapeInferenceHelper.ShapeInference.OnnxLayoutToTensorShape(shape0.ToArray())); - scale1 = scale1.Reshape(Compiler.IRShapeInferenceHelper.ShapeInference.OnnxLayoutToTensorShape(shape1.ToArray())); - } - - TensorShape biasShape = TensorExtensions.MaxShape(new[] { scale0, scale1 }); - - Layer lmerged = new Layer(l0.name, l0.type); - lmerged.inputs = l0.inputs; - lmerged.datasets = new Layer.DataSet[1]; - lmerged.datasets[0].name = l0.datasets[0].name; - lmerged.datasets[0].shape = biasShape; - lmerged.datasets[0].itemSizeInBytes = 4; - lmerged.datasets[0].length = biasShape.length; - lmerged.datasets[0].offset = 0; - lmerged.weights = new BarracudaArray(biasShape.length); - lmerged.axis = rankO; - - Tensor bias = m_Ops.Mul(new[] { scale0, scale1 }); - - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, 0, bias.length); - - bias.Dispose(); - scale0.Dispose(); - scale1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.ScaleBias, Layer.Type.ScaleBias), (l0, l1) => - { - Tensor scale0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor scale1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l0.type); - lmerged.inputs = l0.inputs; - lmerged.datasets = l0.datasets; - lmerged.weights = new BarracudaArray(l0.weights.Length); - - // s1*(s0*x + b0)+b1 = s1*s0*x + s1*b0+b1 - Tensor scale = m_Ops.Mul(new [] { scale1, scale0}); - Tensor bias = m_Ops.ScaleBias(bias0, scale1, bias1); - - BarracudaArray.Copy(scale.ToReadOnlyArray(), 0, lmerged.weights, 0, scale.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, scale.length, bias.length); - - scale.Dispose(); - bias.Dispose(); - scale0.Dispose(); - bias0.Dispose(); - scale1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.ScaleBias, Layer.Type.Dense), (l0, l1) => - { - Tensor scale0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor weights1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l1.type); - lmerged.inputs = l0.inputs; - lmerged.datasets = l1.datasets; - lmerged.weights = new BarracudaArray(l1.weights.Length); - - // b = W1 x b0 + b1 - Tensor bias = m_Ops.Dense(bias0, weights1, bias1, Layer.FusedActivation.None); - - // W = W1 x s - Tensor weights = new Tensor(weights1.shape); - for (int x = 0; x < weights1.flatWidth; ++x) - for (int i = 0; i < weights1.flatHeight; ++i) - { - int c = i % bias0.length; - float gamma = scale0[c]; - - float w = weights1[i, x]; - weights[i, x] = w * gamma; - } - - BarracudaArray.Copy(weights.ToReadOnlyArray(), 0, lmerged.weights, 0, weights.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, weights.length, bias.length); - - bias.Dispose(); - weights.Dispose(); - scale0.Dispose(); - bias0.Dispose(); - weights1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Dense, Layer.Type.ScaleBias), (l0, l1) => - { - Tensor weights0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor scale1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l0.type); - lmerged.inputs = l0.inputs; - lmerged.datasets = l0.datasets; - lmerged.weights = new BarracudaArray(l0.weights.Length); - - // w = s1*w0 - Tensor weights = m_Ops.Mul(new [] { scale1, weights0 }); - // b = s1*b0+b1 - Tensor bias = m_Ops.ScaleBias(bias0, scale1, bias1); - - BarracudaArray.Copy(weights.ToReadOnlyArray(), 0, lmerged.weights, 0, weights.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, weights.length, bias.length); - - weights.Dispose(); - bias.Dispose(); - weights0.Dispose(); - bias0.Dispose(); - scale1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Mul, Layer.Type.Conv2D), (l0, l1) => - { - Tensor scale0 = l0.DataSetToTensor(0); - - Tensor kernel1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l1.type); - lmerged.pad = l1.pad; - lmerged.stride = l1.stride; - lmerged.pool = l1.pool; - lmerged.inputs = l0.inputs; - lmerged.datasets = l1.datasets; - lmerged.weights = new BarracudaArray(l1.weights.Length); - - // k = k * s - Tensor kernel = new Tensor(kernel1.shape); - - for (int y = 0; y < kernel1.kernelHeight; ++y) - for (int x = 0; x < kernel1.kernelWidth; ++x) - for (int c = 0; c < kernel1.kernelDepth; ++c) - { - float gamma = scale0[scale0.IndexWithBroadcast(0, 0, 0, c)]; - for (int k = 0; k < kernel1.kernelCount; ++k) - { - float w = kernel1[y, x, c, k]; - kernel[y, x, c, k] = gamma * w; - } - } - - - BarracudaArray.Copy(kernel.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel.length); - BarracudaArray.Copy(bias1.ToReadOnlyArray(), 0, lmerged.weights, kernel.length, bias1.length); - - kernel.Dispose(); - scale0.Dispose(); - kernel1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Conv2D, Layer.Type.Mul), (l0, l1) => - { - Tensor kernel0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor scale1 = l1.DataSetToTensor(0); - - Layer lmerged = new Layer(l0.name, l0.type); - lmerged.pad = l0.pad; - lmerged.stride = l0.stride; - lmerged.pool = l0.pool; - lmerged.inputs = l0.inputs; - lmerged.datasets = l0.datasets; - lmerged.weights = new BarracudaArray(l0.weights.Length); - - // k = s1*k0 - Tensor kernel = m_Ops.Mul(new[] { scale1, kernel0 }); - // b = s1*b0 - Tensor bias = m_Ops.Mul(new[] { scale1, bias0 }); - - BarracudaArray.Copy(kernel.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, kernel.length, bias.length); - - kernel.Dispose(); - bias.Dispose(); - kernel0.Dispose(); - bias0.Dispose(); - scale1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Add, Layer.Type.Conv2D), (l0, l1) => - { - Tensor bias0 = l0.DataSetToTensor(0); - - Tensor kernel1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l1.type); - lmerged.pad = l1.pad; - lmerged.stride = l1.stride; - lmerged.pool = l1.pool; - lmerged.inputs = l0.inputs; - lmerged.datasets = l1.datasets; - lmerged.weights = new BarracudaArray(l1.weights.Length); - - // k = k - // b = Sum_k[wk * beta] + b - Tensor bias = new Tensor(bias1.shape, bias1.ToReadOnlyArray()); - for (int y = 0; y < kernel1.kernelHeight; ++y) - for (int x = 0; x < kernel1.kernelWidth; ++x) - for (int c = 0; c < kernel1.kernelDepth; ++c) - { - float beta = bias0[bias0.IndexWithBroadcast(0, 0, 0, c)]; - for (int k = 0; k < kernel1.kernelCount; ++k) - { - float w = kernel1[y, x, c, k]; - bias[k] += w * beta; - } - } - - - BarracudaArray.Copy(kernel1.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel1.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, kernel1.length, bias.length); - - bias.Dispose(); - bias0.Dispose(); - kernel1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Conv2D, Layer.Type.Add), (l0, l1) => - { - Tensor kernel0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor bias1 = l1.DataSetToTensor(0); - - Layer lmerged = new Layer(l0.name, l0.type); - lmerged.pad = l0.pad; - lmerged.stride = l0.stride; - lmerged.pool = l0.pool; - lmerged.inputs = l0.inputs; - lmerged.datasets = l0.datasets; - lmerged.weights = new BarracudaArray(l0.weights.Length); - - // b = b0+b1 - Tensor bias = m_Ops.Add( new [] { bias0, bias1 }); - - BarracudaArray.Copy(kernel0.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel0.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, kernel0.length, bias.length); - - bias.Dispose(); - kernel0.Dispose(); - bias0.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Conv2D, Layer.Type.ScaleBias), (l0, l1) => - { - Tensor kernel0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor scale1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l0.type); - lmerged.pad = l0.pad; - lmerged.stride = l0.stride; - lmerged.pool = l0.pool; - lmerged.inputs = l0.inputs; - lmerged.datasets = l0.datasets; - lmerged.weights = new BarracudaArray(l0.weights.Length); - - // k = s1*k0 - Tensor kernel = m_Ops.Mul(new[] { scale1, kernel0 }); - // b = s1*b0+b1 - Tensor bias = m_Ops.ScaleBias(bias0, scale1, bias1); - - BarracudaArray.Copy(kernel.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, kernel.length, bias.length); - - kernel.Dispose(); - bias.Dispose(); - kernel0.Dispose(); - bias0.Dispose(); - scale1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.ScaleBias, Layer.Type.Conv2D), (l0, l1) => - { - Tensor scale0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor kernel1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l1.type); - lmerged.pad = l1.pad; - lmerged.stride = l1.stride; - lmerged.pool = l1.pool; - lmerged.inputs = l0.inputs; - lmerged.datasets = l1.datasets; - lmerged.weights = new BarracudaArray(l1.weights.Length); - - // k = k * s - Tensor kernel = new Tensor(kernel1.shape); - // b = Sum_k[wk * beta] + b - Tensor bias = new Tensor(bias1.shape, bias1.ToReadOnlyArray()); - for (int y = 0; y < kernel1.kernelHeight; ++y) - for (int x = 0; x < kernel1.kernelWidth; ++x) - for (int c = 0; c < kernel1.kernelDepth; ++c) - { - float beta = bias0[0, 0, 0, c]; - float gamma = scale0[0, 0, 0, c]; - for (int k = 0; k < kernel1.kernelCount; ++k) - { - float w = kernel1[y, x, c, k]; - kernel[y, x, c, k] = gamma * w; - bias[k] += w * beta; - } - } - - BarracudaArray.Copy(kernel.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, kernel.length, bias.length); - - kernel.Dispose(); - bias.Dispose(); - scale0.Dispose(); - bias0.Dispose(); - kernel1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.DepthwiseConv2D, Layer.Type.ScaleBias), (l0, l1) => - { - Tensor kernel0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor scale1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l0.type); - lmerged.pad = l0.pad; - lmerged.stride = l0.stride; - lmerged.pool = l0.pool; - lmerged.inputs = l0.inputs; - lmerged.datasets = l0.datasets; - lmerged.weights = new BarracudaArray(l0.weights.Length); - - // k = s1*k0 - Tensor kernel = m_Ops.Mul(new[] { scale1, kernel0 }); - // b = s1*b0+b1 - Tensor bias = m_Ops.ScaleBias(bias0, scale1, bias1); - - BarracudaArray.Copy(kernel.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, kernel.length, bias.length); - - kernel.Dispose(); - bias.Dispose(); - kernel0.Dispose(); - bias0.Dispose(); - scale1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.ScaleBias, Layer.Type.DepthwiseConv2D), (l0, l1) => - { - Tensor scale0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - - Tensor kernel1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - - Layer lmerged = new Layer(l0.name, l1.type); - lmerged.pad = l1.pad; - lmerged.stride = l1.stride; - lmerged.pool = l1.pool; - lmerged.inputs = l0.inputs; - lmerged.datasets = l1.datasets; - lmerged.weights = new BarracudaArray(l1.weights.Length); - - // k = k * s - Tensor kernel = new Tensor(kernel1.shape); - // b = Sum_k[wk * beta] + b - Tensor bias = new Tensor(bias1.shape); - for (int k = 0; k < kernel1.kernelCount; ++k) - { - float b = bias1[k]; - - float beta = bias0[0, 0, 0, k]; - float gamma = scale0[0, 0, 0, k]; - for (int y = 0; y < kernel1.kernelHeight; ++y) - for (int x = 0; x < kernel1.kernelWidth; ++x) - { - float w = kernel1[y, x, 0, k]; - kernel[y, x, 0, k] = gamma * w; - b += w * beta; - } - - bias[k] = b; - } - - BarracudaArray.Copy(kernel.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, kernel.length, bias.length); - - kernel.Dispose(); - bias.Dispose(); - scale0.Dispose(); - bias0.Dispose(); - kernel1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Dense, Layer.Type.Dense), (l0, l1) => - { - var weights0 = l0.DataSetToTensor(0); - var bias0 = l0.DataSetToTensor(1); - - var weights1 = l1.DataSetToTensor(0); - var bias1 = l1.DataSetToTensor(1); - - TensorShape weightsShape = new TensorShape(weights0.shape.flatHeight, weights1.shape.flatWidth); - - Layer lmerged = new Layer(l0.name, l1.type); - lmerged.inputs = l0.inputs; - lmerged.datasets = new Layer.DataSet[2]; - lmerged.datasets[0].name = weights0.name; - lmerged.datasets[0].shape = weightsShape; - lmerged.datasets[0].itemSizeInBytes = 4; - lmerged.datasets[0].length = weightsShape.length; - lmerged.datasets[0].offset = 0; - - lmerged.datasets[1].name = bias0.name; - lmerged.datasets[1].shape = bias1.shape; - lmerged.datasets[1].itemSizeInBytes = 4; - lmerged.datasets[1].length = bias1.length; - lmerged.datasets[1].offset = weightsShape.length; - lmerged.weights = new BarracudaArray(weightsShape.length + bias1.shape.length); - - // W = W1 x W0 - Tensor weights = m_Ops.MatMul(weights0, false, weights1, false); - // b = W1 x b0 + b1 - Tensor bias = m_Ops.Dense(bias0, weights1, bias1, Layer.FusedActivation.None); - - BarracudaArray.Copy(weights.ToReadOnlyArray(), 0, lmerged.weights, 0, weights.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, weights.length, bias.length); - - weights.Dispose(); - bias.Dispose(); - weights0.Dispose(); - bias0.Dispose(); - weights1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - Add((Layer.Type.Conv2D, Layer.Type.Conv2D), (l0, l1) => - { - Tensor kernel0 = l0.DataSetToTensor(0); - Tensor bias0 = l0.DataSetToTensor(1); - var strides0 = l0.stride; - var pad0 = l0.pad; - - Tensor kernel1 = l1.DataSetToTensor(0); - Tensor bias1 = l1.DataSetToTensor(1); - var strides1 = l1.stride; - var pad1 = l1.pad; - - - // Y = (X * K0 + b0) * K1 + b1 - // = (X * K0) * K1 + (b0 * K1 + b1) - // = X * (K0 * k1) + (b0 * K1 + b1) - // = X * K2 + b2 - // K2 dimensions: - // kernelDepth and kernelCount: - // X = [n, . , . , c0], K0 = [ . , . , c0, d0] , K1 = [ . , . , c1, d1] - // => Km = [ x , x , c0, d1] - // kernelHeight and kernelHeight: - // Y = (((X + 2*p0 - k0)/s0 + 1) + 2*p1 - k1)/s1 + 1 - // = ((X + 2*p0 - k0 + s0 + 2*p1*s0 - k1*s0)/s0)/s1 + 1 - // = (X + 2*p0 - k0 + s0 + 2*p1*s0 - k1*s0) / (s0*s1) + 1 - // = (X + 2*(p0+p1*s0) - (k0 + k1*s0 - s0)) / (s0*s1) + 1 - // => pad = p0 + p1*s0 - // kernel = k0 + s0*(k1 - 1) - // stride = s0*s1 - TensorShape kernelShape = new TensorShape(kernel0.kernelHeight + (kernel1.kernelHeight - 1) * strides0[0], - kernel0.kernelWidth + (kernel1.kernelWidth - 1) * strides0[1], - kernel0.kernelDepth, kernel1.kernelCount); - - var pad = new int[4] { pad0[0] + pad1[0] * strides0[0], pad0[1] + pad1[1] * strides0[1], - pad0[2] + pad1[2] * strides0[0], pad0[3] + pad1[3] * strides0[1] }; - var strides = new int[2] { strides0[0] * strides1[0], strides0[1] * strides1[1] }; - - TensorShape biasShape = bias1.shape; - - - Layer lmerged = new Layer(l0.name, l1.type); - lmerged.inputs = l0.inputs; - lmerged.stride = strides; - lmerged.pad = pad; - lmerged.datasets = new Layer.DataSet[2]; - lmerged.datasets[0].name = kernel0.name; - lmerged.datasets[0].shape = kernelShape; - lmerged.datasets[0].itemSizeInBytes = 4; - lmerged.datasets[0].length = kernelShape.length; - lmerged.datasets[0].offset = 0; - - lmerged.datasets[1].name = bias0.name; - lmerged.datasets[1].shape = biasShape; - lmerged.datasets[1].itemSizeInBytes = 4; - lmerged.datasets[1].length = biasShape.length; - lmerged.datasets[1].offset = kernelShape.length; - lmerged.weights = new BarracudaArray(kernelShape.length + biasShape.length); - - - Tensor kernel = new Tensor(kernelShape); // 0-filled by default - // |x0 x1 x3 | x4 |y0 y1| y2 |z0| z1 - // |x5 x6 x7 | x8 * k0 k1 => |y3 y4| y5 * l0 l1 => z2 z3 - // |x9 x10 x11| x12 k2 k3 y6 y7 y8 l2 l3 - // x13 x14 x15 x13 - // - // in order to compute z0, we need to do 2 convolutions - // - // |y0 y1/ - // | |x0 /x1| x3/ | - // | |x5 /x6| x7/ | - // | x9 x10 x11 | - // - // |x0 x1| is convolved with K and then * l0 - // |x5 x6| - // /x1 x3/ is convolved with K and then * l1 - // /x6 x7/ - // - // by unwrapping the whole process - // z0 = [x0 * k0 * l0 + x1 * k1 * l0 + ....] + [x1 * k1 * l1 + ....] - // l0 * y0-block l1 * y1-block - // resulting conv kernel is the following - // - // z0 = | x0 x1 x3 | * | [k0*l0] [k1*l0 + k1*l1] [l2*l1] | - // | x5 x6 x7 | | [k2*l0 + k2*l2] [k3*l0 + k2*l1 + k1*l2 + k0*l3] [k3*l1 + k3*l3] | - // | x9 x10 x11 | | [k2*l2] [k2*l0 + k2*l3 [k3*l3] | - Tensor kernel0T = m_Ops.Transpose(kernel0, new[] { 2, 0, 1, 3 }); - Tensor emptyB = new Tensor(new TensorShape(1, 1, 1, kernel.kernelCount)); - for (int y1 = 0; y1 < kernel1.kernelHeight; ++y1) - for (int x1 = 0; x1 < kernel1.kernelWidth; ++x1) - { - Tensor kernel1XY = m_Ops.StridedSlice(kernel1, new[] { y1, x1, 0, 0 }, new[] { y1 + 1, x1 + 1, kernel1.kernelDepth, kernel.kernelCount }, new[] { 1, 1, 1, 1 }); - Tensor kernelk = m_Ops.Conv2D(kernel0T, kernel1XY, emptyB, new[] { 1, 1 }, new[] { 0, 0, 0, 0 }, Layer.FusedActivation.None); - - for (int y0 = 0; y0 < kernel0.kernelHeight; ++y0) - for (int x0 = 0; x0 < kernel0.kernelWidth; ++x0) - { - int ox = x0 + strides0[0] * x1; - int oy = y0 + strides0[1] * y1; - for (int c = 0; c < kernel.kernelDepth; ++c) - for (int k = 0; k < kernel.kernelCount; ++k) - { - kernel[oy, ox, c, k] += kernelk[c,y0,x0,k]; - } - } - kernel1XY.Dispose(); - kernelk.Dispose(); - } - - // |y0 y1| * l0 l1 + bl = z0 - // |y3 y4| l2 l3 - // y0 = Sum_k() + bk, y1 = Sum_k() + bk - // y2 = Sum_k() + bk, y2 = Sum_k() + bk - // - // moving b from the convolution process leads - // z0 = | x0 x1 x3 | * M + bl + l0*bk + l1*bk + l2*bk + l3*bk - // | x5 x6 x7 | - // | x9 x10 x11 | - // N.B: as you can see this breaks if there is some amount of zero-padding to the second conv layer - // because some weights of L will be * 0, essentialy masking out bk - Tensor bias = new Tensor(biasShape, bias1.ToReadOnlyArray()); - for (int x1 = 0; x1 < kernel1.kernelWidth; ++x1) - for (int y1 = 0; y1 < kernel1.kernelHeight; ++y1) - for (int c = 0; c < kernel1.kernelDepth; ++c) - { - float bias0c = bias0[c]; - for (var k = 0; k < kernel.kernelCount; ++k) - { - bias[k] += kernel1[y1, x1, c, k] * bias0c; - } - } - - BarracudaArray.Copy(kernel.ToReadOnlyArray(), 0, lmerged.weights, 0, kernel.length); - BarracudaArray.Copy(bias.ToReadOnlyArray(), 0, lmerged.weights, kernel.length, bias.length); - - kernel0T.Dispose(); - emptyB.Dispose(); - kernel.Dispose(); - bias.Dispose(); - kernel0.Dispose(); - bias0.Dispose(); - kernel1.Dispose(); - bias1.Dispose(); - - return lmerged; - }); - } - - public Layer FuseLayers(Layer l0, Layer l1) - { - var fnFuse = m_LayerFusers[(l0.type, l1.type)]; - return fnFuse(l0, l1); - } - } - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/LayerFusingHelper.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/LayerFusingHelper.cs.meta deleted file mode 100644 index 13ace7c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/LayerFusingHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b940ee731fee3c3478e90a161a7a7288 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/MatrixUtils.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/MatrixUtils.cs deleted file mode 100644 index 155c5bf..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/MatrixUtils.cs +++ /dev/null @@ -1,259 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using UnityEngine.Assertions; -using UnityEngine.Scripting; - -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs; - -[assembly: InternalsVisibleTo("Unity.Barracuda.BurstBLAS")] - -namespace Unity.Barracuda -{ - [Preserve] - internal class CSharpBLAS : BLASPlugin - { - public bool IsNative() - { - return false; // reference implementation - } - - public bool IsCurrentPlatformSupported() - { - return true; - } - - public unsafe void SGEMM(float* Ap, int AM, int AN, float* Bp, int BM, int BN, float* Cp, int CM, int CN, int bs, - bool transposeA = false, bool transposeB = false) - { - MatrixUtils.MultiplyBlockUnrollHx8ParallelWithPadding(Ap, AM, AN, Bp, BM, BN, Cp, CM, CN, bs, - transposeA, transposeB); - } - - public unsafe JobHandle ScheduleSGEMM(JobHandle dependsOn, - float* Ap, int AM, int AN, float* Bp, int BM, int BN, float* Cp, int CM, int CN, - int bs, - bool transposeA = false, bool transposeB = false) - { - var job = new SGEMMJob(); - job.Ap = Ap; job.AM = AM; job.AN = AN; - job.Bp = Bp; job.BM = BM; job.BN = BN; - job.Cp = Cp; job.CM = CM; job.CN = CN; - job.transposeA = transposeA; - job.transposeB = transposeB; - job.bs = bs; - return job.Schedule(dependsOn); - } - - unsafe struct SGEMMJob : IJob - { - [NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* Ap; - public int AM, AN; - [NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* Bp; - public int BM, BN; - [NativeDisableUnsafePtrRestriction] public unsafe float* Cp; - public int CM, CN; - public int bs; - public bool transposeA; - public bool transposeB; - - public void Execute() - { - MatrixUtils.MultiplyBlockUnrollHx8ParallelWithPadding( - Ap, AM, AN, - Bp, BM, BN, - Cp, CM, CN, bs, - transposeA, transposeB); - } - } - } - - internal class MatrixUtils - { - public static unsafe void CopyBlockWithPadding(float* matrixIn, int row, int M, int col, int N, float[] blockOut, int bs, bool transpose = false) - { - Array.Clear(blockOut, 0, bs * bs); - - var rowFinal = Math.Min(row + bs, M); - var count = Math.Min(col + bs, N) - col; - - // @TODO: measure which one is better - sequential access over matrix memory or blockOut cache - if (transpose) - { - // sequential access over blockOut, strided over matrixIn - //for (var i = row; i < rowFinal; i++) - // for (var j = 0; j < count; ++j) - // blockOut[(i - row) * bs + j] = matrixIn[i + (col + j) * N]; - - // sequential access over matrixIn, strided over blockOut - for (var j = 0; j < count; ++j) - for (var i = row; i < rowFinal; i++) - blockOut[(i - row) * bs + j] = matrixIn[i + (col + j) * M]; - } - else - for (var i = row; i < rowFinal; i++) - { - //D.Log(string.Format("Copy[{3}] {0} -> {1} {2}", i * M + col, (i - row) * bs, count, i)); - Marshal.Copy((IntPtr)(matrixIn + i * N + col), blockOut, (i - row) * bs, count); - } - - } - - public static unsafe void ClearFloatArray(float* arr, float val, int count) - { - for (int i = 0; i < count; i++) - { - arr[i] = val; - } - } - - public static unsafe void CopyFloatArray(float* from, float* to, int count) - { - for (int i = 0; i < count; i++) - { - to[i] = from[i]; - } - } - - public static unsafe void CopyBlockWithPadding(float* matrixIn, int row, int M, int col, int N, float* blockOut, int bs, bool transpose = false) - { - ClearFloatArray(blockOut, 0, bs * bs); - - var rowFinal = Math.Min(row + bs, M); - var count = Math.Min(col + bs, N) - col; - - // @TODO: measure which one is better - sequential access over matrix memory or blockOut cache - if (transpose) - { - // sequential access over blockOut, strided over matrixIn - //for (var i = row; i < rowFinal; i++) - // for (var j = 0; j < count; ++j) - // blockOut[(i - row) * bs + j] = matrixIn[i + (col + j) * N]; - - // sequential access over matrixIn, strided over blockOut - for (var j = 0; j < count; ++j) - for (var i = row; i < rowFinal; i++) - blockOut[(i - row) * bs + j] = matrixIn[i + (col + j) * M]; - } - else - for (var i = row; i < rowFinal; i++) - { - //D.Log(string.Format("Copy[{3}] {0} -> {1} {2}", i * M + col, (i - row) * bs, count, i)); - CopyFloatArray(matrixIn + i * N + col, blockOut + (i - row) * bs, count); - } - - } - - public static unsafe void CopyBlockWithPadding(float[] blockOut, float* matrixIn, int row, int M, int col, int N, int bs) - { - var rowFinal = Math.Min(row + bs, M); - var count = Math.Min(col + bs, N) - col; - - for (var i = row; i < rowFinal; i++) - Marshal.Copy(blockOut, (i - row) * bs, (IntPtr)(matrixIn + i * N + col), count); - } - - public static unsafe void CopyBlockWithPadding(float* blockOut, float* matrixIn, int row, int M, int col, int N, int bs) - { - var rowFinal = Math.Min(row + bs, M); - var count = Math.Min(col + bs, N) - col; - - for (var i = row; i < rowFinal; i++) - CopyFloatArray(blockOut + (i - row) * bs, matrixIn + i * N + col, count); - } - - public static unsafe void MultiplyBlockUnrollHx8Padded(float* Ap, - float* Bp, - float* Cp, int bs) - { - for (int i = 0; i < bs; i++) - { - for (int j = 0; j < bs; j += 8) - { - int baseC = i * bs + j; - float sum0 = *(Cp + baseC); - float sum1 = *(Cp + baseC + 1); - float sum2 = *(Cp + baseC + 2); - float sum3 = *(Cp + baseC + 3); - float sum4 = *(Cp + baseC + 4); - float sum5 = *(Cp + baseC + 5); - float sum6 = *(Cp + baseC + 6); - float sum7 = *(Cp + baseC + 7); - - for (int l = 0; l < bs; l++) - { - float A = Ap[i * bs + l]; - int baseB = l * bs + j; - - sum0 += A * *(Bp + baseB); - sum1 += A * *(Bp + baseB + 1); - sum2 += A * *(Bp + baseB + 2); - sum3 += A * *(Bp + baseB + 3); - sum4 += A * *(Bp + baseB + 4); - sum5 += A * *(Bp + baseB + 5); - sum6 += A * *(Bp + baseB + 6); - sum7 += A * *(Bp + baseB + 7); - } - - *(Cp + baseC) = sum0; - *(Cp + baseC + 1) = sum1; - *(Cp + baseC + 2) = sum2; - *(Cp + baseC + 3) = sum3; - *(Cp + baseC + 4) = sum4; - *(Cp + baseC + 5) = sum5; - *(Cp + baseC + 6) = sum6; - *(Cp + baseC + 7) = sum7; - } - } - } - - public static unsafe void MultiplyBlockUnrollHx8ParallelWithPadding(float* Ap, int AM, int AN, - float* Bp, int BM, int BN, - float* Cp, int CM, int CN, int bs, - bool transposeA = false, bool transposeB = false) - { - if (transposeA) - { - var tmp = AM; AM = AN; AN = tmp; - } - if (transposeB) - { - var tmp = BM; BM = BN; BN = tmp; - } - - int N = AM; - { - Assert.IsTrue(bs >= 8, "Matrix Mul block size should be >= 8"); - - Parallel.For(0, (BN / bs) + (BN % bs > 0 ? 1 : 0), colB => - { - float[] blockA = new float[bs * bs]; - float[] blockB = new float[bs * bs]; - float[] blockC = new float[bs * bs]; - - for (int rowA = 0; rowA < N; rowA += bs) - { - for (int l = 0; l < AN; l += bs) - { - - CopyBlockWithPadding(Ap, rowA, AM, l, AN, blockA, bs, transposeA); - CopyBlockWithPadding(Bp, l, BM, colB * bs, BN, blockB, bs, transposeB); - CopyBlockWithPadding(Cp, rowA, CM, colB * bs, CN, blockC, bs); - - fixed (float* blockAp = blockA, blockBp = blockB, blockCp = blockC) - { - MultiplyBlockUnrollHx8Padded(blockAp, blockBp, blockCp, bs); - } - - CopyBlockWithPadding(blockC, Cp, rowA, CM, colB * bs, CN, bs); - } - } - }); - } - } - } -} - diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/MatrixUtils.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/MatrixUtils.cs.meta deleted file mode 100644 index 0c8ebab..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/MatrixUtils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bf04fe6d135714369af8cab2915b2735 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/MemoryAndExecutionReportHelper.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/MemoryAndExecutionReportHelper.cs deleted file mode 100644 index 6b5da4e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/MemoryAndExecutionReportHelper.cs +++ /dev/null @@ -1,985 +0,0 @@ -#if ENABLE_BARRACUDA_STATS - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine.Assertions; - -namespace Unity.Barracuda { - -internal static class MemoryAndExecutionReportHelper -{ - public static void GenerateStringReport(StringBuilder stringBuilder, ModelExecutionReport modelExecutionReport, - bool spreadSheetFormat) - { - stringBuilder.Append($"Number of completed layers : {modelExecutionReport.CompletedLayerExecutionReports.Count}\n"); - if (modelExecutionReport.CurrentLayerExecutionReport != null) - stringBuilder.Append("Warning: last layer was not completed. It will be logged, but it's information might be incomplete or erroneous.\n"); - stringBuilder.Append("\n"); - - List allLayerReports = new List(); - allLayerReports.AddRange(modelExecutionReport.CompletedLayerExecutionReports); - if (modelExecutionReport.CurrentLayerExecutionReport != null) - allLayerReports.Add(modelExecutionReport.CurrentLayerExecutionReport); - - var layerExecutionViews = GenerateExecutionViews(allLayerReports, modelExecutionReport.CompletedLayerExecutionReports.Count); - GenerateReportForViews(stringBuilder, layerExecutionViews, spreadSheetFormat, "", false); - } - - public static MemoryPeakSummary GenerateStringReport(StringBuilder stringBuilder, List memorySnapshots, - bool spreadSheetFormat) - { - CollectAllAsFirstSeen(in memorySnapshots, - out var allTensorAsFirstSeen, - out var allAllocatorAsFirstSeen, - out var allTensorDataAsFirstSeen, - out var allTempMemoriesAsFirstSeen); - - var summaryViews = GenerateSummaryViews(memorySnapshots, allTensorAsFirstSeen, allTensorDataAsFirstSeen, allTempMemoriesAsFirstSeen, out var memoryPeakSummary); - GenerateHeaderForSummaryViews(stringBuilder, summaryViews, spreadSheetFormat); - GenerateReportForViews(stringBuilder, summaryViews, spreadSheetFormat, "Tensors allocation and deallocation (diff from previous snapshot):", isSummaryView:true); - stringBuilder.Append("\n"); - stringBuilder.Append("\n"); - - var tensorViews = GenerateTensorsViews(memorySnapshots, allTensorAsFirstSeen); - GenerateHeaderForTensorViews(stringBuilder, tensorViews, spreadSheetFormat); - GenerateReportForViews(stringBuilder, tensorViews, spreadSheetFormat, "All Tensors:", isSummaryView:false); - stringBuilder.Append("\n"); - stringBuilder.Append("\n"); - - var allocatorViews = GenerateAllocatorViews(memorySnapshots, allAllocatorAsFirstSeen); - GenerateHeaderForAllocatorsViews(stringBuilder, allocatorViews, spreadSheetFormat); - GenerateReportForViews(stringBuilder, allocatorViews, spreadSheetFormat, "All Allocators:", isSummaryView:false); - stringBuilder.Append("\n"); - stringBuilder.Append("\n"); - - var tensorDatasViews = GenerateTensorDatasViews(memorySnapshots, allTensorDataAsFirstSeen); - GenerateHeaderForTensorDatasViews(stringBuilder, tensorDatasViews, spreadSheetFormat); - GenerateReportForViews(stringBuilder, tensorDatasViews, spreadSheetFormat, "All TensorDatas:", isSummaryView:false); - stringBuilder.Append("\n"); - stringBuilder.Append("\n"); - - var tempMemoriesDatasViews = GenerateTempMemoriesDatasViews(memorySnapshots, allTempMemoriesAsFirstSeen); - GenerateHeaderForTempMemoriesViews(stringBuilder, tempMemoriesDatasViews, spreadSheetFormat); - GenerateReportForViews(stringBuilder, tempMemoriesDatasViews, spreadSheetFormat, "All worker temporary memories:", isSummaryView:false); - stringBuilder.Append("\n"); - stringBuilder.Append("\n"); - - return memoryPeakSummary; - } - - #region `Internal data format` declaration - private class SnapshotFields - { - public readonly string[] Titles; - public readonly Dictionary Items; - - public SnapshotFields(string[] titles) - { - Titles = titles; - Items = new Dictionary(); - foreach (var title in titles) - { - Items[title] = ""; - } - } - - public string this[string title] - { - set { - Assert.IsTrue(Items.ContainsKey(title)); - Assert.IsTrue(Items[title] == ""); - Items[title] = value; - } - get => Items[title]; - } - - public void AddTitlesToReport(StringBuilder stringBuilder, string separator) - { - foreach (var title in Titles) - { - stringBuilder.Append(title); - stringBuilder.Append(separator); - } - } - - public void AddValuesToReport(StringBuilder stringBuilder, string separator) - { - foreach (var title in Titles) - { - stringBuilder.Append(Items[title]); - stringBuilder.Append(separator); - } - } - - public void AddAllToReport(StringBuilder stringBuilder, string suffix, string prefix="") - { - bool first = true; - foreach (var title in Titles) - { - if (!first) - stringBuilder.Append(suffix); - - stringBuilder.Append(prefix); - stringBuilder.Append(title); - stringBuilder.Append(": "); - stringBuilder.Append(Items[title]); - first = false; - } - } - } - - private class SnapshotFieldsWithContexts - { - public readonly string[] FieldTitles; - public readonly string[] ContextTitles; - public SortedDictionary Fields { get; } - public SortedDictionary Contexts { get; } - - public SnapshotFieldsWithContexts(string[] fieldsTitles, string[] contextTitles) - { - FieldTitles = fieldsTitles; - ContextTitles = contextTitles; - Contexts = new SortedDictionary(); - Fields = new SortedDictionary(); - } - - public void AddContext(int uniqueId) - { - Assert.IsFalse(Contexts.ContainsKey(uniqueId)); - Contexts[uniqueId] = new SnapshotFields(ContextTitles); - Fields[uniqueId] = new SnapshotFields(FieldTitles); - } - - public void SetContext(int uniqueId, string title, string value) - { - Assert.IsTrue(Contexts.ContainsKey(uniqueId)); - Contexts[uniqueId][title] = value; - } - - public string this[int uniqueId, string title] - { - set - { - Assert.IsTrue(Fields.ContainsKey(uniqueId)); - Fields[uniqueId][title] = value; - } - } - } - - private class SnapshotView - { - public SnapshotFields context; - public SnapshotFields summary; - public SnapshotFieldsWithContexts sections; - - public SnapshotView(int snapShotIndex, MemorySnapshotReport report) - { - context = new SnapshotFields( new [] {"Snapshot index", "Type", "Name"} ); - context["Snapshot index"] = snapShotIndex.ToString(); - context["Type"] = report.ContextType; - context["Name"] = report.ContextName; - } - - public SnapshotView(int snapShotIndex, LayerExecutionReport report) - { - context = new SnapshotFields( new [] {"Layer index", "Type", "Name"} ); - context["Layer index"] = snapShotIndex.ToString(); - context["Type"] = report.LayerType; - context["Name"] = report.LayerName; - } - } - #endregion - - #region Helpers to find information in Reports - - private static TempMemoryInfo FindTempMemoryInSnapshot(MemorySnapshotReport memorySnapshot, int tempMemoryId) - { - return memorySnapshot.TempMemoriesInfo.Find(memoryInfo => memoryInfo.UniqueId == tempMemoryId); - } - - private static AllocatorMemoryInfo FindAllocatorInSnapshot(MemorySnapshotReport memorySnapshot, int allocatorId) - { - return memorySnapshot.AllocatorsMemoryInfo.Find(memoryInfo => memoryInfo.UniqueId == allocatorId); - } - - - private static string FindTensorDataAllocatorInSnapshot(MemorySnapshotReport memorySnapshot, int tensorDataId) - { - foreach (var allocatorMemoryInfo in memorySnapshot.AllocatorsMemoryInfo) - { - var foundTensorData = allocatorMemoryInfo.TensorDatasMemoryInfo.Find(memoryInfo => memoryInfo.UniqueId == tensorDataId); - if (foundTensorData != null) - return $"{allocatorMemoryInfo.Name} / Id: {allocatorMemoryInfo.UniqueId}"; - } - return ""; - } - - private static TensorDataMemoryInfo FindTensorDataInSnapshot(MemorySnapshotReport memorySnapshot, int tensorDataId) - { - bool MatchTensorDataGuidForTensor(TensorMemoryInfo memoryInfo) => - memoryInfo.tensorDataMemoryInfo != null && memoryInfo.tensorDataMemoryInfo.UniqueId == tensorDataId; - - var foundTensor = memorySnapshot.TensorsMemoryInfo.Find(MatchTensorDataGuidForTensor); - if (foundTensor != null) - return foundTensor.tensorDataMemoryInfo; - - foreach (var allocatorMemoryInfo in memorySnapshot.AllocatorsMemoryInfo) - { - var foundTensorData = allocatorMemoryInfo.TensorDatasMemoryInfo.Find(memoryInfo => memoryInfo.UniqueId == tensorDataId); - if (foundTensorData != null) - return foundTensorData; - } - - return null; - } - - private static IEnumerable FindAllTensorsInSnapshotUsingTensorDataId(MemorySnapshotReport memorySnapshot, int tensorDataId) - { - SortedSet tensors = new SortedSet( Comparer.Create((a, b) => a.UniqueId.CompareTo(b.UniqueId))); - - var foundTensors = memorySnapshot.TensorsMemoryInfo.FindAll(memoryInfo => memoryInfo.tensorDataMemoryInfo != null && memoryInfo.tensorDataMemoryInfo.UniqueId == tensorDataId); - tensors.UnionWith(foundTensors); - - foreach (var allocatorMemoryInfo in memorySnapshot.AllocatorsMemoryInfo) - { - var allocatorFoundTensor = allocatorMemoryInfo.TensorsMemoryInfo.FindAll(memoryInfo => memoryInfo.tensorDataMemoryInfo != null && memoryInfo.tensorDataMemoryInfo.UniqueId == tensorDataId); - tensors.UnionWith(allocatorFoundTensor); - } - - return tensors; - } - - private static TensorMemoryInfo FindTensorInSnapshot(MemorySnapshotReport memorySnapshot, int tensorId) - { - var foundTensor = memorySnapshot.TensorsMemoryInfo.Find(memoryInfo => memoryInfo.UniqueId == tensorId); - if (foundTensor != null) - return foundTensor; - - foreach (var allocatorMemoryInfo in memorySnapshot.AllocatorsMemoryInfo) - { - foundTensor = allocatorMemoryInfo.TensorsMemoryInfo.Find(memoryInfo => memoryInfo.UniqueId == tensorId); - if (foundTensor != null) - return foundTensor; - } - - return null; - } - - private static void CollectAllAsFirstSeen(in List memorySnapshots, - out SortedDictionary tensors, - out SortedDictionary allocators, - out SortedDictionary tensorDatas, - out SortedDictionary tempMemories) - { - tensors = new SortedDictionary(); - allocators = new SortedDictionary(); - tensorDatas = new SortedDictionary(); - tempMemories = new SortedDictionary(); - - //Collect all unique tensors, tensors and allocator - foreach (var snapshot in memorySnapshots) - { - //From Vars - foreach (var tensor in snapshot.TensorsMemoryInfo) - { - tensors[tensor.UniqueId] = tensor; - if (tensor.tensorDataMemoryInfo != null) - tensorDatas[tensor.tensorDataMemoryInfo.UniqueId] = tensor.tensorDataMemoryInfo; - } - - //From allocators - foreach (var allocator in snapshot.AllocatorsMemoryInfo) - { - allocators[allocator.UniqueId] = allocator; - foreach (var tensor in allocator.TensorsMemoryInfo) - { - tensors[tensor.UniqueId] = tensor; - if (tensor.tensorDataMemoryInfo != null) - tensorDatas[tensor.tensorDataMemoryInfo.UniqueId] = tensor.tensorDataMemoryInfo; - } - - foreach (var tensorData in allocator.TensorDatasMemoryInfo) - { - tensorDatas[tensorData.UniqueId] = tensorData; - } - } - - //From temp memories - foreach (var tempMemoryInfo in snapshot.TempMemoriesInfo) - { - tempMemories[tempMemoryInfo.UniqueId] = tempMemoryInfo; - } - } - } - #endregion - - #region Reports -> internal data format - - private static List GenerateTempMemoriesDatasViews(List memorySnapshots, - SortedDictionary allTempMemoryInfosAsFirstSeen) - { - List views = new List(); - for (var memorySnapshotIndex = 0; memorySnapshotIndex < memorySnapshots.Count; memorySnapshotIndex++) - { - long allTotal = 0L; - var snapshot = memorySnapshots[memorySnapshotIndex]; - - //Titles and contexts - SnapshotView view = new SnapshotView(memorySnapshotIndex, snapshot); - view.sections = new SnapshotFieldsWithContexts( - fieldsTitles: new[] - { - "Allocated (bytes)", - "On GPU" - }, - contextTitles: new[] {"Name", "Id"}); - foreach (var tempMemoryInfo in allTempMemoryInfosAsFirstSeen) - { - var id = tempMemoryInfo.Key; - view.sections.AddContext(id); - view.sections.SetContext(id, "Name", tempMemoryInfo.Value.Name); - view.sections.SetContext(id, "Id", id.ToString()); - } - view.summary = new SnapshotFields(new[] - { - "Memory pressure in bytes (sum of all temp memory capacities)" - }); - - //Details - foreach (var alloc in allTempMemoryInfosAsFirstSeen) - { - var tempMemory = FindTempMemoryInSnapshot(snapshot, alloc.Key); - if (tempMemory != null) - { - allTotal += tempMemory.TotalBytes; - view.sections[tempMemory.UniqueId, "Allocated (bytes)"] = tempMemory.TotalBytes.ToString(); - view.sections[tempMemory.UniqueId, "On GPU"] = tempMemory.IsGPUMem ? "GPU" : "CPU"; - } - } - - //Summary - view.summary["Memory pressure in bytes (sum of all temp memory capacities)"] = allTotal.ToString(); - views.Add(view); - } - - return views; - } - - private static List GenerateAllocatorViews(List memorySnapshots, - SortedDictionary allAllocatorAsFirstSeen) - { - List views = new List(); - for (var memorySnapshotIndex = 0; memorySnapshotIndex < memorySnapshots.Count; memorySnapshotIndex++) - { - long allTotal = 0L; - long allBusy = 0L; - long allUsed = 0L; - long allFragmented = 0L; - long allFree = 0L; - var snapshot = memorySnapshots[memorySnapshotIndex]; - - //Titles and contexts - SnapshotView view = new SnapshotView(memorySnapshotIndex, snapshot); - view.sections = new SnapshotFieldsWithContexts( - fieldsTitles: new[] - { - "Memory pressure in bytes (sum of allocated tensorDatas capacities)", - "Busy bytes, for all allocators (sum of 'in use' tensorDatas capacities)", - "Needed bytes, for all allocators (sum of sizes of the part of the tensorDatas used by Tensors)", - "Unusable bytes, for all allocators (sum of the part of tensorData lost because of allocator fragmentation)", - "Ready bytes, for all allocators (sum of capacities of tensorData not used but allocated)" - }, - contextTitles: new[] {"Name", "Id"}); - foreach (var allocatorMemoryInfo in allAllocatorAsFirstSeen) - { - var id = allocatorMemoryInfo.Key; - view.sections.AddContext(id); - view.sections.SetContext(id, "Name", allocatorMemoryInfo.Value.Name); - view.sections.SetContext(id, "Id", id.ToString()); - } - view.summary = new SnapshotFields(new[] - { - "Memory pressure in bytes, for all allocators (sum of allocated tensorDatas capacities)", - "Busy bytes, for all allocators (sum of 'in use' tensorDatas capacities)", - "Needed bytes, for all allocators (sum of sizes of the part of the tensorDatas used by Tensors)", - "Unusable bytes, for all allocators (sum of the part of tensorData lost because of allocator fragmentation)", - "Ready bytes, for all allocators (sum of capacities of tensorData not used but allocated)" - }); - - //Details - foreach (var alloc in allAllocatorAsFirstSeen) - { - var allocator = FindAllocatorInSnapshot(snapshot, alloc.Key); - if (allocator != null) - { - allTotal += allocator.TotalBytes; - allBusy += allocator.BusyBytes; - allUsed += allocator.UsedBytes; - allFragmented += allocator.BusyBytes-allocator.UsedBytes; - allFree += allocator.FreeBytes; - view.sections[allocator.UniqueId, "Memory pressure in bytes (sum of allocated tensorDatas capacities)"] = allocator.TotalBytes.ToString(); - view.sections[allocator.UniqueId, "Busy bytes, for all allocators (sum of 'in use' tensorDatas capacities)"] = allocator.BusyBytes.ToString(); - view.sections[allocator.UniqueId, "Needed bytes, for all allocators (sum of sizes of the part of the tensorDatas used by Tensors)"] = allocator.UsedBytes.ToString(); - view.sections[allocator.UniqueId, "Unusable bytes, for all allocators (sum of the part of tensorData lost because of allocator fragmentation)"] = allocator.BytesLostToFragmentation.ToString(); - view.sections[allocator.UniqueId, "Ready bytes, for all allocators (sum of capacities of tensorData not used but allocated)"] = allocator.FreeBytes.ToString(); - } - } - - //Summary - view.summary["Memory pressure in bytes, for all allocators (sum of allocated tensorDatas capacities)"] = allTotal.ToString(); - view.summary["Busy bytes, for all allocators (sum of 'in use' tensorDatas capacities)"] = allBusy.ToString(); - view.summary["Needed bytes, for all allocators (sum of sizes of the part of the tensorDatas used by Tensors)"] = allUsed.ToString(); - view.summary["Unusable bytes, for all allocators (sum of the part of tensorData lost because of allocator fragmentation)"] = allFragmented.ToString(); - view.summary["Ready bytes, for all allocators (sum of capacities of tensorData not used but allocated)"] = allFree.ToString(); - views.Add(view); - } - - return views; - } - - private static List GenerateTensorDatasViews(List memorySnapshots, - SortedDictionary allTensorDataAsFirstSeen) - { - List views = new List(); - for (var memorySnapshotIndex = 0; memorySnapshotIndex < memorySnapshots.Count; memorySnapshotIndex++) - { - long allGPUInBytes = 0L; - long allCPUInBytes = 0L; - long allUsedGPUInBytes = 0L; - long allUsedCPUInBytes = 0L; - long allFragmentedMemGPUInBytes = 0L; - long allFragmentedMemCPUInBytes = 0L; - - var snapshot = memorySnapshots[memorySnapshotIndex]; - - //Titles and contexts - SnapshotView view = new SnapshotView(memorySnapshotIndex, snapshot); - view.sections = new SnapshotFieldsWithContexts( - fieldsTitles: new[] - { - "In use", "Capacity (bytes)", "On GPU", "Allocator", - "Tensor(s) Id(s)", "Tensor(s) max bytes", "Fragmented bytes" - }, - contextTitles: new[] {"Id"}); - foreach (var tensorData in allTensorDataAsFirstSeen) - { - var id = tensorData.Key; - view.sections.AddContext(id); - view.sections.SetContext(id, "Id", id.ToString()); - } - view.summary = new SnapshotFields(new[] - { - "GPU sum of all allocated tensorData capacities (bytes)", - "CPU sum of all allocated tensorData capacities (bytes)", - "GPU sum of all 'in use' tensorData (bytes)", - "CPU sum of all 'in use' tensorData (bytes)", - "GPU sum of all 'fragmented' tensorData mem ('in use' but not by large enough tensors) (bytes)", - "CPU sum of all 'fragmented' tensorData mem ('in use' but not by large enough tensors) (bytes)", - }); - - foreach (var tData in allTensorDataAsFirstSeen) - { - TensorDataMemoryInfo tensorData = FindTensorDataInSnapshot(snapshot, tData.Key); - if (tensorData != null) - { - var associatedTensors = FindAllTensorsInSnapshotUsingTensorDataId(snapshot, tensorData.UniqueId); - string tensorNamesandIds = ""; - int tensorBytes = 0; - bool first = true; - foreach (var tensor in associatedTensors) - { - if (!first) - tensorNamesandIds += " / "; - tensorNamesandIds += tensor.Name + " Id:" + tensor.UniqueId; - first = false; - tensorBytes = Math.Max(tensorBytes, tensor.Shape.length * sizeof(float)); - } - int fragmentedTensorDataBytes = (tensorData.InUse) ? tensorData.MaxBytes - tensorBytes : 0; - - if (tensorData.IsGPUMem) - { - allGPUInBytes += tensorData.MaxBytes; - if (tensorData.InUse) - { - allFragmentedMemGPUInBytes += fragmentedTensorDataBytes; - allUsedGPUInBytes += tensorData.MaxBytes; - } - } - else - { - allCPUInBytes += tensorData.MaxBytes; - if (tensorData.InUse) - { - allFragmentedMemCPUInBytes += fragmentedTensorDataBytes; - allUsedCPUInBytes += tensorData.MaxBytes; - } - } - - view.sections[tensorData.UniqueId, "In use"] = tensorData.InUse ? "Yes" : ""; - view.sections[tensorData.UniqueId, "Capacity (bytes)"] = tensorData.MaxBytes.ToString(); - view.sections[tensorData.UniqueId, "On GPU"] = tensorData.IsGPUMem ? "GPU" : "CPU"; - view.sections[tensorData.UniqueId, "Allocator"] = FindTensorDataAllocatorInSnapshot(snapshot, tensorData.UniqueId); - view.sections[tensorData.UniqueId, "Tensor(s) Id(s)"] = tensorNamesandIds; - view.sections[tensorData.UniqueId, "Tensor(s) max bytes"] = tensorBytes.ToString(); - view.sections[tensorData.UniqueId, "Fragmented bytes"] = fragmentedTensorDataBytes.ToString(); - } - } - - //Summary - view.summary["GPU sum of all allocated tensorData capacities (bytes)"] = allGPUInBytes.ToString(); - view.summary["CPU sum of all allocated tensorData capacities (bytes)"] = allCPUInBytes.ToString(); - view.summary["GPU sum of all 'in use' tensorData (bytes)"] = allUsedGPUInBytes.ToString(); - view.summary["CPU sum of all 'in use' tensorData (bytes)"] = allUsedCPUInBytes.ToString(); - view.summary["GPU sum of all 'fragmented' tensorData mem ('in use' but not by large enough tensors) (bytes)"] = allFragmentedMemGPUInBytes.ToString(); - view.summary["CPU sum of all 'fragmented' tensorData mem ('in use' but not by large enough tensors) (bytes)"] = allFragmentedMemCPUInBytes.ToString(); - views.Add(view); - } - - return views; - } - - private static List GenerateTensorsViews(List memorySnapshots, - SortedDictionary allTensorAsFirstSeen) - { - List views = new List(); - for (var memorySnapshotIndex = 0; memorySnapshotIndex < memorySnapshots.Count; memorySnapshotIndex++) - { - var snapshot = memorySnapshots[memorySnapshotIndex]; - - //Titles and contexts - SnapshotView view = new SnapshotView(memorySnapshotIndex, snapshot); - view.sections = new SnapshotFieldsWithContexts( - fieldsTitles: new[] {"Allocated (bytes)", "Name", "Shape", "Cache size (bytes)", "TensorData Id", "TensorData Capacity (bytes)"}, - contextTitles: new[] {"Id"}); - foreach (var tensorMemoryInfo in allTensorAsFirstSeen) - { - var id = tensorMemoryInfo.Key; - view.sections.AddContext(id); - view.sections.SetContext(id, "Id", id.ToString()); - } - view.summary = new SnapshotFields(new[] - { - "Tensor memory on GPU (in bytes)", - "Tensor memory on CPU (in bytes)", - "On CPU tensor cache (in bytes)" - }); - - //Details - long cacheMemInBytes = 0L; - long gpuMem = 0L; - long cpuMem = 0L; - foreach (var tensorFromDict in allTensorAsFirstSeen) - { - var tensor = FindTensorInSnapshot(snapshot, tensorFromDict.Key); - if (tensor != null) - { - cacheMemInBytes += tensor.CacheBytes; - var dataBytes = tensor.Shape.length * sizeof(float); - - string allocatedStr = "Yes"; - if (tensor.tensorDataMemoryInfo != null) - { - allocatedStr += $" ({(tensor.Shape.length * sizeof(float)).ToString()})"; - view.sections[tensor.UniqueId, "TensorData Id"] = tensor.tensorDataMemoryInfo.UniqueId.ToString(); - view.sections[tensor.UniqueId, "TensorData Capacity (bytes)"] = tensor.tensorDataMemoryInfo.MaxBytes.ToString(); - if (tensor.tensorDataMemoryInfo.IsGPUMem) - gpuMem += dataBytes; - else - cpuMem += dataBytes; - } - else - { - allocatedStr += " (0)"; - } - view.sections[tensor.UniqueId, "Name"] = tensor.Name; - view.sections[tensor.UniqueId, "Shape"] = tensor.Shape.ToString(); - view.sections[tensor.UniqueId, "Cache size (bytes)"] = tensor.CacheBytes.ToString(); - view.sections[tensor.UniqueId, "Allocated (bytes)"] = allocatedStr; - } - } - - //Summary - view.summary["Tensor memory on GPU (in bytes)"] = gpuMem.ToString(); - view.summary["Tensor memory on CPU (in bytes)"] = cpuMem.ToString(); - view.summary["On CPU tensor cache (in bytes)"] = cacheMemInBytes.ToString(); - views.Add(view); - } - - return views; - } - - private static List GenerateExecutionViews(List layerReports, int numCompletedLayer) - { - List views = new List(); - for (var layerIndex = 0; layerIndex < layerReports.Count; layerIndex++) - { - var report = layerReports[layerIndex]; - - //Titles - SnapshotView view = new SnapshotView(layerIndex, report); - view.sections = new SnapshotFieldsWithContexts(null, null); - view.summary = new SnapshotFields(new[] - { - "Summary", - "Compute Kernels(workItems:X,Y,Z)", - "Theoretical ALU count", - "Theoretical Bandwidth (bytes)", - "Note" - }); - - //Summary - view.summary["Summary"] = report.Summary==""?"NA":report.Summary; - view.summary["Compute Kernels(workItems:X,Y,Z)"] = report.DispatchInfos; - view.summary["Theoretical ALU count"] = report.NumAlu.ToString(); - view.summary["Theoretical Bandwidth (bytes)"] = report.NumBytes.ToString(); - if (layerIndex >= numCompletedLayer) - view.summary["Note"] = "UNCOMPLETED LAYER"; - views.Add(view); - } - - return views; - } - - private static List GenerateSummaryViews(List memorySnapshots, - SortedDictionary allTensorsAsFirstSeen, - SortedDictionary allTensorDatasAsFirstSeen, - SortedDictionary allTempMemoriesAsFirstSeen, - out MemoryPeakSummary memoryPeakSummary) - { - HashSet previousSnapshotTensorIds = new HashSet(); - List views = new List(); - - long peakMemoryUsageGPU = 0; - long peakMemoryUsageCPU = 0; - long peakMemoryUsageGPUAndCPU = 0; - - for (var memorySnapshotIndex = 0; memorySnapshotIndex < memorySnapshots.Count; memorySnapshotIndex++) - { - var snapshot = memorySnapshots[memorySnapshotIndex]; - - //Titles and contexts - SnapshotView view = new SnapshotView(memorySnapshotIndex, snapshot); - view.sections = new SnapshotFieldsWithContexts( - fieldsTitles: new[] {"Allocated", "Released"}, - contextTitles: new[] {"Type" }); - view.sections.AddContext(0); - view.sections.SetContext(0, "Type", "Tensor"); - view.summary = new SnapshotFields(new[] - { - "Total memory pressure on GPU (in bytes)", - "Total memory pressure on CPU (in bytes)", - "On CPU tensor cache (in bytes)" - }); - - //Summary - HashSet currentSnapshotTensorIds = new HashSet(); - long cacheMemInBytes = 0L; - foreach (var tensor in snapshot.TensorsMemoryInfo) - { - cacheMemInBytes += tensor.CacheBytes; - currentSnapshotTensorIds.Add(tensor.UniqueId); - } - long gpuMem = 0L; - long cpuMem = 0L; - foreach (var tData in allTensorDatasAsFirstSeen) - { - TensorDataMemoryInfo tensorData = FindTensorDataInSnapshot(snapshot, tData.Key); - if (tensorData != null) - { - if (tensorData.IsGPUMem) - gpuMem += tensorData.MaxBytes; - else - cpuMem += tensorData.MaxBytes; - } - } - foreach (var mData in allTempMemoriesAsFirstSeen) - { - TempMemoryInfo tempMemoryInfo = FindTempMemoryInSnapshot(snapshot, mData.Key); - if (tempMemoryInfo != null) - { - if (tempMemoryInfo.IsGPUMem) - gpuMem += tempMemoryInfo.TotalBytes; - else - cpuMem += tempMemoryInfo.TotalBytes; - } - } - view.summary["Total memory pressure on GPU (in bytes)"] = gpuMem.ToString(); - view.summary["Total memory pressure on CPU (in bytes)"] = cpuMem.ToString(); - view.summary["On CPU tensor cache (in bytes)"] = cacheMemInBytes.ToString(); - - peakMemoryUsageGPU = Math.Max(peakMemoryUsageGPU, gpuMem); - peakMemoryUsageCPU = Math.Max(peakMemoryUsageCPU, cpuMem); - peakMemoryUsageGPUAndCPU = Math.Max(peakMemoryUsageGPUAndCPU, gpuMem+cpuMem); - - if (memorySnapshotIndex != 0) - { - //Tensor allocated and freed (diff from snapshot to snapshot) - var allocatedTensorsId = currentSnapshotTensorIds.Except(previousSnapshotTensorIds); - var releasedTensorsId = previousSnapshotTensorIds.Except(currentSnapshotTensorIds); - StringBuilder tensorDiff = new StringBuilder(); - bool first = true; - foreach (var tensorId in allocatedTensorsId) - { - var tensor = FindTensorInSnapshot(snapshot, tensorId); - string tensorDataInfo = "none"; - if (tensor.tensorDataMemoryInfo != null) - { - var data = tensor.tensorDataMemoryInfo; - var memType = data.IsGPUMem ? "GPU" : "CPU"; - tensorDataInfo = $"id:{data.UniqueId} bytes:{data.MaxBytes} on:{memType}"; - } - if (!first) tensorDiff.Append(" / "); - first = false; - tensorDiff.Append($"{tensor.Name} {tensor.Shape} id:{tensor.UniqueId} tensorData:[{tensorDataInfo}]"); - - } - view.sections[0, "Allocated"] = tensorDiff.ToString(); - tensorDiff.Clear(); - - first = true; - foreach (var tensorId in releasedTensorsId) - { - var tensor = allTensorsAsFirstSeen[tensorId]; - if (!first) tensorDiff.Append(" / "); - first = false; - tensorDiff.Append($"{tensor.Name} {tensor.Shape} id:{tensor.UniqueId}"); - } - view.sections[0, "Released"] = tensorDiff.ToString(); - } - - views.Add(view); - previousSnapshotTensorIds = currentSnapshotTensorIds; - } - - memoryPeakSummary = new MemoryPeakSummary(peakMemoryUsageGPU, peakMemoryUsageCPU, peakMemoryUsageGPUAndCPU); - return views; - } - - #endregion - - #region Internal data format -> text - - private static void Append(this StringBuilder sb, string str, int repeatCount) - { - for (int i = 0; i < repeatCount; ++i) - sb.Append(str); - } - - private static void Append(this StringBuilder sb, string str, string separator) - { - sb.Append(str); - sb.Append(separator); - } - - private static void GenerateReportForViews(StringBuilder stringBuilder, List views, bool spreadSheetFormat, string sectionTitle, bool isSummaryView) - { - if (spreadSheetFormat) - { - //Columns Titles - views[0].context.AddTitlesToReport(stringBuilder, ModelExecutionsReporter.SpreadSheetFieldSeparator); - views[0].summary.AddTitlesToReport(stringBuilder, ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - foreach (var tensorFields in views[0].sections.Fields) - { - tensorFields.Value.AddTitlesToReport(stringBuilder, ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - } - stringBuilder.Append("\n"); - - //All snapshots - foreach (var view in views) - { - view.context.AddValuesToReport(stringBuilder, ModelExecutionsReporter.SpreadSheetFieldSeparator); - view.summary.AddValuesToReport(stringBuilder, ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - foreach (var tensorFields in view.sections.Fields) - { - tensorFields.Value.AddValuesToReport(stringBuilder, ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - } - stringBuilder.Append("\n"); - } - - } - else - { - string doubleIndentation = ModelExecutionsReporter.TextIndentation + ModelExecutionsReporter.TextIndentation; - - foreach (var view in views) - { - view.context.AddAllToReport(stringBuilder, ModelExecutionsReporter.TextFormatFieldSeparator); - stringBuilder.Append("\n"); - view.summary.AddAllToReport(stringBuilder, suffix:"\n", prefix: ModelExecutionsReporter.TextIndentation); - stringBuilder.Append("\n"+ModelExecutionsReporter.TextIndentation + sectionTitle +"\n"); - - foreach (var context in view.sections.Contexts) - { - stringBuilder.Append(doubleIndentation); - if (isSummaryView) - { - view.sections.Fields[context.Key].AddAllToReport(stringBuilder, "\n"+doubleIndentation); - } - else - { - context.Value.AddAllToReport(stringBuilder, ModelExecutionsReporter.TextFormatFieldSeparator); - stringBuilder.Append("\n"+doubleIndentation +"=> "); - view.sections.Fields[context.Key].AddAllToReport(stringBuilder, ModelExecutionsReporter.TextFormatFieldSeparator); - stringBuilder.Append("\n"); - } - } - stringBuilder.Append("\n"); - } - } - } - - private static void GenerateHeaderForSummaryViews(StringBuilder stringBuilder, List views, bool spreadSheetFormat) - { - if (views.Count == 0) - { - stringBuilder.Append("<******** Summary info ********> NONE!\n"); - return; - } - - if (!spreadSheetFormat) - { - stringBuilder.Append("<******** Summary info ********>\n"); - return; - } - - //Columns names - int ctxFieldCount = views[0].context.Titles.Length + views[0].summary.Titles.Length; - int sectionFieldCount = views[0].sections.FieldTitles.Length; - - stringBuilder.Append("<******** Summary info ********>"); - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, ctxFieldCount); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - foreach (var context in views[0].sections.Contexts) - { - stringBuilder.Append(context.Value["Type"], ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, sectionFieldCount-1); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - } - stringBuilder.Append("\n"); - } - - private static void GenerateHeaderForTensorViews(StringBuilder stringBuilder, List views, bool spreadSheetFormat) - { - GenerateHeaderForViewsByID(stringBuilder, views, spreadSheetFormat, "Tensors"); - } - - private static void GenerateHeaderForTensorDatasViews(StringBuilder stringBuilder, List views, bool spreadSheetFormat) - { - GenerateHeaderForViewsByID(stringBuilder, views, spreadSheetFormat, "TensorDatas"); - } - - private static void GenerateHeaderForViewsByID(StringBuilder stringBuilder, List views, bool spreadSheetFormat, string dataType) - { - if (views.Count == 0) - { - stringBuilder.Append($"<******** {dataType} info ********> NONE!\n"); - return; - } - - if (!spreadSheetFormat) - { - stringBuilder.Append($"<******** {dataType} info ********>\n"); - return; - } - - //Columns names - int ctxFieldCount = views[0].context.Titles.Length + views[0].summary.Titles.Length; - int sectionFieldCount = views[0].sections.FieldTitles.Length; - - stringBuilder.Append($"<******** {dataType} info ********>"); - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, ctxFieldCount); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - foreach (var context in views[0].sections.Contexts) - { - stringBuilder.Append("Id: "); - stringBuilder.Append(context.Value["Id"], ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, sectionFieldCount-1); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - } - stringBuilder.Append("\n"); - } - - private static void GenerateHeaderForTempMemoriesViews(StringBuilder stringBuilder, List views, bool spreadSheetFormat) - { - if (views.Count == 0) - { - stringBuilder.Append("<******** Worker temporary memories info ********> NONE!\n"); - return; - } - - if (!spreadSheetFormat) - { - stringBuilder.Append("<******** Worker temporary memories info ********>\n"); - return; - } - - //Columns names - int ctxFieldCount = views[0].context.Titles.Length + views[0].summary.Titles.Length; - int sectionFieldCount = views[0].sections.FieldTitles.Length; - - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, ctxFieldCount); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append("Temp memories names and ids:"); - stringBuilder.Append("\n"); - - stringBuilder.Append("<******** Worker temporary memories info ********>"); - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, ctxFieldCount); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - foreach (var context in views[0].sections.Contexts) - { - stringBuilder.Append(context.Value["Name"], " / Id: "); - stringBuilder.Append(context.Value["Id"], ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, sectionFieldCount-1); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - } - stringBuilder.Append("\n"); - } - - private static void GenerateHeaderForAllocatorsViews(StringBuilder stringBuilder, List views, bool spreadSheetFormat) - { - if (views.Count == 0) - { - stringBuilder.Append("<******** Allocators info ********> NONE!\n"); - return; - } - - if (!spreadSheetFormat) - { - stringBuilder.Append("<******** Allocators info ********>\n"); - return; - } - - //Columns names - int ctxFieldCount = views[0].context.Titles.Length + views[0].summary.Titles.Length; - int sectionFieldCount = views[0].sections.FieldTitles.Length; - - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, ctxFieldCount); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append("Allocators names and shapes:"); - stringBuilder.Append("\n"); - - stringBuilder.Append("<******** Allocators info ********>"); - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, ctxFieldCount); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - foreach (var context in views[0].sections.Contexts) - { - stringBuilder.Append(context.Value["Name"], " / Id: "); - stringBuilder.Append(context.Value["Id"], ModelExecutionsReporter.SpreadSheetFieldSeparator); - stringBuilder.Append(ModelExecutionsReporter.SpreadSheetFieldSeparator, sectionFieldCount-1); - stringBuilder.Append("|", ModelExecutionsReporter.SpreadSheetFieldSeparator); - } - stringBuilder.Append("\n"); - } - - #endregion -} - -} // namespace Unity.Barracuda - -#endif //ENABLE_BARRACUDA_STATS diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/MemoryAndExecutionReportHelper.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/MemoryAndExecutionReportHelper.cs.meta deleted file mode 100644 index 2abf269..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/MemoryAndExecutionReportHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5b125a79bdbfb1b41adba78ef255dd80 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/MemorySnapshotsReport.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/MemorySnapshotsReport.cs deleted file mode 100644 index ccc36b7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/MemorySnapshotsReport.cs +++ /dev/null @@ -1,196 +0,0 @@ -#if ENABLE_BARRACUDA_STATS - -using System.Collections.Generic; -using System.Text; - -namespace Unity.Barracuda { - -public class TensorDataMemoryInfo -{ - public int UniqueId { get; } - public int MaxBytes { get; } - public bool InUse { get; } - public bool IsGPUMem { get; } - - internal TensorDataMemoryInfo(ITensorDataStatistics tensorDataStatistics) - { - UniqueId = tensorDataStatistics.uniqueId; - MaxBytes = tensorDataStatistics.maxCapacity * sizeof(float); - InUse = tensorDataStatistics.inUse; - IsGPUMem = tensorDataStatistics.isGPUMem; - } - - public override string ToString() - { - return $"TensorData of maxBytes {MaxBytes}, inUse:{InUse}, onGPU:{IsGPUMem}, uniqueId:{UniqueId}"; - } -} - -public class TempMemoryInfo -{ - public int UniqueId { get; } - public string Name { get; } - public long TotalBytes { get; } - public bool IsGPUMem { get; } - - internal TempMemoryInfo(TempMemoryStatistics tempMemoryStatistics) - { - UniqueId = tempMemoryStatistics.uniqueId; - Name = tempMemoryStatistics.name; - TotalBytes = tempMemoryStatistics.size; - IsGPUMem = tempMemoryStatistics.isGPUMem; - } - - public override string ToString() - { - return $"Temp memory '{Name}' of totalBytes {TotalBytes}"; - } -} - -public class AllocatorMemoryInfo -{ - public int UniqueId { get; } - public string Name { get; } - public long UsedBytes { get; } - public long BusyBytes { get; } - public long FreeBytes { get; } - public long TotalBytes { get; } - public List TensorDatasMemoryInfo { get; } - public List TensorsMemoryInfo { get; } - public long BytesLostToFragmentation => BusyBytes - UsedBytes; - - internal AllocatorMemoryInfo(IAllocatorStatistics allocatorStatistics) - { - UniqueId = allocatorStatistics.uniqueId; - Name = allocatorStatistics.name; - UsedBytes = allocatorStatistics.usedBytes; - BusyBytes = allocatorStatistics.busyBytes; - FreeBytes = allocatorStatistics.freeBytes; - TotalBytes = allocatorStatistics.totalBytes; - TensorDatasMemoryInfo = new List(); - foreach (var tensorDataStatistics in allocatorStatistics.GetTensorDatasStatistics()) - { - TensorDatasMemoryInfo.Add(new TensorDataMemoryInfo(tensorDataStatistics)); - } - TensorsMemoryInfo = new List(); - foreach (var tensorStatistics in allocatorStatistics.GetTensorsStatistics()) - { - TensorsMemoryInfo.Add(new TensorMemoryInfo(tensorStatistics)); - } - } - - public override string ToString() - { - return $"Allocator '{Name}' of totalBytes {TotalBytes}, usedBytes:{UsedBytes}, lostToFragmentation:{BytesLostToFragmentation}, free:{FreeBytes}"; - } -} - -public class TensorMemoryInfo -{ - public int UniqueId { get; } - public string Name { get; } - public TensorShape Shape { get; } - public int CacheBytes { get; } - public TensorDataMemoryInfo tensorDataMemoryInfo { get; } - - internal TensorMemoryInfo(ITensorStatistics tensorStatistics) - { - UniqueId = tensorStatistics.uniqueId; - Name = tensorStatistics.name; - Shape = tensorStatistics.shape; - CacheBytes = tensorStatistics.cacheBytes; - var tensorDataStats = tensorStatistics.GetTensorDataStatistics(); - if (tensorDataStats != null) - tensorDataMemoryInfo = new TensorDataMemoryInfo(tensorDataStats); - } - - public override string ToString() - { - var tensorDataStr = (tensorDataMemoryInfo != null) ? tensorDataMemoryInfo.ToString() : ""; - return $"Tensor: {Name} of shape {Shape.ToString()}, cacheBytes: {CacheBytes} (data: {tensorDataStr})"; - } -} - -public class MemorySnapshotReport -{ - public string ContextType { get; } - public string ContextName { get; } - public List TensorsMemoryInfo { get; } - public List AllocatorsMemoryInfo { get; } - public List TempMemoriesInfo { get; } - - internal MemorySnapshotReport(IOps ops, IVarsStatistics vars, string context, Layer layer) - { - ContextType = context; - ContextName = ""; - if (layer != null) - { - ContextType += ": " + layer.type + ((layer.type == Layer.Type.Activation) ? ("." + layer.activation) : ""); - ContextName += layer.name; - } - - TensorsMemoryInfo = new List(); - AllocatorsMemoryInfo = new List(); - TempMemoriesInfo = new List(); - - foreach (var allocatorsStatistic in vars.GetAllocatorsStatistics()) - { - AllocatorsMemoryInfo.Add(new AllocatorMemoryInfo(allocatorsStatistic)); - } - - foreach (var tensorStatistic in vars.GetTensorsStatistics()) - { - TensorsMemoryInfo.Add(new TensorMemoryInfo(tensorStatistic)); - } - - foreach (var tempMemoryStatistic in ops.GetTempMemoryStatistics()) - { - TempMemoriesInfo.Add(new TempMemoryInfo(tempMemoryStatistic)); - } - } -} - -public class MemorySnapshotsReport -{ - public List MemorySnapshotsReports { get; private set; } - - public MemorySnapshotsReport() - { - Reset(); - } - - public void Reset() - { - MemorySnapshotsReports = new List(); - } - - public void TakeMemorySnapshot(IOps ops, IVars vars, string context, Layer layer) - { - var varsWithStatistics = vars as IVarsStatistics; - if (varsWithStatistics == null) - return; - - MemorySnapshotsReports.Add(new MemorySnapshotReport(ops, varsWithStatistics, context, layer)); - } - - public MemoryPeakSummary GenerateStringReport(StringBuilder stringBuilder, bool spreadSheetFormat) - { - stringBuilder.Append("**************** MEMORY SNAPSHOTS REPORTS - START ****************\n"); - stringBuilder.Append($"Number of snapshots : {MemorySnapshotsReports.Count}\n\n"); - - var memoryPeakSummary = MemoryAndExecutionReportHelper.GenerateStringReport(stringBuilder, MemorySnapshotsReports, spreadSheetFormat); - stringBuilder.Append("**************** MEMORY SNAPSHOTS REPORTS - STOP ****************\n"); - return memoryPeakSummary; - } - - public override string ToString() - { - var stringBuilder = new StringBuilder(10000); - GenerateStringReport(stringBuilder, spreadSheetFormat:false); - return stringBuilder.ToString(); - } -} - -} // namespace Unity.Barracuda - -#endif //ENABLE_BARRACUDA_STATS diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/MemorySnapshotsReport.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/MemorySnapshotsReport.cs.meta deleted file mode 100644 index 1a94992..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/MemorySnapshotsReport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0e26059fb46b5a345a0a59a9fe3eafae -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelAnalyzer.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelAnalyzer.cs deleted file mode 100644 index 64ea1d4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelAnalyzer.cs +++ /dev/null @@ -1,922 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; - -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; - -[assembly: InternalsVisibleTo("Unity.Barracuda.ONNX")] -[assembly: InternalsVisibleTo("Unity.Barracuda.Editor")] - -namespace Unity.Barracuda { - - -internal class ModelAnalyzer -{ - public static string GetDefaultInputName(Model model) - { - bool modelHasOnlyOneInput = model.inputs.Count == 1; - if (modelHasOnlyOneInput) - return model.inputs[0].name; - - var memories = new HashSet(); - foreach (var m in model.memories) - memories.Add(m.input); - - // find the first unconnected input as a default model input - var previousLayerNames = new HashSet(); - foreach (var l in model.layers) - { - previousLayerNames.Add(l.name); - - bool layerDoesNotNeedInput = (l.type == Layer.Type.Load); - - if (layerDoesNotNeedInput) - continue; - - foreach (var inputName in l.inputs) - { - bool inputIsUnconnected = !previousLayerNames.Contains(inputName); - bool inputIsNotPartOfMemory = !memories.Contains(inputName); - - if (inputIsUnconnected && inputIsNotPartOfMemory) - return inputName; - } - } - - return ""; - } - - static public string GetDefaultOutputName(Model model) - { - if (model.outputs.Count == 1) - return model.outputs[0]; - - if (model.layers.Count > 0) - { - var lastLayer = model.layers[model.layers.Count - 1]; - return lastLayer.name; - } - - return ""; - } - - public static TensorShape?[] ListTemporaryTensorShapes(Model model, IDictionary inputShapes) - { - IDictionary shapesByName; - return ListTemporaryTensorShapes(model, inputShapes, out shapesByName); - } - - public static TensorShape?[] ListTemporaryTensorShapes(Model model, IDictionary inputShapes, - out IDictionary shapesByName) - { - Profiler.BeginSample ("Barracuda.ListTemporaryTensorShapes"); - var shapes = new List(); - shapesByName = new Dictionary(); - foreach (var entry in inputShapes) - shapesByName.Add(entry.Key, entry.Value); - - TensorShape? Xn; - shapesByName.TryGetValue(GetDefaultInputName(model), out Xn); // default input - TensorShape? O = Xn; - - foreach (var l in model.layers) - { - if (l.inputs.Length > 0 && shapesByName.TryGetValue(l.inputs[0], out TensorShape? xShape)) - Xn = xShape; - else - Xn = O; // previous output is used, if-and-only-if layer has no explicit inputs - - if (Xn == null) - { - shapes.Add(Xn); - shapesByName.Add(l.name, Xn); - continue; - } - - TensorShape X = Xn.Value; - - if (l.type == Layer.Type.Dense) - { - Assert.IsNotNull(l.datasets); - var W = l.datasets[0].shape; - O = new TensorShape(X.flatHeight, W.flatWidth); - } - else if (l.type == Layer.Type.Dense3) - { - Assert.IsNotNull(l.datasets); - var W = l.datasets[0].shape; - O = new TensorShape(X.batch, 1, W.channels, X.channels); - } - else if (l.type == Layer.Type.MatMul) - { - if (!shapesByName.ContainsKey(l.inputs[1]) || shapesByName[l.inputs[1]] == null) - { - O = null; - break; - } - - var Y = shapesByName[l.inputs[1]].Value; - - int rankX; - int rankY; - List onnxXshape; - List onnxYshape; - - if (l.pool == null || l.pool.Length == 0) - { - LegacyGetXYRanks(X, Y, out rankX, out rankY); - } - else - { - rankX = l.pool[0]; - rankY = l.pool[1]; - } - - onnxXshape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToOnnxLayout(X, rankX); - onnxYshape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToOnnxLayout(Y, rankY); - - int rankO = Math.Max(rankX, rankY); - - // pad 1 on front of shape to both be rankO shape - for (int i = 0; i < (rankX - rankY); i++) - onnxYshape.Insert(0, 1); - - for (int i = 0; i < (rankY - rankX); i++) - onnxXshape.Insert(0, 1); - - if (rankO == 2) - O = new TensorShape(onnxXshape[0], 1, 1, onnxYshape[1]); - else if (rankO == 3) - O = new TensorShape(Math.Max(onnxXshape[0], onnxYshape[0]), 1, onnxYshape[2], onnxXshape[1]); - else - O = new TensorShape(Math.Max(onnxXshape[0], onnxYshape[0]), onnxXshape[2], onnxYshape[3], Math.Max(onnxXshape[1], onnxYshape[1])); - } - else if ( - l.type == Layer.Type.Conv2D || - l.type == Layer.Type.Conv3D || - l.type == Layer.Type.DepthwiseConv2D) - { - var K = l.datasets[0].shape; - - Assert.IsNotNull(l.stride); - Assert.IsNotNull(l.pad); - var pad = X.AdjustPadToKernel(K, l.stride, l.pad); - - O = X.ApplyKernel(K, l.stride, pad); - } - else if ( - l.type == Layer.Type.Conv2DTrans) - { - var K = l.datasets[0].shape; - Assert.IsNotNull(l.stride); - Assert.IsNotNull(l.pad); - // pool size is treated as output_adjustment aka output_padding here - var outputAdjustment = l.pool; - var pad = X.AdjustPadToKernel(K, l.stride, l.pad); - O = X.ApplyKernelInverse(K, l.stride, pad, outputAdjustment); - } - else if ( - l.type == Layer.Type.Upsample2D) - { - if(l.pool.Length != 2) - { - O = null; - } - else - { - // pool size is treated as upsample coefficient here - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 2); - O = new TensorShape(X.batch, X.height * l.pool[1], X.width * l.pool[0], X.channels); - } - } - else if ( - l.type == Layer.Type.Upsample3D) - { - if(l.pool.Length != 2) - { - O = null; - } - else - { - // pool size is treated as upsample coefficient here - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 3); - O = new TensorShape(1,1,X.batch, 1, X.depth * l.pool[2], X.height * l.pool[1], X.width * l.pool[0], X.channels); - } - } - else if ( - l.type == Layer.Type.Resample2D) - { - if(l.pool.Length != 2) - { - O = null; - } - else - { - // pool is treated as resample size here - var size = l.pool; - Assert.IsNotNull(size); - Assert.AreEqual(size.Length, 2); - O = new TensorShape(X.batch, size[1], size[0], X.channels); - } - } - else if ( - l.type == Layer.Type.DepthToSpace) - { - // pool size is treated as blocksize here - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 2); - Assert.AreEqual(X.channels % (l.pool[0] * l.pool[1]), 0); - O = new TensorShape(X.batch, X.height * l.pool[1], X.width * l.pool[0], X.channels / (l.pool[0] * l.pool[1])); - } - else if ( - l.type == Layer.Type.SpaceToDepth) - { - // pool size is treated as blocksize here - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 2); - O = new TensorShape(X.batch, X.height / l.pool[1], X.width / l.pool[0], X.channels * (l.pool[0] * l.pool[1])); - } - else if ( - l.type == Layer.Type.MaxPool2D || - l.type == Layer.Type.AvgPool2D) - { - Assert.IsNotNull(l.pool); - Assert.IsNotNull(l.stride); - Assert.IsNotNull(l.pad); - var pad = X.AdjustPadToPool(l.pool, l.stride, l.pad); - O = X.ApplyPool(l.pool, l.stride, pad); - } - else if ( - l.type == Layer.Type.GlobalMaxPool2D || - l.type == Layer.Type.GlobalAvgPool2D) - { - O = new TensorShape(X.batch, 1, 1, X.channels); - } - else if (l.type == Layer.Type.Border3D) - { - Assert.IsNotNull(l.pad); - // legacy support - if (l.pad.Length == 6) - X = X.ApplyBorder(new[] { l.pad[0], l.pad[1], l.pad[2], 0, l.pad[3], l.pad[4], l.pad[5], 0 }); - else - O = X.ApplyBorder(l.pad); - } - else if ( - l.type == Layer.Type.Border2D || - l.type == Layer.Type.Pad2DReflect || - l.type == Layer.Type.Pad2DSymmetric || - l.type == Layer.Type.Pad2DEdge) - { - Assert.IsNotNull(l.pad); - // legacy support - if (l.pad.Length == 4) - X = X.ApplyBorder(new[] { l.pad[0], l.pad[1], 0, l.pad[2], l.pad[3], 0 }); - else - O = X.ApplyBorder(l.pad); - } - else if ( - l.type == Layer.Type.Conv3D || - l.type == Layer.Type.Conv3DTrans || - l.type == Layer.Type.Upsample3D || - l.type == Layer.Type.MaxPool3D || - l.type == Layer.Type.AvgPool3D || - l.type == Layer.Type.GlobalMaxPool3D || - l.type == Layer.Type.GlobalAvgPool3D || - l.type == Layer.Type.Border3D) - { - throw new NotImplementedException(); - } - else if ( - l.type == Layer.Type.RandomNormal || - l.type == Layer.Type.RandomUniform) - { - Assert.IsNotNull(l.pool); - // pool size is treated as shape constant, if not empty - // otherwise shape of the previous tensor is used - if (l.pool.Length > 0) - O = new TensorShape(l.pool); - else - O = X; - } - else if (l.type == Layer.Type.ConstantOfShape) - { - if(l.axis != 1) - O = null; - else - O = X; - } - else if ( - l.type == Layer.Type.Multinomial) - { - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 1); - O = new TensorShape(X.batch, l.pool[0]); - } - else if ( - l.type == Layer.Type.OneHot) - { - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 1); - int depth = l.pool[0]; - int inputRank = l.axis; - inputRank = inputRank < 0 ? X.dimensions : inputRank; - - if (inputRank == 1) - O = new TensorShape(X.flatHeight, depth); - else if (inputRank == 2) - O = new TensorShape(X.flatHeight, 1, depth, X.flatWidth); - else - O = new TensorShape(X.batch, X.height, depth, X.channels); - } - else if (l.type == Layer.Type.RoiAlign) - { - Assert.IsNotNull(l.pool); - Assert.AreEqual(l.pool.Length, 2); - - if (shapesByName.TryGetValue(l.inputs[1], out TensorShape? shape) && shape != null) - { - int batches = shape.Value.flatHeight; - O = new TensorShape(batches, l.pool[0], l.pool[1], X.channels); - } - else - O = null; - } - else if ( - l.type == Layer.Type.Add || - l.type == Layer.Type.Sub || - l.type == Layer.Type.Mul || - l.type == Layer.Type.Div || - l.type == Layer.Type.Pow || - l.type == Layer.Type.Min || - l.type == Layer.Type.Max || - l.type == Layer.Type.Mean|| - l.type == Layer.Type.Greater || - l.type == Layer.Type.GreaterEqual || - l.type == Layer.Type.Less || - l.type == Layer.Type.LessEqual || - l.type == Layer.Type.Equal || - l.type == Layer.Type.LogicalOr || - l.type == Layer.Type.LogicalAnd || - l.type == Layer.Type.LogicalXor || - l.type == Layer.Type.Where) - { - // gather shapes by names - var list = new List(l.inputs.Length); - bool allShapesKnown = true; - foreach (var i in l.inputs) - { - if (shapesByName.TryGetValue(i, out TensorShape? shape) && shape != null) - list.Add(shape.Value); - else - allShapesKnown = false; - } - - O = allShapesKnown ? TensorExtensions.Max(list.ToArray()) : default(TensorShape?); - } - else if ( - l.type == Layer.Type.ReduceL1 || - l.type == Layer.Type.ReduceL2 || - l.type == Layer.Type.ReduceLogSum || - l.type == Layer.Type.ReduceLogSumExp || - l.type == Layer.Type.ReduceMax || - l.type == Layer.Type.ReduceMean || - l.type == Layer.Type.ReduceMin || - l.type == Layer.Type.ReduceProd || - l.type == Layer.Type.ReduceSum || - l.type == Layer.Type.ReduceSumSquare || - l.type == Layer.Type.ArgMax || - l.type == Layer.Type.ArgMin) - { - O = X.Reduce(l.axis); - } - else if ( - l.type == Layer.Type.Flatten) - { - O = X.Flatten(); - } - else if ( - l.type == Layer.Type.Reshape) - { - // pool size is treated as the shape, if not empty - var size = l.pool; - - Assert.IsNotNull(size); - - if (size.Length == 0 && l.inputs.Length > 1) - { - switch (l.axis) - { - // Legacy - use the shape of the input tensor as the shape - case -1: - if (shapesByName.TryGetValue(l.inputs[1], out TensorShape? shape)) - size = shape.Value.ToArray(); - break; - - // Use the tensor values as the shape; Calculated at runtime - case 1: - O = null; - break; - } - - if (O == null) - break; - } - - Assert.IsTrue( (size.Length == 4) || (size.Length == 8)); - O = X.Reshape(size); - } - else if ( - l.type == Layer.Type.Expand) - { - // pool size is treated as new shape - var newShape = l.pool; - - Assert.IsNotNull(newShape); - Assert.IsTrue(newShape.Length == 8 || newShape.Length == 4); - - O = new TensorShape(newShape); - } - else if ( - l.type == Layer.Type.Transpose) - { - var permutations = l.pool; - if (permutations == null) - O = new TensorShape(X.flatWidth, X.flatHeight); - else - { - Assert.IsTrue(permutations.Length == 8 || permutations.Length == 4); - O = X.Permute(permutations); - } - } - else if ( - l.type == Layer.Type.Gather) - { - if (!shapesByName.TryGetValue(l.inputs[0], out TensorShape? input0Shape) || input0Shape == null - || !shapesByName.TryGetValue(l.inputs[1], out TensorShape? input1Shape) || input1Shape == null) - { - O = null; - break; - } - - int[] shape = input0Shape.Value.ToArray(); - shape[l.axis] = input1Shape.Value.length; - - O = new TensorShape(shape); - - if (l.pool != null && l.pool.Length == 2 && l.pool[1] > 1) - { - int xRank = l.pool[0]; - int indicesRank = l.pool[1]; - var oShape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToList(O.Value, xRank); - var indicesShape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToList(input1Shape.Value, indicesRank); - - int axis = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaAxisToTensor(l.axis, xRank); - oShape.InsertRange(axis, indicesShape); - oShape.RemoveAt(axis + indicesShape.Count); - - O = (O.Value).Reshape(Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaLayoutToTensorShapeLayout(oShape.ToArray())); - - // rank 2 -> 3 - if (xRank == 2 && oShape.Count == 3) - O = (O.Value).Permute(new int[] { 0, 1, 3, 2 }); - } - - } - else if (l.type == Layer.Type.ScatterND) - { - O = X; - } - else if ( - l.type == Layer.Type.Squeeze || - l.type == Layer.Type.Unsqueeze) - { - O = X; - } - else if ( - l.type == Layer.Type.Concat) - { - // gather shapes by names - var list = new List(l.inputs.Length); - bool allShapesKnown = true; - foreach (var i in l.inputs) - { - if (!shapesByName.TryGetValue(i, out var shape) || shape == null) - { - allShapesKnown = false; - continue; - } - list.Add(shape.Value); - } - - O = allShapesKnown ? TensorExtensions.Concat(list.ToArray(), l.axis) : default(TensorShape?); - } - else if ( - l.type == Layer.Type.StridedSlice) - { - Assert.IsNotNull(l.pad); - Assert.IsNotNull(l.pool); - Assert.IsNotNull(l.stride); - O = X.ApplyStridedSlice(l.pad, l.pool, l.stride); - } - else if ( - l.type == Layer.Type.Tile) - { - // pool size is treated as tiling coefficient here - Assert.IsNotNull(l.pool); - var scale = l.pool; - O = X.Scale(scale); - } - else if ( - l.type == Layer.Type.Load) - { - O = l.datasets[0].shape; - } - else if (// elementwise operations - l.type == Layer.Type.Nop || - l.type == Layer.Type.Activation || - l.type == Layer.Type.ScaleBias || - l.type == Layer.Type.Normalization || - l.type == Layer.Type.LRN || - l.type == Layer.Type.Dropout || - l.type == Layer.Type.LogicalNot || - l.type == Layer.Type.Sign) - { - // works in place, keeps the same shape size - O = X; - } - else if ( - l.type == Layer.Type.TopKIndices || - l.type == Layer.Type.TopKValues || - l.type == Layer.Type.NonMaxSuppression || - l.type == Layer.Type.LSTM || - l.type == Layer.Type.NonZero) - { - // Calculated at runtime - O = null; - } - else if (l.type == Layer.Type.Shape) - { - int shapeRank = l.axis > 0 ? 1 : X.length; - O = new TensorShape(shapeRank, 1, 1, 1); - } - else if ( - l.type == Layer.Type.Conv3D || - l.type == Layer.Type.Conv3DTrans || - l.type == Layer.Type.Upsample3D || - l.type == Layer.Type.MaxPool3D || - l.type == Layer.Type.AvgPool3D || - l.type == Layer.Type.GlobalMaxPool3D || - l.type == Layer.Type.GlobalAvgPool3D || - l.type == Layer.Type.Border3D) - { - throw new NotImplementedException("3D operations are not implemented yet!"); - } - else - { - throw new NotImplementedException($"Layer type {l.type} needs to be explicitly handled"); - } - - shapes.Add(O); - shapesByName.Add(l.name, O); - } - - Profiler.EndSample(); - return shapes.ToArray(); - } - - // TODO: Remove when the legacy importer / code path is no longer needed (i.e. when pool is always set) - public static void LegacyGetXYRanks(TensorShape X, TensorShape Y, out int rankX, out int rankY) - { - // ONNX rank 2 : N,C => N,1,1,C - // rank 3 : one must be N C W, (batches = N) => N, 1, W, C - // rank 4 : one must be N C H W, (batches = N * C) => N H W C - // X and Y can be different ranks - var onnxXshape = new List { X.batch, X.channels, X.height, X.width }; - if (X.height == 1) onnxXshape = new List { X.batch, X.channels, X.width, 1 }; - var onnxYshape = new List { Y.batch, Y.channels, Y.height, Y.width }; - if (Y.height == 1) onnxYshape = new List { Y.batch, Y.channels, Y.width, 1 }; - - rankX = 0; - for (int i = 3; i >= 0; i--) - { - if (onnxXshape[i] != 1) - { - rankX = i + 1; - break; - } - } - - rankY = 0; - for (int i = 3; i >= 0; i--) - { - if (onnxYshape[i] != 1) - { - rankY = i + 1; - break; - } - } - } - - public static bool TryGetOutputTensorShape(Model model, IDictionary inputShapes, string output, out TensorShape shape) - { - shape = new TensorShape(); - IDictionary shapesByName; - ListTemporaryTensorShapes(model, inputShapes, out shapesByName); - - TensorShape? dynamicShape; - bool found = shapesByName.TryGetValue(output, out dynamicShape) && dynamicShape != null; - if (found) - shape = dynamicShape.Value; - return found; - } - - public static bool TryGetOutputTensorShape(Model model, string output, out TensorShape shape) - { - var inputShapes = new Dictionary(); - foreach (var i in model.inputs) - inputShapes.Add(i.name, new TensorShape(i.shape)); - return TryGetOutputTensorShape(model, inputShapes, output, out shape); - } - - public static bool FindLayerByName(Model model, string name, out Layer layer) - { - layer = new Layer("",Layer.Type.Nop); - foreach (var l in model.layers) - { - if (l.name == name) - { - layer = l; - return true; - } - } - return false; - } - - public static HashSet FindLayersThatRequireStorage(Model model) - { - var allInputsExceptFromPreviousLayer = new HashSet(); - Layer prevLayer = null; - foreach (var layer in model.layers) - { - foreach (var input in layer.inputs) - if (prevLayer != null && input != prevLayer.name) - allInputsExceptFromPreviousLayer.Add(input); - prevLayer = layer; - } - - var allOutputs = new HashSet(); - foreach (var output in model.outputs) - allOutputs.Add(output); - foreach (var memory in model.memories) - allOutputs.Add(memory.output); - allOutputs.Add(GetDefaultOutputName(model)); - - var requireStorage = new HashSet(); - foreach (var layer in model.layers) - { - // loading constant tensor requires storage - if (layer.type == Layer.Type.Load) - requireStorage.Add(layer); - - // @TBD: implement safety check that ensures Nop never has input - // otherwise it has to be treated as Load operation - if (layer.type == Layer.Type.Nop) - requireStorage.Add(layer); - - if (allInputsExceptFromPreviousLayer.Contains(layer.name) || - allOutputs.Contains(layer.name)) - requireStorage.Add(layer); - } - - return requireStorage; - } - - public static HashSet FindUpstreamLayers(Model model, string[] outputs) - { - // TODO: replace with var layersByName = model.layers.ToDictionary(i => i.name, i => i); - var layersByName = new Dictionary(); - foreach (var l in model.layers) - layersByName.Add(l.name, l); - - var connected = new HashSet(); - var layersToVisit = new HashSet(); - foreach (var o in outputs) - if (layersByName.ContainsKey(o)) - { - layersToVisit.Add(layersByName[o]); - connected.Add(layersByName[o]); - } - - while (layersToVisit.Count > 0) - { - var visitNext = new HashSet(); - foreach (var l in layersToVisit) - foreach (var i in l.inputs) - if (layersByName.ContainsKey(i)) - { - visitNext.Add(layersByName[i]); - connected.Add(layersByName[i]); - } - - layersToVisit = visitNext; - } - return connected; - } - - public static TensorShape FindLargestNecessaryTensorShape(Model model, IDictionary inputShapes) - { - Profiler.BeginSample ("Barracuda.FindLargestNecessaryTensorShape"); - - var shapes = ListTemporaryTensorShapes(model, inputShapes); - - var maxTensorShape = new TensorShape(1,1,1,1); - foreach (var X in shapes) - if (X?.length > maxTensorShape.length) - maxTensorShape = X.Value; - - Profiler.EndSample (); - - return maxTensorShape; - } - - public static TensorShape FindLargestArgumentTensorShape(Model model) - { - TensorShape maxTensorShape = new TensorShape(1,1,1,1); - foreach (var layer in model.layers) - foreach (var arg in layer.datasets) - if (arg.shape.length > maxTensorShape.length) - maxTensorShape = arg.shape; - - return maxTensorShape; - } - - public static string[] FindUnusedLayers(Model model) - { - var layerUsageByName = model.layers.ToDictionary(i => i.name, i => false); - foreach (var layer in model.layers) - { - if (layer.flags.HasFlag(Layer.Flags.Preserve)) - layerUsageByName[layer.name] = true; - - foreach (var i in layer.inputs) - { - layerUsageByName[i] = true; - } - } - - foreach (var o in model.outputs) - { - layerUsageByName[o] = true; - } - - foreach (var mem in model.memories) - { - layerUsageByName[mem.output] = true; - } - - return layerUsageByName.Where(keyValue => !keyValue.Value).Select(keyValue => keyValue.Key).ToArray(); - } - - private static string[] FindBrokenLinks(Model model, HashSet links) - { - var allVariables = new HashSet(model.layers.Select(i => i.name)); - var globalInputs = new HashSet(model.inputs.Select(i => i.name)); - var memoryInputs = new HashSet(model.memories.Select(i => i.input)); - allVariables.UnionWith(globalInputs); - allVariables.UnionWith(memoryInputs); - - var brokenLinks = links; - brokenLinks.ExceptWith(allVariables); - return brokenLinks.ToArray(); - } - - private static string[] FindBrokenLinks(Model model, string[] links) - { - return FindBrokenLinks(model, new HashSet(links)); - } - - public static string[] FindBrokenLinks(Model model) - { - // check global outputs - var linksToInspect = new HashSet(model.outputs); - - // and all layers - foreach (var layer in model.layers) - foreach (var i in layer.inputs) - linksToInspect.Add(i); - - return FindBrokenLinks(model, linksToInspect); - } - - public static string[] FindUnconnectedInputs(Model model) - { - var unconnected = model.inputs.ToDictionary(i => i.name, i => true); - - // check global outputs - foreach (var o in model.outputs) - unconnected.Remove(o); - - // and all layers - foreach (var layer in model.layers) - foreach (var i in layer.inputs) - unconnected.Remove(i); - - return unconnected.Keys.ToArray(); - } - - public static string[] FindLayerOutputs(Model model, string layerName) - { - var allVariables = model.layers.Where(x => x.inputs.Contains(layerName)).Select(x => x.name); - var globalOutputs = model.outputs.Where(x => x == layerName); ; - - allVariables.Union(globalOutputs); - - return allVariables.ToArray(); - } - - static public string[] FindUnconnectedOutputs(Model model) - { - return FindBrokenLinks(model, model.outputs.ToArray()); - } - - public static bool IsLayerBroacastable(Layer layer) - { - return layer.type == Layer.Type.Add || - layer.type == Layer.Type.Sub || - layer.type == Layer.Type.Mul || - layer.type == Layer.Type.Div || - layer.type == Layer.Type.Pow || - layer.type == Layer.Type.Min || - layer.type == Layer.Type.Max || - layer.type == Layer.Type.Mean || - layer.type == Layer.Type.Greater || - layer.type == Layer.Type.GreaterEqual || - layer.type == Layer.Type.Less || - layer.type == Layer.Type.LessEqual || - layer.type == Layer.Type.Equal || - layer.type == Layer.Type.LogicalOr || - layer.type == Layer.Type.LogicalAnd || - layer.type == Layer.Type.LogicalXor || - layer.type == Layer.Type.Where || - layer.type == Layer.Type.Concat; - } - public static bool IsLayerBroadcastSkippable(Layer layer) - { - if(layer.type == Layer.Type.ConstantOfShape) - { - // dynamic shape support - if (layer.axis != 1) - return true; - else - return false; - } - - return false; - } - - // Allow some unknown input dimension for shape inference pass - // for now batch does not yield problematic shape inference, so allow for unkown batch - public static bool IsInputShapeAcceptablyKnowForShapeInference(Model.Input input) // acceptable unknown shape : N - { - for (int i = 0; i < input.shape.Length; i++) - { - var x = input.shape[i]; - if (x <= 0 && i != TensorShape.DataBatch) - return false; - } - return true; - } - - public static bool DoesTransposeChangeTensorLayout(TensorShape shape, int[] permutations) - { - var activeDimLayout = new List(); - for (int i = 0; i < 8; i++) - { - if (shape[i] != 1) - activeDimLayout.Add(i); - } - - if (permutations.Length == 4) - permutations = TensorExtensions.Get8DPermutationsForNHWCPermutationsAndShape(shape, permutations); - - var transposedLayout = TensorExtensions.Permute(new[] { 0, 1, 2, 3, 4, 5, 6, 7 }, permutations); - var permutedShape = shape.Permute(permutations); - var premutedActiveDimLayout = new List(); - for (int i = 0; i < 8; i++) - { - if (permutedShape[i] != 1) - premutedActiveDimLayout.Add(transposedLayout[i]); - } - - return activeDimLayout.SequenceEqual(premutedActiveDimLayout); - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelAnalyzer.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelAnalyzer.cs.meta deleted file mode 100644 index eab91aa..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelAnalyzer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 58838262534854657974303d5782ea38 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelExecutionsReport.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelExecutionsReport.cs deleted file mode 100644 index 4c47a33..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelExecutionsReport.cs +++ /dev/null @@ -1,253 +0,0 @@ -#if ENABLE_BARRACUDA_STATS - -using System.Collections.Generic; -using System.IO; -using System.Text; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda { - -public readonly struct DispatchInfo -{ - public readonly string backend; - public readonly string kernel; - public readonly int workItemsX; - public readonly int workItemsY; - public readonly int workItemsZ; - - public DispatchInfo(string backend, string kernel, int workItemsX, int workItemsY, int workItemsZ) - { - this.backend = backend; - this.kernel = kernel; - this.workItemsX = workItemsX; - this.workItemsY = workItemsY; - this.workItemsZ = workItemsZ; - } - - public override string ToString() - { - return $"{backend}:{kernel}({workItemsX},{workItemsY},{workItemsZ})"; - } - - internal static DispatchInfo CreateFromComputeFunc(ComputeFunc computeFunc, int x, int y, int z) - { - var backend = computeFunc.computeShaderContext==ComputeShaderContext.Reference?"REF":"OPT"; - return new DispatchInfo(backend, computeFunc.kernelName, x, y, z); - } -} - -public class LayerExecutionReport -{ - public string LayerType { get; } - public string LayerName { get; } - public string DispatchInfos { get; private set; } - public string Summary { get; private set; } - public long NumAlu { get; private set; } - public long NumBytes { get; private set; } - - internal LayerExecutionReport(Layer l) - { - LayerType = l.type + ((l.type == Layer.Type.Activation) ? ("." + l.activation) : ""); - LayerName = l.name; - Summary = ""; - DispatchInfos = ""; - NumAlu = 0; - NumBytes = 0; - } - - internal void SetSummary(string message) - { - Summary = message; - } - - internal void SetALUAndMemStats(long alu, long bytes) - { - NumAlu = alu; - NumBytes = bytes; - } - - internal void AddDispatch(DispatchInfo dispatchInfo) - { - if (DispatchInfos.Length != 0) - DispatchInfos = DispatchInfos + " / "; - DispatchInfos = DispatchInfos + dispatchInfo; - } -} - -public class ModelExecutionReport -{ - public List CompletedLayerExecutionReports { get; } - public LayerExecutionReport CurrentLayerExecutionReport { get; private set; } - - internal ModelExecutionReport() - { - CompletedLayerExecutionReports = new List(); - CurrentLayerExecutionReport = null; - } - - internal void LayerExecutionStarted(Layer layer) - { - Assert.IsNull(CurrentLayerExecutionReport); - CurrentLayerExecutionReport = new LayerExecutionReport(layer); - } - - internal void LayerExecutionCompleted() - { - CompletedLayerExecutionReports.Add(CurrentLayerExecutionReport); - CurrentLayerExecutionReport = null; - } - - internal void SetLayerSummary(string message) - { - Assert.IsNotNull(CurrentLayerExecutionReport); - CurrentLayerExecutionReport.SetSummary(message); - } - - internal void SetLayerALUAndMemStats(long alu, long bytes) - { - Assert.IsNotNull(CurrentLayerExecutionReport); - CurrentLayerExecutionReport.SetALUAndMemStats(alu, bytes); - } - - internal void AddLayerDispatch(DispatchInfo dispatchInfo) - { - Assert.IsNotNull(CurrentLayerExecutionReport); - CurrentLayerExecutionReport.AddDispatch(dispatchInfo); - } -} - -public class ModelExecutionsReporter : IModelExecutionsReporter -{ - //Tabs separator make importing into spreadsheet software easy. - public static readonly string SpreadSheetFieldSeparator = "\t"; - public static readonly string TextFormatFieldSeparator = " / "; - public static readonly string TextIndentation = " "; - - public List CompletedModelExecutionReports { get; private set; } - public ModelExecutionReport CurrentModelExecutionReport { get; private set; } - public MemorySnapshotsReport MemorySnapshotsReport { get; private set; } - - public ModelExecutionsReporter() - { - Reset(); - } - - public void Reset() - { - CompletedModelExecutionReports = new List(); - CurrentModelExecutionReport = null; - MemorySnapshotsReport = new MemorySnapshotsReport(); - } - - public void TakeMemorySnapshot(IOps ops, IVars vars, string context, Layer layer) - { - MemorySnapshotsReport.TakeMemorySnapshot(ops, vars, context, layer); - } - - public void ModelExecutionStarted() - { - Assert.IsNull(CurrentModelExecutionReport); - CurrentModelExecutionReport = new ModelExecutionReport(); - } - - public void ModelExecutionCompleted() - { - CompletedModelExecutionReports.Add(CurrentModelExecutionReport); - CurrentModelExecutionReport = null; - } - - public void LayerExecutionStarted(Layer layer) - { - Assert.IsNotNull(CurrentModelExecutionReport); - CurrentModelExecutionReport.LayerExecutionStarted(layer); - } - - public void LayerExecutionCompleted() - { - Assert.IsNotNull(CurrentModelExecutionReport); - CurrentModelExecutionReport.LayerExecutionCompleted(); - } - - public void SetLayerSummary(string message) - { - Assert.IsNotNull(CurrentModelExecutionReport); - CurrentModelExecutionReport.SetLayerSummary(message); - } - - public void SetLayerALUAndMemStats(long alu, long bytes) - { - Assert.IsNotNull(CurrentModelExecutionReport); - CurrentModelExecutionReport.SetLayerALUAndMemStats(alu, bytes); - } - - public void AddLayerDispatch(DispatchInfo dispatchInfo) - { - Assert.IsNotNull(CurrentModelExecutionReport); - CurrentModelExecutionReport.AddLayerDispatch(dispatchInfo); - } - - public override string ToString() - { - return GenerateStringReport(out var memoryPeakSummary, false); - } - - public string GenerateStringReport(out MemoryPeakSummary memoryPeakSummary, bool spreadsheetFormat) - { - var stringBuilder = new StringBuilder(1000); - - //**************** MODEL EXECUTIONS REPORT - START **************** - stringBuilder.Append($"**************** MODEL EXECUTIONS REPORT - START ****************\n"); - stringBuilder.Append($"Number of completed executions : {CompletedModelExecutionReports.Count}\n"); - if (CurrentModelExecutionReport != null) - stringBuilder.Append("Warning: last model execution was not completed. It will be logged, but information might be incomplete.\n"); - stringBuilder.Append("\n"); - int i = 0; - for (; i < CompletedModelExecutionReports.Count; ++i) - { - stringBuilder.Append($"--------- Execution index : {i} - START ---------\n"); - MemoryAndExecutionReportHelper.GenerateStringReport(stringBuilder, CompletedModelExecutionReports[i], spreadsheetFormat); - stringBuilder.Append($"--------- Execution index : {i} - STOP ---------\n"); - stringBuilder.Append("\n"); - } - if (CurrentModelExecutionReport != null) - { - stringBuilder.Append($"--------- Uncompleted execution - START ---------\n"); - MemoryAndExecutionReportHelper.GenerateStringReport(stringBuilder, CurrentModelExecutionReport, spreadsheetFormat); - stringBuilder.Append($"--------- Uncompleted execution - STOP ---------\n"); - stringBuilder.Append("\n"); - } - stringBuilder.Append($"**************** MODEL EXECUTION REPORT - STOP ****************\n"); - stringBuilder.Append("\n"); - //**************** MODEL EXECUTIONS REPORT - STOP **************** - - //**************** MEMORY SNAPSHOTS REPORTS - START **************** - memoryPeakSummary = MemorySnapshotsReport.GenerateStringReport(stringBuilder, spreadsheetFormat); - //**************** MEMORY SNAPSHOTS REPORTS - STOP **************** - - return stringBuilder.ToString(); - } - - #if UNITY_EDITOR - public static string ToTextFile(IModelExecutionsReporter report, bool spreadsheetFormat, out MemoryPeakSummary memoryPeakSummary, string filename = null) - { - string stringToSave = report.GenerateStringReport(out memoryPeakSummary, spreadsheetFormat); - string fullPath = Application.temporaryCachePath; - if (filename == null) - { - fullPath = Path.Combine(fullPath, "ModelExecutionReport"); - fullPath = Path.ChangeExtension(fullPath, "txt"); - } - else - { - fullPath = Path.Combine(fullPath, filename); - } - File.WriteAllText(fullPath, stringToSave); - return fullPath; - } - #endif -} - -} // namespace Unity.Barracuda - -#endif //ENABLE_BARRACUDA_STATS diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelExecutionsReport.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelExecutionsReport.cs.meta deleted file mode 100644 index a609bc8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelExecutionsReport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ab688279bb437e74b9ea9cd53ea1f09d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelOptimizer.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelOptimizer.cs deleted file mode 100644 index 9e40603..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelOptimizer.cs +++ /dev/null @@ -1,433 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; // ToArray(), ToDictionary() -using UnityEngine.Assertions; - -namespace Unity.Barracuda -{ - -internal class ModelOptimizer -{ - static public Model Optimize(Model model, bool allowFusing, HashSet keepLayers = null) - { - RemoveUnused(model, keepLayers); - - if (allowFusing) - { - FuseLinear(model, keepLayers); - FuseActivations(model); - } - - return model; - } - - public static void RemoveUnused(Model model, HashSet keepLayers) - { - // TODO: strip layers not useful to compute output - var preserve = new HashSet( - model.memories.Select(mem => mem.input).Concat( - model.memories.Select(mem => mem.output)).Concat( - model.outputs)); - - // Strip unused layers - var unusedLayers = new HashSet(ModelAnalyzer.FindUnusedLayers(model)); - if (keepLayers != null) // Except explicitly specified for keeping - unusedLayers.ExceptWith(keepLayers); - model.layers = model.layers.Where(l => !unusedLayers.Contains(l.name) || preserve.Contains(l.name)).ToList(); - } - - public static bool IsLayerSupportingActivationFusing(Layer.Type layerType) - { - return layerType == Layer.Type.Dense || - layerType == Layer.Type.Conv2D || - layerType == Layer.Type.Conv3D || - layerType == Layer.Type.DepthwiseConv2D || - layerType == Layer.Type.Conv2DTrans || - layerType == Layer.Type.Normalization; - } - - public static bool IsActivationFusable(Layer.Activation activationType) - { - var fusedActivationType = (Layer.FusedActivation) activationType; - switch (fusedActivationType) - { - case Layer.FusedActivation.None: - case Layer.FusedActivation.Relu: - case Layer.FusedActivation.Tanh: - case Layer.FusedActivation.Softplus: - case Layer.FusedActivation.Sigmoid: - case Layer.FusedActivation.Relu6: - case Layer.FusedActivation.Swish: - case Layer.FusedActivation.Neg: - case Layer.FusedActivation.Sqrt: - case Layer.FusedActivation.Exp: - case Layer.FusedActivation.Log: - case Layer.FusedActivation.Acos: - case Layer.FusedActivation.Acosh: - case Layer.FusedActivation.Asin: - case Layer.FusedActivation.Asinh: - case Layer.FusedActivation.Atan: - case Layer.FusedActivation.Atanh: - case Layer.FusedActivation.Cos: - case Layer.FusedActivation.Cosh: - case Layer.FusedActivation.Sin: - case Layer.FusedActivation.Sinh: - case Layer.FusedActivation.Tan: - case Layer.FusedActivation.Erf: - return true; - default: - return false; - } - } - - static private void FuseActivation(Model model, Layer mainLayer, Layer activationToFuse) - { - //patch `mainLayer` - mainLayer.activation = activationToFuse.activation; - - //patch all layers depending on `activationToFuse` - foreach (var l in model.layers) - { - for (int i = 0; i < l.inputs.Length; ++i) - { - if (l.inputs[i] == activationToFuse.name) - l.inputs[i] = mainLayer.name; - } - } - - //remove `activationToFuse` if not an output, if an output make it an identity layer instead. - if (model.outputs.Contains(activationToFuse.name) || model.memories.Exists(m => m.output == activationToFuse.name)) - { - activationToFuse.type = Layer.Type.Nop; - activationToFuse.activation = Layer.Activation.None; - } - else - model.layers.Remove(activationToFuse); - } - - static public void FuseActivations(Model model) - { - //Fused activation - var fusableActivations = model.layers.Where(l => l.type == Layer.Type.Activation && IsActivationFusable(l.activation)).ToList(); - foreach (var activationLayer in fusableActivations) - { - if (activationLayer.inputs.Length != 1) - continue; - - var mainLayer = model.layers.Find(l => l.name == activationLayer.inputs[0]); - if (mainLayer == null) - continue; - - if (!IsLayerSupportingActivationFusing(mainLayer.type)) - continue; - - if (mainLayer.activation != Layer.Activation.None) - continue; - - if (model.outputs.Contains(mainLayer.name)) - continue; - - if (model.memories.Exists(m => m.output == mainLayer.name)) - continue; - - //Need to check that no other layers uses mainLayer directly. - //Activation in the graph below can not be fused because (concat) layer needs raw output of (conv) layer - //conv -> relu -----. - // \ v - // `---------> concat - if (model.layers.Exists(l => l != activationLayer && l.inputs.Contains(mainLayer.name))) - continue; - - FuseActivation(model, mainLayer, activationLayer); - } - } - - private static bool IsPermutationNoop(int[] permutations) - { - for (int i = 0; i < permutations.Length; ++i) - if (permutations[i] != i) - return false; - return true; - } - - static bool IsLayerNoop(Layer layer) - { - return layer.type == Layer.Type.Nop || - (layer.type == Layer.Type.Activation && layer.activation == Layer.Activation.None) || - (layer.type == Layer.Type.Transpose && IsPermutationNoop(layer.pool) || - layer.type == Layer.Type.StridedSlice - // Nothing is actually being done in this case since it is the full range with single stepping, so skip it - && layer.pad.All(s => s == 0) - && layer.pool.All(e => e == int.MaxValue) - && layer.stride.All(s => s == 1)); - } - - public static Model RemoveNoop(Model model) - { - var noopLayers = new List(); - var remap = new Dictionary(); - - // outputs and memories can be queried by the user, make sure they are not removed - var preserve = new HashSet( - model.memories.Select(mem => mem.input).Concat( - model.memories.Select(mem => mem.output)).Concat( - model.outputs)); - - // algorithm: - // - if input is pointing to a noop, we need to remap it to upstream layer - // - if layer is a noop, store its link to upstream layer - // layers are in order of appearance, so if layer_N has layer_M as input, we'd have treated layer_M before - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - - // replace removed layers with their upstream inputs - for (int i = 0; i < layer.inputs.Length; ++i) - { - var input = layer.inputs[i]; - if (remap.ContainsKey(input)) - { - Assert.IsTrue(noopLayers.Any(x => input == x.name)); - model.layers[l].inputs[i] = remap[input]; - } - else - { - Assert.IsFalse(noopLayers.Any(x => input == x.name)); - } - } - - if (preserve.Contains(layer.name)) - continue; - - if (layer.inputs.Length == 0) // const - continue; - - // if layer is noop = nop, identity or flatten - if (IsLayerNoop(layer)) - { - Assert.IsTrue(layer.inputs.Length == 1); // noop layers have only 1 input - remap[layer.name] = layer.inputs[0]; - noopLayers.Add(layer); - } - } - - foreach (var l in noopLayers) - { - model.layers.Remove(l); - } - - return model; - } - - - public static bool IsLayerConstant(Layer layer) - { - return layer.type == Layer.Type.Load; - } - static bool IsLayerFusedActivation(Layer layer) - { - return layer.activation != Layer.Activation.None; - } - - static StaticLayerOppComplexity m_LayerComplexity = new StaticLayerOppComplexity(); - static long LayerComplextity(Layer l) { return m_LayerComplexity.LayerComplextity(l); } - - static LinearLayerFusing linearLayerFuser = new LinearLayerFusing(); - static Layer FuseConsecutiveLayers(Layer previous, Layer current) - { - return linearLayerFuser.FuseLayers(previous, current); - } - static bool AreLayersFusable(Layer l0, Layer l1) - { - // can't fuse if input has a fused activation or if fusing code not implemented - return !IsLayerFusedActivation(l0) && linearLayerFuser.AreLayersFusable(l0, l1); - } - - private static void PackConstants(Model model, Dictionary constantLayers) - { - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - - if (!LinearLayerFusing.IsLayerLinearMathOp(layer)) - continue; - var constInputs = layer.inputs.Count(x => constantLayers.ContainsKey(x)); - // @TODO fuse multi const inputs here - if (!(layer.inputs.Length == 2 && constInputs == 1)) - continue; - - var constInput = layer.inputs.ToList().Find(x => constantLayers.ContainsKey(x)); - - layer.datasets = new Layer.DataSet[constantLayers[constInput].datasets.Length]; - Array.Copy(constantLayers[constInput].datasets, layer.datasets, constantLayers[constInput].datasets.Length); - layer.weights = new BarracudaArray(constantLayers[constInput].weights.Length); - BarracudaArray.Copy(constantLayers[constInput].weights, layer.weights, constantLayers[constInput].weights.Length); - - model.layers[l].inputs = layer.inputs.Where(x => x != constInput).ToArray(); - } - } - - private static void UnpackConstants(Model model) - { - List newConstants = new List(); - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - if(!LinearLayerFusing.IsLayerLinearMathOp(layer)) - continue; - - if (layer.datasets == null || layer.datasets.Length != 1) - continue; - - var name = "c" + layer.name; - Layer constInput = new Layer(name,Layer.Type.Load); - - constInput.datasets = new Layer.DataSet[layer.datasets.Length]; - Array.Copy(layer.datasets, constInput.datasets, layer.datasets.Length); - for(int d = 0; d < constInput.datasets.Length; ++d) - constInput.datasets[d].name = name; - - constInput.weights = new BarracudaArray(layer.weights.Length); - BarracudaArray.Copy(layer.weights, constInput.weights, layer.weights.Length); - - Array.Resize(ref layer.inputs, layer.inputs.Length + 1); - layer.inputs[layer.inputs.Length-1] = constInput.name; - - newConstants.Add(constInput); - - layer.datasets = new Layer.DataSet[0]; - layer.weights = new BarracudaArray(0);//TODO fp16 - } - newConstants.AddRange(model.layers); - model.layers = newConstants; - } - - public static void FuseLinear(Model model, HashSet keepLayers = null) - { - // outputs and memories can be queried by the user, make sure they are not removed - var preserve = new HashSet( - model.memories.Select(mem => mem.input).Concat( - model.memories.Select(mem => mem.output)).Concat( - model.outputs)); - - var constantLayers = new Dictionary(); - foreach (var l in model.layers) - { - if (IsLayerConstant(l)) - constantLayers[l.name] = l; - } - - // pack constants into layer database - PackConstants(model, constantLayers); - - var remap = new Dictionary(); - var mergedLayers = new HashSet(); - - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - - bool isLayerLinear = LinearLayerFusing.IsLayerLinear(layer, constantLayers); - bool isLayerPreserved = preserve.Contains(layer.name); - bool layerHasActivation = IsLayerFusedActivation(layer); - - if(!isLayerLinear) - continue; - - // if layer has an activation, we fuse it, but treat it as non linear for future children - if (!layerHasActivation) - { - remap[layer.name] = layer.name; - } - - // Multi input nodes can only fuse constants and same inputs - // only merge constants. @TODO: fuse equal input nodes - var nonLinearInputs = layer.inputs.Where(x => !remap.ContainsKey(x) && !constantLayers.ContainsKey(x)).ToList(); - var linearInputs = layer.inputs.Where(x => remap.ContainsKey(x)).ToList(); - - // merge layer with one linearInput and eventual constants - if (nonLinearInputs.Count > 0 || linearInputs.Count > 1) - continue; - - var input = linearInputs[0]; - - // input is a linear layer, fuse it - int inputLayerIndex = model.layers.FindIndex(x => x.name == remap[input]); - Layer inputLayer = model.layers[inputLayerIndex]; - - if(!AreLayersFusable(inputLayer, layer)) - continue; - - // convention: layer will be fused into inputLayer - // => fused layer will have the same inputs as inputLayer - Layer fusedLayer = FuseConsecutiveLayers(inputLayer, layer); - - if(LayerComplextity(fusedLayer) > LayerComplextity(inputLayer) + LayerComplextity(layer)) - continue; - - if (layerHasActivation) - { - fusedLayer.activation = layer.activation; - } - - bool hasNoSkipConnection = (model.GetDownStreamLayersCount(input) == 1); - // if input has more than 1 child, we can't override input with fused result - // same if input is preserved - if (!hasNoSkipConnection || preserve.Contains(input)) - { - fusedLayer.name = layer.name; - model.layers[l] = fusedLayer; - continue; - } - - // preserve layer if output/memory - if(isLayerPreserved) - { - // cannot merge layer into input: - // remove input, no need to remap as inputs == input.inputs - fusedLayer.name = layer.name; - mergedLayers.Add(inputLayer); - model.layers[l] = fusedLayer; - } - else - { - // merge layer into input - // remove current and remap input names - mergedLayers.Add(layer); - remap[layer.name] = fusedLayer.name; - model.layers[inputLayerIndex] = fusedLayer; - } - } - - // remove merged layers - model.layers.RemoveAll(x => mergedLayers.Contains(x)); - - // update remapped inputs - for (int l = 0; l < model.layers.Count; ++l) - { - Layer layer = model.layers[l]; - for (int i = 0; i < layer.inputs.Length; ++i) - { - var input = layer.inputs[i]; - if(remap.ContainsKey(input)) - model.layers[l].inputs[i] = remap[input]; - } - } - - // unpack constants - UnpackConstants(model); - - // remove unused constants - foreach (var l in model.layers) - foreach (var i in l.inputs) - { - if (constantLayers.ContainsKey(i)) - constantLayers.Remove(i); - } - model.layers.RemoveAll(x => constantLayers.ContainsKey(x.name) && - !preserve.Contains(x.name) && - (keepLayers == null ? true : !keepLayers.Contains(x.name))); - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelOptimizer.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelOptimizer.cs.meta deleted file mode 100644 index ad4f91a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/ModelOptimizer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5b3983e71fb437348b667e0ecee2e9a3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/OpsUtils.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/OpsUtils.cs deleted file mode 100644 index 60a32c1..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/OpsUtils.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System.Collections.Generic; - -namespace Unity.Barracuda { - -class OpsUtils -{ - // Split W, R, and B into [iofj] tensors w, r, wb, rb - public static void SplitWRBForLSTM(IOps ops, Tensor W, Tensor R, Tensor B, out Tensor[] w, out Tensor[] r, out Tensor[] wb, out Tensor[] rb) - { - w = new[] - { - // w_i - ops.StridedSlice(W, new[] { 0, 0, 0, 0 }, new[] { W.batch, 1, 1, W.channels / 4 }, new[] { 1, 1, 1, 1 }), - // w_o - ops.StridedSlice(W, new[] { 0, 0, 0, W.channels / 4 }, new[] { W.batch, 1, 1, 2 * W.channels / 4 }, new[] { 1, 1, 1, 1 }), - // w_f - ops.StridedSlice(W, new[] { 0, 0, 0, 2 * W.channels / 4 }, new[] { W.batch, 1, 1, 3 * W.channels / 4 }, new[] { 1, 1, 1, 1 }), - // w_j - ops.StridedSlice(W, new[] { 0, 0, 0, 3 * W.channels / 4 }, new[] { W.batch, 1, 1, 4 * W.channels / 4 }, new[] { 1, 1, 1, 1 }), - }; - - r = new[] - { - // r_i - ops.StridedSlice(R, new[] { 0, 0, 0, 0 }, new[] { R.batch, 1, 1, R.channels / 4 }, new[] { 1, 1, 1, 1 }), - // r_o - ops.StridedSlice(R, new[] { 0, 0, 0, R.channels / 4 }, new[] { R.batch, 1, 1, 2 * R.channels / 4 }, new[] { 1, 1, 1, 1 }), - // r_f - ops.StridedSlice(R, new[] { 0, 0, 0, 2 * R.channels / 4 }, new[] { R.batch, 1, 1, 3 * R.channels / 4 }, new[] { 1, 1, 1, 1 }), - // r_j - ops.StridedSlice(R, new[] { 0, 0, 0, 3 * R.channels / 4 }, new[] { R.batch, 1, 1, 4 * R.channels / 4 }, new[] { 1, 1, 1, 1 }) - }; - - wb = new[] - { - // wb_i - ops.StridedSlice(B, new[] { 0, 0, 0, 0 }, new[] { 1, 1, 1, B.channels / 8 }, new[] { 1, 1, 1, 1 }), - // wb_o - ops.StridedSlice(B, new[] { 0, 0, 0, B.channels / 8 }, new[] { 1, 1, 1, 2 * B.channels / 8 }, new[] { 1, 1, 1, 1 }), - // wb_f - ops.StridedSlice(B, new[] { 0, 0, 0, 2 * B.channels / 8 }, new[] { 1, 1, 1, 3 * B.channels / 8 }, new[] { 1, 1, 1, 1 }), - // wb_j - ops.StridedSlice(B, new[] { 0, 0, 0, 3 * B.channels / 8 }, new[] { 1, 1, 1, 4 * B.channels / 8 }, new[] { 1, 1, 1, 1 }) - }; - - rb = new [] - { - // rb_i - ops.StridedSlice(B, new[] { 0, 0, 0, 4 * B.channels / 8 }, new[] { 1, 1, 1, 5 * B.channels / 8 }, new[] { 1, 1, 1, 1 }), - // rb_o - ops.StridedSlice(B, new[] { 0, 0, 0, 5 * B.channels / 8 }, new[] { 1, 1, 1, 6 * B.channels / 8 }, new[] { 1, 1, 1, 1 }), - // rb_f - ops.StridedSlice(B, new[] { 0, 0, 0, 6 * B.channels / 8 }, new[] { 1, 1, 1, 7 * B.channels / 8 }, new[] { 1, 1, 1, 1 }), - // rb_j - ops.StridedSlice(B, new[] { 0, 0, 0, 7 * B.channels / 8 }, new[] { 1, 1, 1, 8 * B.channels / 8 }, new[] { 1, 1, 1, 1 }) - }; - } - - public static void BakeConstantWRBIntoLSTMLayer(Layer layer, Tensor W, Tensor R, Tensor B) - { - string name = layer.name; - - // Bake out constant tensors into layer - void AddDataset(List datasets, BarracudaArray weights, string tensorName, Tensor t, ref int offset) - { - var dataset = new Layer.DataSet(); - dataset.name = $"{name}/{tensorName}"; - dataset.shape = t.shape; - dataset.itemSizeInBytes = 4; - dataset.length = t.shape.length; - dataset.offset = offset; - datasets.Add(dataset); - - t.ToReadOnlyArray().CopyToBarracudaArray(weights, offset); - - offset += t.shape.length; - } - - var layerDatasets = new List(); - var layerWeights = new BarracudaArray(W.shape.length + R.shape.length + B.shape.length); - int dataOffset = 0; - - var ops = new ReferenceCPUOps(); - using (var td = new TensorScope()) - { - TensorScope.F _ = td._; - - Tensor[] w_iofj, r_iofj, wb_iofj, rb_iofj; - SplitWRBForLSTM(ops, W, R, B, out w_iofj, out r_iofj, out wb_iofj, out rb_iofj); - - var indexName = new[] { "i", "o", "f", "j" }; - - for (int i = 0; i < w_iofj.Length; i++) - { - AddDataset(layerDatasets, layerWeights, $"w_{indexName[i]}", _(w_iofj[i]), ref dataOffset); - } - - for (int i = 0; i < w_iofj.Length; i++) - { - AddDataset(layerDatasets, layerWeights, $"r_{indexName[i]}", _(r_iofj[i]), ref dataOffset); - } - - for (int i = 0; i < w_iofj.Length; i++) - { - AddDataset(layerDatasets, layerWeights, $"wb_{indexName[i]}", _(wb_iofj[i]), ref dataOffset); - } - - for (int i = 0; i < w_iofj.Length; i++) - { - AddDataset(layerDatasets, layerWeights, $"rb_{indexName[i]}", _(rb_iofj[i]), ref dataOffset); - } - } - - layer.datasets = layerDatasets.ToArray(); - layer.weights = layerWeights; - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/OpsUtils.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/OpsUtils.cs.meta deleted file mode 100644 index cbc7724..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/OpsUtils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d6cd3668a018f1e4dbe95e8c7daade7c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/PixelShaderSingleton.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/PixelShaderSingleton.cs deleted file mode 100644 index ac88b05..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/PixelShaderSingleton.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Profiling; - -namespace Unity.Barracuda -{ - /// - /// Stores compute kernel cache for GPU pixel shader backends - /// - public sealed class PixelShaderSingleton - { - /// - /// Enable kernel usage tracking - /// - public bool EnableDebug = false; - - private static readonly PixelShaderSingleton instance = new PixelShaderSingleton(); - - // Maps shader name -> Shader - private Dictionary m_shaderNameToPixelShader = new Dictionary(); - - private HashSet m_usedShaders = new HashSet(); - - internal Shader FindShader(string kernelName) - { - if (EnableDebug) m_usedShaders.Add(kernelName); - - if (!m_shaderNameToPixelShader.ContainsKey(kernelName)) - { - Profiler.BeginSample(kernelName); - m_shaderNameToPixelShader[kernelName] = Shader.Find(kernelName); - Profiler.EndSample(); - } - - return m_shaderNameToPixelShader[kernelName]; - } - - /// - /// Warmup pixel shaders - /// - /// list of shaders to warm up - /// IEnumerator - public IEnumerator WarmupPixelShaderKernels(List shaders) - { - foreach (var shader in shaders) - { - if (!m_shaderNameToPixelShader.ContainsKey(shader)) - { - FindShader(shader); - yield return null; - } - } - yield break; - } - - /// - /// Get used pixel shader list - /// - /// list of kernels - public List GetUsedPixelShaders() - { - if (!EnableDebug) - { - D.LogWarning("List of used pixel shaders was requested while PixelShaderSingleton.EnableDebug == false"); - return null; - } - - return m_usedShaders.ToList(); - } - - /// - /// Singleton - /// - public static PixelShaderSingleton Instance { - get { return instance; } - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/PixelShaderSingleton.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/PixelShaderSingleton.cs.meta deleted file mode 100644 index 38308fa..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/PixelShaderSingleton.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 29faad9ef63aaad48b43893fc5c8aafc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/StaticOpsComplexityHelper.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/StaticOpsComplexityHelper.cs deleted file mode 100644 index a1ed614..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/StaticOpsComplexityHelper.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using UnityEngine; -using System.Collections.Generic; - -namespace Unity.Barracuda { - - -internal class StaticLayerOppComplexity -{ - private readonly Dictionary> m_layerComplexityStats = - new Dictionary>(); - - private void Add(Layer.Type layerType, Func opStats) - { - m_layerComplexityStats.Add(layerType, opStats); - } - - public StaticLayerOppComplexity() - { - Add((Layer.Type.Add), (l) => - { - return l.datasets.Length; - }); - Add((Layer.Type.Mul), (l) => - { - return l.datasets.Length; - }); - Add((Layer.Type.ScaleBias), (l) => - { - return 2L; - }); - Add((Layer.Type.Dense), (l) => - { - var W = l.datasets[0].shape; - return (long)W.flatHeight * (long)W.flatWidth * 2L; - }); - Add((Layer.Type.Conv2D), (l) => - { - var K = l.datasets[0].shape; - long n = (long)K.kernelDepth; - long k = (long)K.kernelWidth * (long)K.kernelHeight * (long)K.channels; - return n * k * 2L; - }); - Add((Layer.Type.Conv3D), (l) => - { - var K = l.datasets[0].shape; - long n = (long)K.kernelDepth; - long k = (long)K.kernelSpatialDepth * K.kernelWidth * (long)K.kernelHeight * (long)K.channels; - return n * k * 2L; - }); - Add((Layer.Type.DepthwiseConv2D), (l) => - { - var K = l.datasets[0].shape; - long n = (long)K.kernelDepth; - long k = (long)K.kernelWidth * (long)K.kernelHeight; - return n * k * 2L; - }); - } - - public long LayerComplextity(Layer l) - { - var fnComplexity = m_layerComplexityStats[l.type]; - return fnComplexity(l); - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/StaticOpsComplexityHelper.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/StaticOpsComplexityHelper.cs.meta deleted file mode 100644 index 7b33a21..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/StaticOpsComplexityHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a983c58109196f44da7d3c5b326877c5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/StatsOps.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/StatsOps.cs deleted file mode 100644 index f6db52f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/StatsOps.cs +++ /dev/null @@ -1,1195 +0,0 @@ -using System; -using UnityEngine; -using System.Collections.Generic; - -namespace Unity.Barracuda { - -/// -/// Proxy `IOps` implementation for tracking computational expenses for specific model -/// -public class StatsOps : IOps, IModelCompiler -{ - class Transcendental - { - - // Table of approximate alu operation costs - // mul 1 - // rcp/mad 2 - // div/sqrt 10 - // log/exp 100 - // pow 200 - // see: https://www.sciencedirect.com/topics/computer-science/division-operation - // see: https://colfaxresearch.com/arithmetics-on-intels-sandy-bridge-and-westmere-cpus-not-all-flops-are-created-equal/ - - public const long Reciprocal = 2L; - public const long Div = 10L; - public const long Root = 10L; - public const long Exponent = 100L; - public const long Pow = 200L; - public const long Trigonometric = 200L; - } - - private IOps m_Ops; - private LayerStat m_Alu; - private LayerStat m_Mem; - - private readonly struct LayerStat - { - public readonly long total; - public readonly long layer; - - public LayerStat(long totalBeforeLayer, long layer) - { - this.total = totalBeforeLayer + layer; - this.layer = layer; - } - - public static implicit operator long(LayerStat d) => d.total; - public static LayerStat operator +(LayerStat a, long b) => new LayerStat(a.total, b); - }; - -#if ENABLE_BARRACUDA_STATS - public IEnumerable GetTempMemoryStatistics() - { - return m_Ops.GetTempMemoryStatistics(); - } -#endif //ENABLE_BARRACUDA_STATS - - /// - /// Create `StatsOps` - /// - /// target ops - public StatsOps(IOps ops) - { - m_Ops = ops; - m_Alu = new LayerStat(0L,0L); - m_Mem = new LayerStat(0L,0L); - } - - /// - public virtual void PostLayerCleanup() - { - m_Ops.PostLayerCleanup(); - } - - /// - public virtual void PrepareModel(Model model, IDictionary inputShapes, IVars vars) - { - if (m_Ops is IModelCompiler) - ((IModelCompiler)m_Ops).PrepareModel(model, inputShapes, vars); - } - - /// - public virtual void PreExecuteLayer(Layer layer, Tensor[] inputs) - { - if (m_Ops is IModelCompiler) - ((IModelCompiler)m_Ops).PreExecuteLayer(layer, inputs); - } - - /// - Tensor IOps.MatMul(Tensor X, int rankX, Tensor Y, int rankY) - { - var O = m_Ops.MatMul(X, rankX, Y, rankY); - - m_Alu += (long)X.height * (long)X.width * (long)Y.width * 2L * (long)X.batch * (long)X.channels; - m_Mem += (long)X.length + (long)Y.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - var O = m_Ops.MatMul(X, xTranspose, Y, yTranspose); - m_Alu += (long)X.flatHeight * (long)X.flatWidth * (long)Y.flatWidth * 2L; - m_Mem += (long)X.length + (long)Y.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - var O = m_Ops.Dense(X, W, B, fusedActivation); - m_Alu += (long)X.flatHeight * (long)X.flatWidth * (long)W.flatWidth * 2L; - m_Mem += (long)X.length + (long)W.length + (long)B.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Dense3(Tensor X, Tensor W, Tensor B) - { - var O = m_Ops.Dense3(X, W, B); - - m_Alu += (long)X.height * (long)X.width * (long)W.width * 2L * (long)X.batch * (long)X.channels; - m_Mem += (long)X.length + (long)W.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - var O = m_Ops.Conv2D(X, K, B, stride, pad, fusedActivation); - long m = (long)O.batch * (long)O.width * (long)O.height; - long n = (long)X.channels; - long k = (long)K.kernelWidth * (long)K.kernelHeight * (long)K.channels; - m_Alu += m * n * k * 2L; - m_Mem += (long)X.length + (long)K.length + (long)B.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Conv3D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - var O = m_Ops.Conv3D(X, K, B, stride, pad, fusedActivation); - long m = (long)O.batch * (long)O.width * (long)O.height * O.depth; - long n = (long)X.channels; - long k = (long)K.kernelSpatialDepth * K.kernelWidth * (long)K.kernelHeight * (long)K.channels; - m_Alu += m * n * k * 2L; - m_Mem += (long)X.length + (long)K.length + (long)B.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - var O = m_Ops.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - long m = (long)O.batch * (long)O.width * (long)O.height; - long n = (long)X.channels; - long k = (long)K.kernelWidth * (long)K.kernelHeight; - m_Alu += m * n * k * 2L; - m_Mem += (long)X.length + (long)K.length + (long)B.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - var O = m_Ops.Conv2DTrans(X, K, B, stride, pad, outputAdjustment, fusedActivation); - long m = (long)O.batch * (long)O.width * (long)O.height; - long n = (long)X.channels; - long k = (long)(K.kernelWidth/stride[1]) * (long)(K.kernelHeight/stride[0]) * (long)K.channels; - m_Alu += m * n * k * 2L; - m_Mem += (long)X.length + (long)K.length + (long)B.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Upsample2D(Tensor X, int[] scale, bool bilinear) - { - var O = m_Ops.Upsample2D(X, scale, bilinear); - m_Alu += (long)O.length * (bilinear ? 8 : 1); - m_Mem += (long)X.length * (bilinear ? 4 : 1) + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Upsample3D(Tensor X, int[] scale, bool trilinear) - { - var O = m_Ops.Upsample3D(X, scale, trilinear); - m_Alu += (long)O.length * (trilinear ? 18 : 1); - m_Mem += (long)X.length * (trilinear ? 8 : 1) + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Resample2D(Tensor X, int[] size, bool bilinear) - { - var O = m_Ops.Resample2D(X, size, bilinear); - m_Alu += (long)O.length * (bilinear ? 8 : 1); - m_Mem += (long)X.length * (bilinear ? 4 : 1) + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.DepthToSpace(Tensor X, int[] scale, Layer.DepthToSpaceMode mode) - { - var O = m_Ops.DepthToSpace(X, scale, mode); - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.SpaceToDepth(Tensor X, int[] scale) - { - var O = m_Ops.SpaceToDepth(X, scale); - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - var O = m_Ops.MaxPool2D(X, pool, stride, pad); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - var O = m_Ops.AvgPool2D(X, pool, stride, pad); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.GlobalMaxPool2D(Tensor X) - { - var O = m_Ops.GlobalMaxPool2D(X); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.GlobalAvgPool2D(Tensor X) - { - var O = m_Ops.GlobalAvgPool2D(X); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.GlobalAvgVariancePool2D(Tensor X) - { - var O = m_Ops.GlobalAvgVariancePool2D(X); - m_Alu += (long)X.length * 2L + (long)O.length; - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - /// - Tensor IOps.Border2D(Tensor X, int[] pad, float value) - { - var O = m_Ops.Border2D(X, pad, value); - m_Alu += 0; - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Border3D(Tensor X, int[] pad, float value) - { - var O = m_Ops.Border3D(X, pad, value); - m_Alu += 0; - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Pad2DReflect(Tensor X, int[] pad) - { - var O = m_Ops.Pad2DReflect(X, pad); - m_Alu += 0; - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Pad2DSymmetric(Tensor X, int[] pad) - { - var O = m_Ops.Pad2DSymmetric(X, pad); - m_Alu += 0; - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Pad2DEdge(Tensor X, int[] pad) - { - var O = m_Ops.Pad2DEdge(X, pad); - m_Alu += 0; - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ScaleBias(Tensor X, Tensor S, Tensor B) - { - Elementwise(X, 2L); - RegisterLayerStats(); - return m_Ops.ScaleBias(X, S, B); - } - - /// - Tensor IOps.Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) - { - var O = m_Ops.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); - m_Alu += (long)X.length * 4L + (long)O.length * 2L; - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.LRN(Tensor X, float alpha, float beta, float bias, int size) - { - var O = m_Ops.LRN(X, alpha, beta, bias, size); - //A bit over conservative. Number of read/alu is lower than `size` when normalisation windows is too large for data at current index. - long sizeL = size; - m_Alu += (long)X.length * (5L + sizeL * 2L); - m_Mem += (long)X.length * (sizeL + 2L); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Dropout(Tensor X, float alpha) - { - Elementwise(X); - return m_Ops.Dropout(X, alpha); - } - - /// - Tensor IOps.RandomNormal(TensorShape s, float mean, float scale, int seed) - { - var O = m_Ops.RandomNormal(s, mean, scale, seed); - // @TODO: not implemented - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.RandomUniform(TensorShape s, float mean, float scale, int seed) - { - var O = m_Ops.RandomUniform(s, mean, scale, seed); - // @TODO: not implemented - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Multinomial(Tensor X, int count, int seed) - { - var O = m_Ops.Multinomial(X, count, seed); - // @TODO: not implemented - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.OneHot(Tensor X, int depth, float onValue, float offValue, int inputRank) - { - var O = m_Ops.OneHot(X, depth, onValue, offValue, inputRank); - // @TODO: not implemented - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.RoiAlign(Tensor X, Tensor rois, Tensor indices, int outputHeight, int outputWidth, int samplingRatio, float spatialScale) - { - var O = m_Ops.RoiAlign(X, rois, indices, outputHeight, outputWidth, samplingRatio, spatialScale); - m_Alu += 4 * outputHeight * outputWidth * samplingRatio * samplingRatio; - m_Mem += 4 * outputHeight * outputWidth * samplingRatio * samplingRatio; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.TopKIndices(Tensor X, int k, int axis, bool largest, bool sorted) - { - var O = m_Ops.TopKIndices(X, k, axis, largest, sorted); - // @TODO: not implemented - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - public Tensor TopKValues(Tensor X, Tensor I, int axis) - { - var O = m_Ops.TopKValues(X, I, axis); - // @TODO: not implemented - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - public Tensor NonZero(Tensor X) - { - var O = m_Ops.NonZero(X); - // @TODO: not implemented - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Relu(Tensor X) - { - Elementwise(X); - RegisterLayerStats(); - return m_Ops.Relu(X); - } - - /// - Tensor IOps.Softmax(Tensor X, int axis) - { - Elementwise(X, Transcendental.Exponent); - RegisterLayerStats(); - return m_Ops.Softmax(X, axis); - } - - /// - Tensor IOps.LogSoftmax(Tensor X, int axis) - { - Elementwise(X, Transcendental.Exponent); - RegisterLayerStats(); - return m_Ops.LogSoftmax(X, axis); - } - - /// - Tensor IOps.Tanh(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Tanh(X); - } - - /// - Tensor IOps.Softplus(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Softplus(X); - } - - /// - Tensor IOps.Sigmoid(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Sigmoid(X); - } - - /// - Tensor IOps.HardSigmoid(Tensor X, float alpha, float beta) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.HardSigmoid(X, alpha, beta); - } - - /// - Tensor IOps.Relu6(Tensor X) - { - Elementwise(X, 4L); - RegisterLayerStats(); - return m_Ops.Relu6(X); - } - - /// - Tensor IOps.Elu(Tensor X, float alpha) - { - Elementwise(X, Transcendental.Exponent); - RegisterLayerStats(); - return m_Ops.Elu(X, alpha); - } - - /// - Tensor IOps.LeakyRelu(Tensor X, float alpha) - { - Elementwise(X, 4L); - RegisterLayerStats(); - return m_Ops.LeakyRelu(X, alpha); - } - - /// - Tensor IOps.Selu(Tensor X, float alpha, float gamma) - { - Elementwise(X, Transcendental.Exponent); - RegisterLayerStats(); - return m_Ops.Selu(X, alpha, gamma); - } - - /// - Tensor IOps.PRelu(Tensor X, Tensor S) - { - Elementwise(X, 4L); - RegisterLayerStats(); - return m_Ops.PRelu(X, S); - } - - /// - Tensor IOps.Swish(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Swish(X); - } - - /// - Tensor IOps.Abs(Tensor X) - { - Elementwise(X); - RegisterLayerStats(); - return m_Ops.Abs(X); - } - - /// - Tensor IOps.Neg(Tensor X) - { - Elementwise(X); - RegisterLayerStats(); - return m_Ops.Neg(X); - } - - /// - Tensor IOps.Ceil(Tensor X) - { - Elementwise(X); - RegisterLayerStats(); - return m_Ops.Ceil(X); - } - - /// - Tensor IOps.Clip(Tensor X, float min, float max) - { - Elementwise(X, 2L); - RegisterLayerStats(); - return m_Ops.Clip(X, min, max); - } - - /// - Tensor IOps.Floor(Tensor X) - { - Elementwise(X); - RegisterLayerStats(); - return m_Ops.Floor(X); - } - - /// - Tensor IOps.Round(Tensor X) - { - Elementwise(X); - RegisterLayerStats(); - return m_Ops.Round(X); - } - - /// - Tensor IOps.Reciprocal(Tensor X) - { - Elementwise(X, Transcendental.Reciprocal); - RegisterLayerStats(); - return m_Ops.Reciprocal(X); - } - - /// - Tensor IOps.Pow(Tensor X, float alpha) - { - Elementwise(X, Transcendental.Pow); - RegisterLayerStats(); - return m_Ops.Pow(X, alpha); - } - - /// - Tensor IOps.Exp(Tensor X) - { - Elementwise(X, Transcendental.Exponent); - RegisterLayerStats(); - return m_Ops.Exp(X); - } - - /// - Tensor IOps.Log(Tensor X) - { - Elementwise(X, Transcendental.Exponent); - RegisterLayerStats(); - return m_Ops.Log(X); - } - - /// - Tensor IOps.Sqrt(Tensor X) - { - Elementwise(X, Transcendental.Root); - RegisterLayerStats(); - return m_Ops.Sqrt(X); - } - - /// - Tensor IOps.Acos(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Acos(X); - } - - /// - Tensor IOps.Acosh(Tensor X) - { - Elementwise(X, Transcendental.Exponent + 1 + Transcendental.Root + 3); - RegisterLayerStats(); - return m_Ops.Acosh(X); - } - - /// - Tensor IOps.Asin(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Asin(X); - } - - /// - Tensor IOps.Asinh(Tensor X) - { - Elementwise(X, Transcendental.Exponent + 1 + Transcendental.Root + 3); - RegisterLayerStats(); - return m_Ops.Asinh(X); - } - - /// - Tensor IOps.Atan(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Atan(X); - } - - /// - Tensor IOps.Atanh(Tensor X) - { - Elementwise(X, 1 + Transcendental.Exponent + 2 + Transcendental.Div); - RegisterLayerStats(); - return m_Ops.Atanh(X); - } - - /// - Tensor IOps.Cos(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Cos(X); - } - - /// - Tensor IOps.Cosh(Tensor X) - { - Elementwise(X, 2 + 2*Transcendental.Exponent); - RegisterLayerStats(); - return m_Ops.Cosh(X); - } - - /// - Tensor IOps.Sin(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Sin(X); - } - - /// - Tensor IOps.Sinh(Tensor X) - { - Elementwise(X, 2 + 2*Transcendental.Exponent); - RegisterLayerStats(); - return m_Ops.Sinh(X); - } - - /// - Tensor IOps.Tan(Tensor X) - { - Elementwise(X, Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Tan(X); - } - - /// - Tensor IOps.Erf(Tensor X) - { - Elementwise(X, 1 + Transcendental.Trigonometric); - RegisterLayerStats(); - return m_Ops.Erf(X); - } - - /// - Tensor IOps.Add(Tensor[] tensors) - { - var O = m_Ops.Add(tensors); - ElementwiseBroadcast(tensors, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Sub(Tensor[] tensors) - { - var O = m_Ops.Sub(tensors); - ElementwiseBroadcast(tensors, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Mul(Tensor[] tensors) - { - var O = m_Ops.Mul(tensors); - ElementwiseBroadcast(tensors, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Div(Tensor[] tensors) - { - var O = m_Ops.Div(tensors); - ElementwiseBroadcast(tensors, O, Transcendental.Div); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Pow(Tensor[] tensors) - { - var O = m_Ops.Pow(tensors); - ElementwiseBroadcast(tensors, O, Transcendental.Pow); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Min(Tensor[] tensors) - { - var O = m_Ops.Min(tensors); - ElementwiseBroadcast(tensors, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Max(Tensor[] tensors) - { - var O = m_Ops.Max(tensors); - ElementwiseBroadcast(tensors, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Mean(Tensor[] tensors) - { - var O = m_Ops.Mean(tensors); - ElementwiseBroadcast(tensors, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ArgMax(Tensor X, int axis) - { - var O = m_Ops.ArgMax(X, axis); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ArgMin(Tensor X, int axis) - { - var O = m_Ops.ArgMin(X, axis); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ReduceMax(Tensor X, int axis) - { - var O = m_Ops.ReduceMax(X, axis); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ReduceMean(Tensor X, int axis) - { - var O = m_Ops.ReduceMean(X, axis); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ReduceMin(Tensor X, int axis) - { - var O = m_Ops.ReduceMin(X, axis); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ReduceProd(Tensor X, int axis) - { - var O = m_Ops.ReduceProd(X, axis); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ReduceSum(Tensor X, int axis) - { - var O = m_Ops.ReduceSum(X, axis); - Reduce(X, O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Greater(Tensor a, Tensor b) - { - var O = m_Ops.Greater(a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.GreaterEqual(Tensor a, Tensor b) - { - var O = m_Ops.GreaterEqual(a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Less(Tensor a, Tensor b) - { - var O = m_Ops.Less(a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.LessEqual(Tensor a, Tensor b) - { - var O = m_Ops.LessEqual(a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Equal(Tensor a, Tensor b) - { - var O = m_Ops.Equal(a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.LogicalOr(Tensor a, Tensor b) - { - var O = m_Ops.LogicalOr(a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.LogicalAnd(Tensor a, Tensor b) - { - var O = m_Ops.LogicalAnd(a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.LogicalXor(Tensor a, Tensor b) - { - var O = m_Ops.LogicalXor(a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.LogicalNot(Tensor x) - { - var O = m_Ops.LogicalNot(x); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Sign(Tensor x) - { - var O = m_Ops.Sign(x); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Where(Tensor c, Tensor a, Tensor b) - { - var O = m_Ops.Where(c, a, b); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Flatten(Tensor X) - { - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return m_Ops.Flatten(X); - } - - /// - Tensor IOps.Reshape(Tensor X, TensorShape shape) - { - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return m_Ops.Reshape(X, shape); - } - - /// - Tensor IOps.Expand(Tensor X, TensorShape shape) - { - var O = m_Ops.Expand(X, shape); - m_Alu += 0; - m_Mem += (long)X.length + (long)O.length; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Transpose(Tensor X) - { - Elementwise(X); - RegisterLayerStats(); - return m_Ops.Transpose(X); - } - - /// - Tensor IOps.Transpose(Tensor X, int[] permutations) - { - Elementwise(X); - RegisterLayerStats(); - return m_Ops.Transpose(X, permutations); - } - - /// - Tensor IOps.Gather(Tensor[] tensors, int axis) - { - var O = m_Ops.Gather(tensors, axis); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - // - Tensor IOps.ScatterND(Tensor X, Tensor indices, Tensor updates, Layer.ScatterNDReductionMode reduction) - { - var O = m_Ops.ScatterND(X, indices, updates, reduction); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.NonMaxSuppression(Tensor[] tensors, int maxOutputBoxesPerClass, float iouThreshold, float scoreThreshold, int centerPointBox) - { - var O = m_Ops.NonMaxSuppression(tensors, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, centerPointBox); - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - public Tensor[] LSTM(Tensor X, Tensor[] W, Tensor[] R, Tensor[] Wb, Tensor[] Rb, Tensor hidden, Tensor cell) - { - var O = m_Ops.LSTM(X, W, R, Wb, Rb, hidden, cell); - // @TODO: not implemented - m_Alu += 0; - m_Mem += 0; - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Concat(Tensor[] tensors, int axis) - { - var O = m_Ops.Concat(tensors, axis); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.StridedSlice(Tensor X, int[] starts, int[] ends, int[] strides) - { - var O = m_Ops.StridedSlice(X, starts, ends, strides); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Tile(Tensor X, int[] repeats) - { - var O = m_Ops.Tile(X, repeats); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Shape(Tensor X, int axis) - { - var O = m_Ops.Shape(X, axis); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.ConstantOfShape(TensorShape X, DataType type, float value) - { - var O = m_Ops.ConstantOfShape(X, type, value); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Copy(Tensor x) - { - var O = m_Ops.Copy(x); - Elementwise(O); - RegisterLayerStats(); - return O; - } - - /// - Tensor IOps.Prepare(Tensor X) - { - return m_Ops.Prepare(X); - } - - /// - Tensor IOps.PrepareNoAlloc(Tensor X) - { - return m_Ops.PrepareNoAlloc(X); - } - - /// - void IOps.ResetAllocator(bool keepCachedMemory) - { - m_Ops.ResetAllocator(keepCachedMemory); - m_Alu = new LayerStat(0L, 0L); - m_Mem = new LayerStat(0L, 0L); - } - - /// - void IOps.SetModelExecutionsReporter(IModelExecutionsReporter executionsReporter) - { - m_Ops.SetModelExecutionsReporter(executionsReporter); - } - - /// - public IModelExecutionsReporter GetModelExecutionsReporter() - { - return m_Ops.GetModelExecutionsReporter(); - } - - /// - /// Build execution summary - /// - /// execution summary - public override string ToString() - { - string alu = m_Alu.ToString(); - if (m_Alu > 1e12) - alu = $"{(double)m_Alu / (1e12):###.0}T"; - else if (m_Alu > 1e9) - alu = $"{(double)m_Alu / (1e9):###.0}G"; - else if (m_Alu > 1e6) - alu = $"{(double)m_Alu / (1e6):###.0}M"; - - var mem4 = m_Mem * 4L; - string mem = mem4.ToString(); - if (mem4 > 1024*1024*1024) - mem = $"{(double)mem4 / (1024*1024*1024):###.0}Gb"; - else if (mem4 > 1024*1024) - mem = $"{(double)mem4 / (1024*1024):###.0}Mb"; - return $"ALU operations: {alu} bytes accessed: {mem}"; - } - - private void RegisterLayerStats() - { -#if ENABLE_BARRACUDA_STATS - GetModelExecutionsReporter()?.SetLayerALUAndMemStats(m_Alu.layer, m_Mem.layer); -#endif //ENABLE_BARRACUDA_STATS - } - - // ----- - internal void Elementwise(Tensor X, long aluOperationsPerElement = 1L) - { - m_Alu += (long)X.length * aluOperationsPerElement; - m_Mem += (long)X.length * 2L; - } - - internal void ElementwiseBroadcast(Tensor[] tensors, Tensor X, long aluOperationsPerElement = 1L) - { - m_Alu += (long)X.length * aluOperationsPerElement; - long mem = (long)X.length; - foreach (var t in tensors) - mem += (long)t.length; - m_Mem += mem; - } - - internal void Reduce(Tensor X, Tensor O, long aluOperationsPerElement = 1L) - { - m_Alu += (long)X.length * aluOperationsPerElement; - m_Mem += (long)X.length + (long)O.length; - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/StatsOps.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/StatsOps.cs.meta deleted file mode 100644 index 6f4724a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/StatsOps.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 326d2411861b248059757b7e98e3a101 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorAllocators.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorAllocators.cs deleted file mode 100644 index 7e5425f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorAllocators.cs +++ /dev/null @@ -1,790 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; // ToList() - -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; - -namespace Unity.Barracuda { - -// @TODO: reduce code duplication between TensorCachingByShapeAllocator and TensorCachingAllocator -internal class TensorCachingByShapeAllocator : ITensorAllocator -{ - struct Entry - { - public TensorShape shape; - public ITensorData buffer; - public CacheKey ToKey() { return new CacheKey { shape = shape, dataType = buffer.dataType }; } - } - - struct CacheKey - { - public TensorShape shape; - public DataType dataType; - } - - // multi-value Dictionary implemented via - // pair of m_FreeTensorByShape and m_FreeTensors - private Dictionary> m_FreeBufferByShape = new Dictionary>(); - private LinkedList m_FreeBuffers = new LinkedList(); - private Dictionary m_BusyTensors = new Dictionary(); - private Dictionary m_SharedBuffers = new Dictionary(); - - public TensorCachingByShapeAllocator() - { - } - - ~TensorCachingByShapeAllocator() - { - Dispose(); - } - - protected void AddRef(ITensorData buffer) - { - if (buffer == null) - return; - - var sharedBufferCount = 0; - m_SharedBuffers.TryGetValue(buffer, out sharedBufferCount); - m_SharedBuffers[buffer] = sharedBufferCount + 1; - } - - protected void DecRef(ITensorData buffer, Action onLastRef = null) - { - if (buffer == null) - return; - - Assert.IsTrue(m_SharedBuffers.ContainsKey(buffer)); - Assert.IsTrue(m_SharedBuffers[buffer] > 0); - if (--m_SharedBuffers[buffer] > 0) - return; - - m_SharedBuffers.Remove(buffer); - - if (onLastRef != null) - onLastRef(buffer); - } - - protected void AdoptFreeBuffer(TensorShape shape, ITensorData buffer) - { - // code below automatically covers handles edge-case (2) - // by adopting tensor's with the new ITensorData into m_FreeTensors/m_FreeTensorByShape - var newEntry = new Entry { shape = shape, buffer = buffer }; - var key = newEntry.ToKey(); - LinkedListNode node; - if (m_FreeBufferByShape.TryGetValue(key, out node)) - { - m_FreeBuffers.AddAfter(node, newEntry); - } - else - { - var newNode = m_FreeBuffers.AddLast(newEntry); - m_FreeBufferByShape.Add(key, newNode); - } - } - - public virtual Tensor Alloc(TensorShape shape, AllocScope scope, DataType dataType) - { - Profiler.BeginSample("Barracuda.ShapeAllocator.Alloc"); - var name = "untitled"; - var key = new CacheKey { shape = shape, dataType = dataType }; - LinkedListNode node; - if (m_FreeBufferByShape.TryGetValue(key, out node)) - { - Assert.AreEqual(node.Value.shape, shape); - - // advance dictionary to the next Tensor with the same shape, if available - if (node.Next != null && node.Next.Value.shape == shape) - m_FreeBufferByShape[key] = node.Next; - else - m_FreeBufferByShape.Remove(key); - - var buffer = node.Value.buffer; - buffer?.Reserve(shape.length); - - var tensor = new Tensor(shape, buffer, this); // @TODO: reuse Tensor instances - tensor.name = name; - - m_FreeBuffers.Remove(node); - m_BusyTensors.Add(tensor, buffer); - AddRef(buffer); - - Assert.AreEqual(tensor.shape, shape); - Profiler.EndSample(); - return tensor; - } - - var newTensor = new Tensor(shape, this); - newTensor.name = name; - m_BusyTensors.Add(newTensor, newTensor.tensorOnDevice); - AddRef(newTensor.tensorOnDevice); - - Profiler.EndSample(); - return newTensor; - } - - public virtual Tensor Alloc(TensorShape shape, ITensorData buffer, AllocScope scope, DataType dataType) - { - Profiler.BeginSample("Barracuda.ShapeAllocator.Alloc"); - var name = "untitled"; - - var tensor = new Tensor(shape, buffer, this); // @TODO: reuse Tensor instances - tensor.name = name; - m_BusyTensors.Add(tensor, buffer); - AddRef(buffer); - - Profiler.EndSample(); - return tensor; - } - - public virtual void PostLayerCleanup() - { - - } - - public virtual void Release(Tensor tensor, bool calledFromTensorDispose) - { - Profiler.BeginSample("Barracuda.ShapeAllocator.Release"); - Assert.AreEqual(tensor.allocator, this); - - var detachedBuffer = tensor.Invalidate(); // calls MoveToDevice(newBuffer=null) - - if (!m_BusyTensors.ContainsKey(tensor)) - { - if (detachedBuffer == null) - return; - - foreach (var freeEntry in m_FreeBuffers) - if (freeEntry.buffer == detachedBuffer) - return; - - // some operations can create new Tensor and reassign ITensorData to it - foreach (var busyEntry in m_BusyTensors) - if (busyEntry.Value == detachedBuffer) - return; // we have at least another instance ITensorData in m_BusyTensors, nothing to realease - } - - Assert.IsTrue(m_BusyTensors.ContainsKey(tensor)); - m_BusyTensors.Remove(tensor); - Profiler.EndSample(); - } - - public virtual void MoveToDevice(Tensor tensor, ITensorData newBuffer, ITensorData oldBuffer, bool disposeDetachedBufferHint) - { - if (newBuffer == oldBuffer) - return; - - Assert.AreEqual(tensor.allocator, this); - Assert.IsTrue(m_BusyTensors.ContainsKey(tensor)); - m_BusyTensors[tensor] = newBuffer; - - AddRef(newBuffer); - DecRef(oldBuffer, - (freeBuffer) => { - if (disposeDetachedBufferHint) - freeBuffer.Dispose(); - else - AdoptFreeBuffer(tensor.shape, freeBuffer); - }); - } - - public virtual void Reset(bool keepCachedMemory) - { - Profiler.BeginSample("Barracuda.ShapeAllocator.Reset"); - - if (!keepCachedMemory) - Dispose(); - - foreach (var tensor in m_BusyTensors.Keys.ToList()) - Release(tensor, false); - - Assert.AreEqual(m_BusyTensors.Count, 0); - Assert.AreEqual(m_SharedBuffers.Count, 0); - - Profiler.EndSample(); - } - - public virtual void WaiveOwnership(Tensor tensor) - { - Assert.AreEqual(tensor.allocator, this); - Assert.IsTrue(m_BusyTensors.ContainsKey(tensor)); - m_BusyTensors.Remove(tensor); - - var buffer = tensor.tensorOnDevice; - if (buffer == null) - return; - - Profiler.BeginSample("Barracuda.ShapeAllocator.WaiveOwnership"); - - int sharedCount = 0; - m_SharedBuffers.TryGetValue(buffer, out sharedCount); - if (sharedCount > 1) - { - var patchBusyTensors = new List(); - foreach (var busyEntry in m_BusyTensors) - if (busyEntry.Value == buffer) - patchBusyTensors.Add(busyEntry.Key); - - Assert.AreEqual(sharedCount - 1, patchBusyTensors.Count); - - foreach (var busyTensor in patchBusyTensors) - { - Assert.AreEqual(m_BusyTensors[busyTensor], buffer); - - var oldBuffer = busyTensor.DetachFromDevice(false); - var newBuffer = busyTensor.tensorOnDevice; - Assert.IsTrue(oldBuffer == buffer); - Assert.IsTrue(newBuffer != buffer); - m_BusyTensors[busyTensor] = newBuffer; - AddRef(newBuffer); - } - } - - // Assert no references to tensor are left owned by allocator - Assert.IsTrue(m_SharedBuffers[buffer] == 1); - m_SharedBuffers.Remove(buffer); - foreach (var freeEntry in m_FreeBuffers) - { - Assert.IsTrue(freeEntry.buffer != buffer); - } - foreach (var busyEntry in m_BusyTensors) - { - Assert.IsTrue(busyEntry.Key != tensor); - Assert.IsTrue(busyEntry.Value != buffer); - } - - Profiler.EndSample(); - } - - public virtual void Dispose() - { - m_FreeBufferByShape.Clear(); - foreach (var tensor in m_BusyTensors.Keys.ToList()) - Release(tensor, false); - foreach (var entry in m_FreeBuffers) - entry.buffer?.Dispose(); - - m_BusyTensors.Clear(); - m_FreeBuffers.Clear(); - m_SharedBuffers.Clear(); - } - -#if ENABLE_BARRACUDA_STATS -public long usedBytes => busyBytes; - -public long busyBytes -{ get { - long bytes = 0; - //Dictionary to account for shallow copies of Tensors. - Dictionary tensorDatas = new Dictionary(); - foreach (var tensor in m_BusyTensors.Keys) - { - if (tensor.tensorOnDevice != null) - tensorDatas[tensor.tensorOnDevice.uniqueId] = tensor.tensorOnDevice; - } - foreach (var tensorData in tensorDatas) - bytes += tensorData.Value.maxCapacity * sizeof(float); - - return bytes; -} } -public long freeBytes -{ get { - long bytes = 0; - foreach(var entry in m_FreeBuffers) - bytes += entry.shape.length * sizeof(float); - return bytes; -} } -public long totalBytes -{ get { - return busyBytes + freeBytes; -} } -public override string ToString() -{ - return "Total allocated: " + totalBytes + " busy: " + busyBytes; -} -#endif //ENABLE_BARRACUDA_STATS -} - - - -/// -/// Caching `Tensor` allocator -/// -public class TensorCachingAllocator : UniqueResourceId, ITensorAllocator, IAllocatorStatistics -{ - public string name { get; set; } - - struct Entry : ITensorDataStatistics - { - public int size; - public ITensorData tensorData; - public bool free; - - //ITensorDataStatistics - public int maxCapacity => tensorData.maxCapacity; - public DataType dataType => tensorData.dataType; -#if ENABLE_BARRACUDA_STATS - public int uniqueId => tensorData.uniqueId; - public bool inUse => !free; - public bool isGPUMem => tensorData.isGPUMem; -#endif //ENABLE_BARRACUDA_STATS - } - // Sorted by size array of ITensorData - private List m_AllocatedBuffers = new List(); - private Dictionary m_BusyTensors = new Dictionary(); - private Dictionary m_SharedBuffers = new Dictionary(); - - private Action disposeAllocatedBufferDelegate; - private Action adoptFreeBufferDelegate; - - // Stores only hollow tensor objects, tensor data is stored by m_AllocatedBuffers - private List m_AllocatedTensors = new List(); - private int m_NumAllocatedBufferSinceCleanup = 0; - - /// - /// Create `TensorCachingAllocator` - /// - public TensorCachingAllocator() - { - name = "Caching Allocator"; - disposeAllocatedBufferDelegate = DisposeAllocatedBuffer; - adoptFreeBufferDelegate = AdoptFreeBuffer; - } - - /// - /// Finalizer - /// - ~TensorCachingAllocator() - { - Dispose(); - } - - internal Tensor AllocTensorInternal(DataType dataType, TensorShape shape, ITensorData buffer) - { - Tensor res = null; - - lock (m_AllocatedTensors) - { - if (m_AllocatedTensors.Count > 0) - { - res = m_AllocatedTensors.Last(); - res.Init(shape, buffer, this, dataType); - m_AllocatedTensors.RemoveAt(m_AllocatedTensors.Count - 1); - } - else - { - res = new Tensor(shape, buffer, this, dataType); - } - } - - return res; - } - - internal void AddRef(ITensorData buffer) - { - if (buffer == null) - return; - - var sharedBufferCount = 0; - m_SharedBuffers.TryGetValue(buffer, out sharedBufferCount); - m_SharedBuffers[buffer] = sharedBufferCount + 1; - } - - internal void DecRef(ITensorData buffer, Action onLastRef = null) - { - if (buffer == null) - return; - - Assert.IsTrue(m_SharedBuffers.ContainsKey(buffer)); - Assert.IsTrue(m_SharedBuffers[buffer] > 0); - if (--m_SharedBuffers[buffer] > 0) - return; - - m_SharedBuffers.Remove(buffer); - - if (onLastRef != null) - onLastRef(buffer); - } - - internal void AdoptFreeBuffer(ITensorData buffer) - { - // insert into the sorted array - var size = buffer.maxCapacity; - var newEntry = new Entry { size = size, tensorData = buffer, free = true }; - bool found = false; - for (int i = 0; !found && i < m_AllocatedBuffers.Count; ++i) - { - var entry = m_AllocatedBuffers[i]; - if (buffer == entry.tensorData) - { - Assert.IsTrue(!entry.free); - entry.free = true; - m_AllocatedBuffers[i] = entry; - Assert.IsTrue(m_AllocatedBuffers[i].free); - found = true; - } - if (size < entry.size) - { - m_AllocatedBuffers.Insert(i, newEntry); - Assert.IsTrue(m_AllocatedBuffers[i].size < m_AllocatedBuffers[i + 1].size); - found = true; - } - } - - if (!found) - m_AllocatedBuffers.Add(newEntry); - } - - internal void DisposeAllocatedBuffer(ITensorData buffer) - { - for (int i = m_AllocatedBuffers.Count - 1; i >= 0; i--) - if (m_AllocatedBuffers[i].tensorData == buffer) - m_AllocatedBuffers.RemoveAt(i); - buffer.Dispose(); - } - - /// - public virtual Tensor Alloc(TensorShape shape, AllocScope scope, DataType dataType) - { - Profiler.BeginSample("Barracuda.SizeAllocator.Alloc"); - var name = "untitled"; - - for (int i = 0; i < m_AllocatedBuffers.Count; ++i) - { - var entry = m_AllocatedBuffers[i]; - if (entry.size >= shape.length && entry.dataType == dataType && entry.free) - { - entry.free = false; - m_AllocatedBuffers[i] = entry; - - ITensorData buffer = entry.tensorData; - buffer?.Reserve(shape.length); - - var tensor = AllocTensorInternal(dataType, shape, buffer); - tensor.name = name; - - m_BusyTensors.Add(tensor, tensor.tensorOnDevice); - AddRef(tensor.tensorOnDevice); - - Profiler.EndSample(); - return tensor; - } - } - - ++m_NumAllocatedBufferSinceCleanup; - - var newTensor = AllocTensorInternal(dataType, shape, null); - newTensor.name = name; - m_BusyTensors.Add(newTensor, newTensor.tensorOnDevice); - AddRef(newTensor.tensorOnDevice); - - Profiler.EndSample(); - return newTensor; - } - - /// - public virtual Tensor Alloc(TensorShape shape, ITensorData buffer, AllocScope scope, DataType dataType) - { - Profiler.BeginSample("Barracuda.SizeAllocator.Alloc"); - var name = "untitled"; - - var tensor = AllocTensorInternal(dataType, shape, buffer); - tensor.name = name; - m_BusyTensors.Add(tensor, tensor.tensorOnDevice); - AddRef(tensor.tensorOnDevice); - - Profiler.EndSample(); - return tensor; - } - - /// - public virtual void PostLayerCleanup() - { - //This allocator does not have support for allocation scope, - //all tensors live until Reset() is called. - - //however allocation of new buffer are tracked for debug warning purpose - //reset here to help catch context of those allocation (potential leaks) - m_NumAllocatedBufferSinceCleanup = 0; - } - - /// - public virtual void Release(Tensor tensor, bool calledFromTensorDispose) - { - Profiler.BeginSample("Barracuda.SizeAllocator.Release"); - Assert.AreEqual(tensor.allocator, this); - - var detachedBuffer = tensor.Invalidate(); // calls MoveToDevice(newBuffer=null,disposeDetachedBufferHint=false) - - if (calledFromTensorDispose) - { - lock (m_AllocatedTensors) - { - m_AllocatedTensors.Add(tensor); - tensor.name = ""; - } - } - - if (!m_BusyTensors.ContainsKey(tensor)) - { - if (detachedBuffer == null) - return; - - foreach (var entry in m_AllocatedBuffers) - if (entry.tensorData == detachedBuffer && entry.free) - return; - - // some operations can create new Tensor and reassign ITensorData to it - foreach (var busyEntry in m_BusyTensors) - if (busyEntry.Value == detachedBuffer) - return; // we have original ITensorData in m_BusyTensors, nothing to realease - } - - Assert.IsTrue(m_BusyTensors.ContainsKey(tensor)); - m_BusyTensors.Remove(tensor); - - - Profiler.EndSample(); - } - - /// - public virtual void MoveToDevice(Tensor tensor, ITensorData newBuffer, ITensorData oldBuffer, bool disposeDetachedBufferHint) - { - if (newBuffer == oldBuffer) - return; - - Assert.AreEqual(tensor.allocator, this); - Assert.IsTrue(m_BusyTensors.ContainsKey(tensor)); - m_BusyTensors[tensor] = newBuffer; - - AddRef(newBuffer); - - if (disposeDetachedBufferHint) - DecRef(oldBuffer, disposeAllocatedBufferDelegate); - else - DecRef(oldBuffer, adoptFreeBufferDelegate); - } - - /// - public virtual void Reset(bool keepCachedMemory) - { - Profiler.BeginSample("Barracuda.SizeAllocator.Reset"); - - if (!keepCachedMemory) - Dispose(); - - foreach(var tensor in m_BusyTensors.Keys.ToList()) - Release(tensor, false); - - Assert.AreEqual(m_BusyTensors.Count, 0); - Assert.AreEqual(m_SharedBuffers.Count, 0); - - foreach(var buf in m_AllocatedBuffers) - Assert.IsTrue(buf.free); - - Profiler.EndSample(); - } - - /// - public virtual void WaiveOwnership(Tensor tensor) - { - Assert.AreEqual(tensor.allocator, this); - Assert.IsTrue(m_BusyTensors.ContainsKey(tensor)); - m_BusyTensors.Remove(tensor); - - var buffer = tensor.tensorOnDevice; - if (buffer == null) - return; - - Profiler.BeginSample("Barracuda.SizeAllocator.WaiveOwnership"); - - int sharedCount = 0; - m_SharedBuffers.TryGetValue(buffer, out sharedCount); - if (sharedCount > 1) - { - var patchBusyTensors = new List(); - foreach (var busyEntry in m_BusyTensors) - if (busyEntry.Value == buffer) - patchBusyTensors.Add(busyEntry.Key); - - Assert.AreEqual(sharedCount - 1, patchBusyTensors.Count); - - foreach (var busyTensor in patchBusyTensors) - { - Assert.AreEqual(m_BusyTensors[busyTensor], buffer); - - var oldBuffer = busyTensor.DetachFromDevice(false); - var newBuffer = busyTensor.tensorOnDevice; - Assert.IsTrue(oldBuffer == buffer); - Assert.IsTrue(newBuffer != buffer); - m_BusyTensors[busyTensor] = newBuffer; - AddRef(newBuffer); - } - } - - // Assert no references to tensor are left owned by allocator - Assert.IsTrue(m_SharedBuffers[buffer] == 1); - m_SharedBuffers.Remove(buffer); - - int countInAllocatedBuffers = 0; - for (int i = 0; i < m_AllocatedBuffers.Count; i++) - { - Entry entry = m_AllocatedBuffers[i]; - if (entry.tensorData == buffer) - { - Assert.IsFalse(entry.free); - m_AllocatedBuffers.RemoveAt(i); - countInAllocatedBuffers++; - } - } - // This entry should have only been in the allocated buffers once at most - Assert.IsTrue(countInAllocatedBuffers <= 1); - - foreach(var busyEntry in m_BusyTensors) - { - Assert.IsTrue(busyEntry.Key != tensor); - Assert.IsTrue(busyEntry.Value != buffer); - } - - Profiler.EndSample(); - } - - /// - /// Dispose all allocated buffers - /// - public virtual void Dispose() - { - foreach(var tensor in m_BusyTensors.Keys.ToList()) - Release(tensor, false); - foreach (var entry in m_AllocatedBuffers) - entry.tensorData?.Dispose(); - - m_BusyTensors.Clear(); - m_AllocatedBuffers.Clear(); - m_AllocatedTensors.Clear(); - m_SharedBuffers.Clear(); - } - - /// - /// Return the number of buffer allocated since last call to LastLayerCleanup() - /// - internal int NumAllocatedBufferSinceCleanup - { - get { return m_NumAllocatedBufferSinceCleanup; } - } - - /// - /// Return true if the allocator is ready to be asked for a new ping pong buffer - /// - internal bool IsPingPongReady - { - get { return NumAllocatedBuffer == 2 && NumFreeBuffer >= 1; } - } - - private int NumAllocatedBuffer - { - get { return m_AllocatedBuffers.Count; } - } - - private int NumFreeBuffer - { - get { return m_AllocatedBuffers.Count(e => e.free); } - } - -#if ENABLE_BARRACUDA_STATS - /// - public long usedBytes - { get { - long bytes = 0; - - Dictionary usedSizePerTensorDataId = new Dictionary(); - foreach (var tensorAnDataPair in m_BusyTensors) - { - var tensor = tensorAnDataPair.Key; - var tensorData = tensorAnDataPair.Value; - Assert.IsTrue(tensor.shape.length <= tensorData.maxCapacity); - if (usedSizePerTensorDataId.ContainsKey(tensorData.uniqueId)) - Assert.AreEqual(usedSizePerTensorDataId[tensorData.uniqueId], tensor.shape.length); - else - usedSizePerTensorDataId[tensorData.uniqueId] = tensor.shape.length; - } - - foreach (var usedSizeForTensorData in usedSizePerTensorDataId.Values) - { - bytes += usedSizeForTensorData * sizeof(float); - } - - return bytes; - } } - - /// - public long busyBytes - { get { - long bytes = 0; - //Dictionary to account for shallow copies of Tensors. - Dictionary tensorDatas = new Dictionary(); - foreach (var tensor in m_BusyTensors.Keys) - { - if (tensor.tensorOnDevice != null) - tensorDatas[tensor.tensorOnDevice.uniqueId] = tensor.tensorOnDevice; - } - foreach (var tensorData in tensorDatas) - bytes += tensorData.Value.maxCapacity * sizeof(float); - - return bytes; - } } - - /// - public long freeBytes - { get { - long bytes = 0; - foreach(var entry in m_AllocatedBuffers) - if (entry.free) - bytes += entry.size * sizeof(float); - return bytes; - } } - - /// - public long totalBytes - { get { - return busyBytes + freeBytes; - } } - - /// - public IEnumerable GetTensorsStatistics() - { - foreach (var busyTensor in m_BusyTensors) - { - yield return busyTensor.Key; - } - } - - /// - public IEnumerable GetTensorDatasStatistics() - { - Dictionary tensorDataStats = new Dictionary(); - foreach (var allocatedBuffer in m_AllocatedBuffers) - { - tensorDataStats[allocatedBuffer.uniqueId] = allocatedBuffer; - } - foreach (var sharedBuffer in m_SharedBuffers) - { - tensorDataStats[sharedBuffer.Key.uniqueId] = sharedBuffer.Key; - } - return tensorDataStats.Values; - } - - /// - /// Summary - /// - /// summary - public override string ToString() - { - return "Total allocated: " + totalBytes + " busy: " + busyBytes; - } -#endif //ENABLE_BARRACUDA_STATS -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorAllocators.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorAllocators.cs.meta deleted file mode 100644 index bfbd36c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorAllocators.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1c30b359da14d4b02a55e7c9806058f1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorScope.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorScope.cs deleted file mode 100644 index b5a0e0f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorScope.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Unity.Barracuda -{ - -/// -/// Utility class to help with disposing tensors automatically: -/// Example usage: -/// using (var td = new TensorScope()) -/// { -/// TensorScope.F _ = td._; // Function pointer to have less "visual noise" when making use of this -/// var t1 = _(m_Ops.(...)); -/// var t2 = _(m_Ops.(...)); -/// var t3 = _(m_Ops.(...)); -/// ... -/// } -/// -/// or alternatively it can depend on another tensor being disposed -/// -/// var td = new TensorScope(); -/// { -/// TensorScope.F _ = td._; // Function pointer to have less "visual noise" when making use of this -/// var t1 = _(m_Ops.(...)); -/// var t2 = _(m_Ops.(...)); -/// var t3 = _(m_Ops.(...));g -/// ... -/// } -/// O = m_Ops.(...); -/// td.DependentOn(O); -/// -class TensorScope : IDisposable -{ - public delegate Tensor F(Tensor tensor); - HashSet m_Tensors = new HashSet(); - Tensor m_DependentOnTensor; - - public Tensor _(Tensor tensor) - { - m_Tensors.Add(tensor); - return tensor; - } - - public bool Remove(Tensor tensor) - { - return m_Tensors.Remove(tensor); - } - - public void DependentOn(Tensor tensor) - { - Tensor.tensorDisposed -= DependentDispose; // Prevents multiple subscribes - m_DependentOnTensor = tensor; - Tensor.tensorDisposed += DependentDispose; - } - - void DependentDispose(Tensor tensor) - { - if (m_DependentOnTensor == tensor) - { - m_DependentOnTensor = null; - Tensor.tensorDisposed -= DependentDispose; - Dispose(); - } - } - - public void Dispose() - { - foreach (Tensor t in m_Tensors) - t.Dispose(); - m_Tensors.Clear(); - m_DependentOnTensor = null; - } -} - -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorScope.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorScope.cs.meta deleted file mode 100644 index 2cde85a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/TensorScope.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 180f5d96733109e4695dbccd0ab6bcf5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/VerboseOps.cs b/Packages/com.unity.barracuda/Runtime/Core/Backends/VerboseOps.cs deleted file mode 100644 index ad1d1b9..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/VerboseOps.cs +++ /dev/null @@ -1,1111 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Unity.Barracuda { - - /// - /// Verbose proxy to other `IOps` implementation - /// -public class VerboseOps : IOps, IModelCompiler -{ - private bool m_UseUnityLogFile; - private IOps m_Ops; - private const string Prefix = "After "; - - /// - /// Create `VerboseOps` for target `ops` - /// - /// target `IOps` instance - /// produce log in Unity standard log file, model execution reporter from IOps will always be used if it exist. - public VerboseOps(IOps ops, bool useUnityLogFile = true) - { - m_Ops = ops; - m_UseUnityLogFile = useUnityLogFile; - } - -#if ENABLE_BARRACUDA_STATS - /// - public IEnumerable GetTempMemoryStatistics() - { - return m_Ops.GetTempMemoryStatistics(); - } -#endif //ENABLE_BARRACUDA_STATS - - /// - public virtual void PrepareModel(Model model, IDictionary inputShapes, IVars vars) - { - if (m_Ops is IModelCompiler) - ((IModelCompiler)m_Ops).PrepareModel(model, inputShapes, vars); - } - - /// - public virtual void PostLayerCleanup() - { - m_Ops.PostLayerCleanup(); - } - - /// - public virtual void PreExecuteLayer(Layer layer, Tensor[] inputs) - { - if (m_Ops is IModelCompiler) - ((IModelCompiler)m_Ops).PreExecuteLayer(layer, inputs); - } - - /// - Tensor IOps.MatMul(Tensor X, int rankX, Tensor Y, int rankY) - { - LogLayerSummary(rankX + ":(" + X.batch * X.channels + "," + X.height + "," + X.width + ")" + - " *" + rankY + ":(" + Y.batch * Y.channels + "," + Y.height + "," + Y.width + ")"); - var O = m_Ops.MatMul(X, rankX, Y, rankY); - LogOutputTensorSummary(O, Prefix + "MatMul"); - return O; - } - - /// - Tensor IOps.MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) - { - - LogLayerSummary("(" + X.flatHeight + "," + X.flatWidth + ")" + (xTranspose ? ".T" : "") + - " * (" + Y.flatHeight + "," + Y.flatWidth + ")" + (yTranspose ? ".T" : "")); - var O = m_Ops.MatMul(X, xTranspose, Y, yTranspose); - LogOutputTensorSummary(O, Prefix + "MatMul"); - return O; - } - - /// - Tensor IOps.Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) - { - LogLayerSummary(X.shape + " * (" + W.flatHeight + "," + W.flatWidth + ") + (" + B.flatWidth + ")"); - var O = m_Ops.Dense(X, W, B, fusedActivation); - LogOutputTensorSummary(O, Prefix + "Dense"); - return O; - } - - /// - Tensor IOps.Dense3(Tensor X, Tensor W, Tensor B) - { - LogLayerSummary(X.shape + " * (" + W.flatHeight + "," + W.flatWidth + ") + (" + B.flatWidth + ")"); - var O = m_Ops.Dense3(X, W, B); - LogOutputTensorSummary(O, Prefix + "Dense3"); - return O; - } - - /// - Tensor IOps.Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - LogLayerSummary(X.shape + " # " + K.shape + " + (" + B.flatWidth + ")"); - var O = m_Ops.Conv2D(X, K, B, stride, pad, fusedActivation); - LogOutputTensorSummary(O, Prefix + "Conv2D"); - return O; - } - - /// - Tensor IOps.Conv3D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - LogLayerSummary(X.shape + " # " + K.shape + " + (" + B.flatWidth + ")"); - var O = m_Ops.Conv3D(X, K, B, stride, pad, fusedActivation); - LogOutputTensorSummary(O, Prefix + "Conv3D"); - return O; - } - - /// - Tensor IOps.DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) - { - LogLayerSummary(X.shape + " ∆ " + K.shape + " + (" + B.flatWidth + ")"); - var O = m_Ops.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); - LogOutputTensorSummary(O, Prefix + "DepthwiseConv2D"); - return O; - } - - /// - Tensor IOps.Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) - { - LogLayerSummary(X.shape + " @ " + K.shape + " + (" + B.flatWidth + ")"); - var O = m_Ops.Conv2DTrans(X, K, B, stride, pad, outputAdjustment, fusedActivation); - LogOutputTensorSummary(O, Prefix + "Conv2DTrans"); - return O; - } - - /// - Tensor IOps.Upsample2D(Tensor X, int[] scale, bool bilinear) - { - var O = m_Ops.Upsample2D(X, scale, bilinear); - LogLayerSummary(X.shape + " ^ " + (bilinear ? "bilinear" : "") + O.shape); - LogOutputTensorSummary(O, Prefix + "Upsample2D"); - return O; - } - - /// - Tensor IOps.Upsample3D(Tensor X, int[] scale, bool trilinear) - { - var O = m_Ops.Upsample3D(X, scale, trilinear); - LogLayerSummary(X.shape + " ^ " + (trilinear ? "trilinear" : "") + O.shape); - LogOutputTensorSummary(O, Prefix + "Upsample3D"); - return O; - } - - /// - Tensor IOps.Resample2D(Tensor X, int[] size, bool bilinear) - { - var O = m_Ops.Resample2D(X, size, bilinear); - LogLayerSummary(X.shape + " ^ " + (bilinear ? "bilinear" : "") + O.shape); - LogOutputTensorSummary(O, Prefix + "Resample2D"); - return O; - } - - /// - Tensor IOps.DepthToSpace(Tensor X, int[] scale, Layer.DepthToSpaceMode mode) - { - var O = m_Ops.DepthToSpace(X, scale, mode); - LogLayerSummary(X.shape + " ^ " + mode + O.shape); - LogOutputTensorSummary(O, Prefix + "DepthToSpace"); - return O; - } - - /// - Tensor IOps.SpaceToDepth(Tensor X, int[] scale) - { - var O = m_Ops.SpaceToDepth(X, scale); - LogLayerSummary(X.shape + " ^ " + O.shape); - LogOutputTensorSummary(O, Prefix + "SpaceToDepth"); - return O; - } - - /// - Tensor IOps.MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - var O = m_Ops.MaxPool2D(X, pool, stride, pad); - LogLayerSummary(X.shape + " > " + O.shape); - LogOutputTensorSummary(O, Prefix + "MaxPool2D"); - return O; - } - - /// - Tensor IOps.AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) - { - var O = m_Ops.AvgPool2D(X, pool, stride, pad); - LogLayerSummary(X.shape + " ≥ " + O.shape); - LogOutputTensorSummary(O, Prefix + "AvgPool2D"); - return O; - } - - /// - Tensor IOps.GlobalMaxPool2D(Tensor X) - { - var O = m_Ops.GlobalMaxPool2D(X); - LogLayerSummary(X.shape + " >> " + O.shape); - LogOutputTensorSummary(O, Prefix + "GlobalMaxPool2D"); - return O; - } - - /// - Tensor IOps.GlobalAvgPool2D(Tensor X) - { - var O = m_Ops.GlobalAvgPool2D(X); - LogLayerSummary(X.shape + " ≥≥ " + O.shape); - LogOutputTensorSummary(O, Prefix + "GlobalAvgPool2D"); - return O; - } - - /// - Tensor IOps.GlobalAvgVariancePool2D(Tensor X) - { - var O = m_Ops.GlobalAvgVariancePool2D(X); - LogLayerSummary(X.shape + " ≥≥ " + O.shape); - LogOutputTensorSummary(O, Prefix + "GlobalAvgVariancePool2D"); - return O; - } - - /// - Tensor IOps.Border2D(Tensor X, int[] pad, float value) - { - LogLayerSummary($"{X.shape} ¶(border) value={value} pad=[{pad[0]},{pad[1]},{pad[2]},{pad[3]})"); - var O = m_Ops.Border2D(X, pad, value); - LogOutputTensorSummary(O, Prefix + "Border2D"); - return O; - } - - /// - Tensor IOps.Border3D(Tensor X, int[] pad, float value) - { - LogLayerSummary($"{X.shape} ¶(border3d) value={value} pad=[{pad[0]},{pad[1]},{pad[2]},{pad[3]},{pad[4]},{pad[5]})"); - var O = m_Ops.Border3D(X, pad, value); - LogOutputTensorSummary(O, Prefix + "Border3D"); - return O; - } - - /// - Tensor IOps.Pad2DReflect(Tensor X, int[] pad) - { - LogLayerSummary($"{X.shape} ¶(reflect) pad=[{pad[0]},{pad[1]},{pad[2]},{pad[3]})"); - var O = m_Ops.Pad2DReflect(X, pad); - LogOutputTensorSummary(O, Prefix + "Pad2DReflect"); - return O; - } - - /// - Tensor IOps.Pad2DSymmetric(Tensor X, int[] pad) - { - LogLayerSummary($"{X.shape} ¶(symmetric) pad=[{pad[0]},{pad[1]},{pad[2]},{pad[3]})"); - var O = m_Ops.Pad2DSymmetric(X, pad); - LogOutputTensorSummary(O, Prefix + "Pad2DSymmetric"); - return O; - } - - /// - Tensor IOps.Pad2DEdge(Tensor X, int[] pad) - { - LogLayerSummary($"{X.shape} ¶(edge) pad=[{pad[0]},{pad[1]},{pad[2]},{pad[3]})"); - var O = m_Ops.Pad2DEdge(X, pad); - LogOutputTensorSummary(O, Prefix + "Pad2DEdge"); - return O; - } - - /// - Tensor IOps.ScaleBias(Tensor X, Tensor S, Tensor B) - { - LogLayerSummary(X.shape + " * (" + S.channels + ") + (" + B.channels + ")"); - var O = m_Ops.ScaleBias(X, S, B); - LogOutputTensorSummary(O, Prefix + "ScaleBias"); - return O; - } - - /// - Tensor IOps.Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) - { - LogLayerSummary(X.shape + " ! " + (pool==1 ? "instance": "batch") + " axis=" + axis); - var O = m_Ops.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); - LogOutputTensorSummary(O, Prefix + "Normalization"); - return O; - } - - /// - Tensor IOps.LRN(Tensor X, float alpha, float beta, float bias, int size) - { - LogLayerSummary(X.shape + " LRN n=" + size + " a=" + alpha + " b=" + beta + " bias=" + bias); - var O = m_Ops.LRN(X, alpha, beta, bias, size); - LogOutputTensorSummary(O, Prefix + "LRN"); - return O; - } - - /// - Tensor IOps.Dropout(Tensor X, float alpha) - { - LogLayerSummary(X.shape + " a=" + alpha); - var O = m_Ops.Dropout(X, alpha); - LogOutputTensorSummary(O, Prefix + "Dropout"); - return O; - } - - /// - Tensor IOps.RandomNormal(TensorShape s, float mean, float scale, int seed) - { - LogLayerSummary(s + " N m=" + mean + " s=" + scale + " s=" + seed); - var O = m_Ops.RandomNormal(s, mean, scale, seed); - LogOutputTensorSummary(O, Prefix + "RandomNormal"); - return O; - } - - /// - Tensor IOps.RandomUniform(TensorShape s, float mean, float scale, int seed) - { - LogLayerSummary(s + " U m=" + mean + " s=" + scale + " s=" + seed); - var O = m_Ops.RandomUniform(s, mean, scale, seed); - LogOutputTensorSummary(O, Prefix + "RandomUniform"); - return O; - } - - /// - Tensor IOps.Multinomial(Tensor X, int count, int seed) - { - LogLayerSummary(X.shape + " M n=" + count + " s=" + seed); - var O = m_Ops.Multinomial(X, count, seed); - LogOutputTensorSummary(O, Prefix + "Multinomial"); - return O; - } - - /// - Tensor IOps.OneHot(Tensor X, int depth, float onValue, float offValue, int inputRank) - { - LogLayerSummary(X.shape + " Ω n=" + depth + " 1=" + onValue + " 0=" + offValue); - var O = m_Ops.OneHot(X, depth, onValue, offValue, inputRank); - LogOutputTensorSummary(O, Prefix + "OneHot"); - return O; - } - - /// - Tensor IOps.RoiAlign(Tensor X, Tensor rois, Tensor indices, int outputHeight, int outputWidth, int samplingRatio, float spatialScale) - { - LogLayerSummary(X.shape + " # " + rois.shape + "-> (" + outputHeight + "," + outputWidth + "," + samplingRatio + "," + spatialScale + ")"); - var O = m_Ops.RoiAlign(X, rois, indices, outputHeight, outputWidth, samplingRatio, spatialScale); - LogOutputTensorSummary(O, Prefix + "RoiAlign"); - return O; - } - - /// - Tensor IOps.TopKIndices(Tensor X, int k, int axis, bool largest, bool sorted) - { - LogLayerSummary($"{X.shape} Ω k={k} a={axis} l={largest} s={sorted}"); - var O = m_Ops.TopKIndices(X, k, axis, largest, sorted); - LogOutputTensorSummary(O, Prefix + "TopKIndices"); - return O; - } - - /// - public Tensor TopKValues(Tensor X, Tensor I, int axis) - { - LogLayerSummary($"{X.shape} {I.shape} Ω a={axis}"); - var O = m_Ops.TopKValues(X, I, axis); - LogOutputTensorSummary(O, Prefix + "TopKValues"); - return O; - } - - /// - public Tensor NonZero(Tensor X) - { - LogLayerSummary($"{X.shape} NonZero"); - var O = m_Ops.NonZero(X); - LogOutputTensorSummary(O, Prefix + "NonZero"); - return O; - } - - /// - Tensor IOps.Relu(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Relu(X); - LogOutputTensorSummary(O, Prefix + "Relu"); - return O; - } - - /// - Tensor IOps.Softmax(Tensor X, int axis) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Softmax(X, axis); - LogOutputTensorSummary(O, Prefix + "Softmax"); - return O; - } - - /// - Tensor IOps.LogSoftmax(Tensor X, int axis) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.LogSoftmax(X, axis); - LogOutputTensorSummary(O, Prefix + "LogSoftmax"); - return O; - } - - /// - Tensor IOps.Tanh(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Tanh(X); - LogOutputTensorSummary(O, Prefix + "Tanh"); - return O; - } - - /// - Tensor IOps.Softplus(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Softplus(X); - LogOutputTensorSummary(O, Prefix + "Softplus"); - return O; - } - - /// - Tensor IOps.Sigmoid(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Sigmoid(X); - LogOutputTensorSummary(O, Prefix + "Sigmoid"); - return O; - } - - /// - Tensor IOps.HardSigmoid(Tensor X, float alpha, float beta) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.HardSigmoid(X, alpha, beta); - LogOutputTensorSummary(O, Prefix + "HardSigmoid"); - return O; - } - - /// - Tensor IOps.Relu6(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Relu6(X); - LogOutputTensorSummary(O, Prefix + "Relu6"); - return O; - } - - /// - Tensor IOps.Elu(Tensor X, float alpha) - { - LogLayerSummary(X.shape + " () a=" + alpha); - var O = m_Ops.Elu(X, alpha); - LogOutputTensorSummary(O, Prefix + "Elu"); - return O; - } - - /// - Tensor IOps.LeakyRelu(Tensor X, float alpha) - { - LogLayerSummary(X.shape + " () a=" + alpha); - var O = m_Ops.LeakyRelu(X, alpha); - LogOutputTensorSummary(O, Prefix + "LeakyRelu"); - return O; - } - - /// - Tensor IOps.Selu(Tensor X, float alpha, float gamma) - { - LogLayerSummary(X.shape + " () a=" + alpha + " g=" + gamma); - var O = m_Ops.Selu(X, alpha, gamma); - LogOutputTensorSummary(O, Prefix + "Selu"); - return O; - } - - /// - Tensor IOps.PRelu(Tensor X, Tensor S) - { - LogLayerSummary(X.shape + " * (" + S.channels + ")"); - var O = m_Ops.PRelu(X, S); - LogOutputTensorSummary(O, Prefix + "PRelu"); - return O; - } - - /// - Tensor IOps.Swish(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Swish(X); - LogOutputTensorSummary(O, Prefix + "Swish"); - return O; - } - - /// - Tensor IOps.Abs(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Abs(X); - LogOutputTensorSummary(O, Prefix + "Abs"); - return O; - } - - /// - Tensor IOps.Neg(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Neg(X); - LogOutputTensorSummary(O, Prefix + "Neg"); - return O; - } - - /// - Tensor IOps.Ceil(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Ceil(X); - LogOutputTensorSummary(O, Prefix + "Ceil"); - return O; - } - - /// - Tensor IOps.Clip(Tensor X, float min, float max) - { - LogLayerSummary(X.shape + " () min=" + min + " max=" + max); - var O = m_Ops.Clip(X, min, max); - LogOutputTensorSummary(O, Prefix + "Clip"); - return O; - } - - /// - Tensor IOps.Floor(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Floor(X); - LogOutputTensorSummary(O, Prefix + "Floor"); - return O; - } - - /// - Tensor IOps.Round(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Round(X); - LogOutputTensorSummary(O, Prefix + "Round"); - return O; - } - - /// - Tensor IOps.Reciprocal(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Reciprocal(X); - LogOutputTensorSummary(O, Prefix + "Reciprocal"); - return O; - } - - /// - Tensor IOps.Pow(Tensor X, float alpha) - { - LogLayerSummary(X.shape + " () a=" + alpha); - var O = m_Ops.Pow(X, alpha); - LogOutputTensorSummary(O, Prefix + "Pow"); - return O; - } - - /// - Tensor IOps.Exp(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Exp(X); - LogOutputTensorSummary(O, Prefix + "Exp"); - return O; - } - - /// - Tensor IOps.Log(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Log(X); - LogOutputTensorSummary(O, Prefix + "Log"); - return O; - } - - /// - Tensor IOps.Sqrt(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Sqrt(X); - LogOutputTensorSummary(O, Prefix + "Sqrt"); - return O; - } - - /// - Tensor IOps.Acos(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Acos(X); - LogOutputTensorSummary(O, Prefix + "Acos"); - return O; - } - - /// - Tensor IOps.Acosh(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Acosh(X); - LogOutputTensorSummary(O, Prefix + "Acosh"); - return O; - } - - /// - Tensor IOps.Asin(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Asin(X); - LogOutputTensorSummary(O, Prefix + "Asin"); - return O; - } - - /// - Tensor IOps.Asinh(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Asinh(X); - LogOutputTensorSummary(O, Prefix + "Asinh"); - return O; - } - - /// - Tensor IOps.Atan(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Atan(X); - LogOutputTensorSummary(O, Prefix + "Atan"); - return O; - } - - /// - Tensor IOps.Atanh(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Atanh(X); - LogOutputTensorSummary(O, Prefix + "Atanh"); - return O; - } - - /// - Tensor IOps.Cos(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Cos(X); - LogOutputTensorSummary(O, Prefix + "Cos"); - return O; - } - - /// - Tensor IOps.Cosh(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Cosh(X); - LogOutputTensorSummary(O, Prefix + "Cosh"); - return O; - } - - /// - Tensor IOps.Sin(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Sin(X); - LogOutputTensorSummary(O, Prefix + "Sin"); - return O; - } - - /// - Tensor IOps.Sinh(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Sinh(X); - LogOutputTensorSummary(O, Prefix + "Sinh"); - return O; - } - - /// - Tensor IOps.Tan(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Tan(X); - LogOutputTensorSummary(O, Prefix + "Tan"); - return O; - } - - /// - Tensor IOps.Erf(Tensor X) - { - LogLayerSummary(X.shape + " ()"); - var O = m_Ops.Erf(X); - LogOutputTensorSummary(O, Prefix + "Erf"); - return O; - } - - /// - Tensor IOps.Add(Tensor[] tensors) - { - var O = m_Ops.Add(tensors); - LogLayerSummary("{" + tensors.Length + "} + " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Add"); - return O; - } - - /// - Tensor IOps.Sub(Tensor[] tensors) - { - var O = m_Ops.Sub(tensors); - LogLayerSummary("{" + tensors.Length + "} - " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Sub"); - return O; - } - - /// - Tensor IOps.Mul(Tensor[] tensors) - { - var O = m_Ops.Mul(tensors); - LogLayerSummary("{" + tensors.Length + "} * " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Mul"); - return O; - } - - /// - Tensor IOps.Div(Tensor[] tensors) - { - var O = m_Ops.Div(tensors); - LogLayerSummary("{" + tensors.Length + "} / " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Div"); - return O; - } - - /// - Tensor IOps.Pow(Tensor[] tensors) - { - var O = m_Ops.Pow(tensors); - LogLayerSummary("{" + tensors.Length + "} ^ " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Pow"); - return O; - } - - /// - Tensor IOps.Min(Tensor[] tensors) - { - var O = m_Ops.Min(tensors); - LogLayerSummary("{" + tensors.Length + "} < " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Min"); - return O; - } - - /// - Tensor IOps.Max(Tensor[] tensors) - { - var O = m_Ops.Max(tensors); - LogLayerSummary("{" + tensors.Length + "} > " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Max"); - return O; - } - - /// - Tensor IOps.Mean(Tensor[] tensors) - { - var O = m_Ops.Mean(tensors); - LogLayerSummary("{" + tensors.Length + "} ∑ " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Mean"); - return O; - } - - /// - Tensor IOps.ReduceMax(Tensor X, int axis) - { - var O = m_Ops.ReduceMax(X, axis); - LogLayerSummary(X.shape + " .> " + O.shape); - LogOutputTensorSummary(O, Prefix + "ReduceMax"); - return O; - } - - /// - Tensor IOps.ReduceMean(Tensor X, int axis) - { - var O = m_Ops.ReduceMean(X, axis); - LogLayerSummary(X.shape + " .∑ " + O.shape); - LogOutputTensorSummary(O, Prefix + "ReduceMean"); - return O; - } - - /// - Tensor IOps.ReduceMin(Tensor X, int axis) - { - var O = m_Ops.ReduceMin(X, axis); - LogLayerSummary(X.shape + " .< " + O.shape); - LogOutputTensorSummary(O, Prefix + "ReduceMin"); - return O; - } - - /// - Tensor IOps.ReduceProd(Tensor X, int axis) - { - var O = m_Ops.ReduceProd(X, axis); - LogLayerSummary(X.shape + " .* " + O.shape); - LogOutputTensorSummary(O, Prefix + "ReduceProd"); - return O; - } - - /// - Tensor IOps.ReduceSum(Tensor X, int axis) - { - var O = m_Ops.ReduceSum(X, axis); - LogLayerSummary(X.shape + " .+ " + O.shape); - LogOutputTensorSummary(O, Prefix + "ReduceSum"); - return O; - } - - /// - Tensor IOps.ArgMax(Tensor X, int axis) - { - var O = m_Ops.ArgMax(X, axis); - LogLayerSummary(X.shape + " .+ " + O.shape); - LogOutputTensorSummary(O, Prefix + "ArgMax"); - return O; - } - - /// - Tensor IOps.ArgMin(Tensor X, int axis) - { - var O = m_Ops.ArgMin(X, axis); - LogLayerSummary(X.shape + " .+ " + O.shape); - LogOutputTensorSummary(O, Prefix + "ArgMin"); - return O; - } - - /// - Tensor IOps.Greater(Tensor a, Tensor b) - { - var O = m_Ops.Greater(a, b); - LogLayerSummary(a.shape + " > " + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "Greater"); - return O; - } - - /// - Tensor IOps.GreaterEqual(Tensor a, Tensor b) - { - var O = m_Ops.GreaterEqual(a, b); - LogLayerSummary(a.shape + " >= " + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "GreaterEqual"); - return O; - } - - /// - Tensor IOps.Less(Tensor a, Tensor b) - { - var O = m_Ops.Less(a, b); - LogLayerSummary(a.shape + " < " + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "Less"); - return O; - } - - /// - Tensor IOps.LessEqual(Tensor a, Tensor b) - { - var O = m_Ops.LessEqual(a, b); - LogLayerSummary(a.shape + " <= " + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "LessEqual"); - return O; - } - - /// - Tensor IOps.Equal(Tensor a, Tensor b) - { - var O = m_Ops.Equal(a, b); - LogLayerSummary(a.shape + " == " + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "Equal"); - return O; - } - - /// - Tensor IOps.LogicalOr(Tensor a, Tensor b) - { - var O = m_Ops.LogicalOr(a, b); - LogLayerSummary(a.shape + " || " + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "LogicalOr"); - return O; - } - - /// - Tensor IOps.LogicalAnd(Tensor a, Tensor b) - { - var O = m_Ops.LogicalAnd(a, b); - LogLayerSummary(a.shape + " && " + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "LogicalAnd"); - return O; - } - - /// - Tensor IOps.LogicalXor(Tensor a, Tensor b) - { - var O = m_Ops.LogicalXor(a, b); - LogLayerSummary(a.shape + " ^ " + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "LogicalXor"); - return O; - } - - /// - Tensor IOps.LogicalNot(Tensor x) - { - var O = m_Ops.LogicalNot(x); - LogLayerSummary("!(" + x.shape +" )"); - LogOutputTensorSummary(O, Prefix + "LogicalNot"); - return O; - } - - /// - Tensor IOps.Sign(Tensor x) - { - var O = m_Ops.Sign(x); - LogLayerSummary("!(" + x.shape +" )"); - LogOutputTensorSummary(O, Prefix + "Sign"); - return O; - } - - /// - Tensor IOps.Where(Tensor c, Tensor a, Tensor b) - { - var O = m_Ops.Where(c, a, b); - LogLayerSummary(c.shape + " ? " + a.shape + ":" + b.shape + " = " + O.shape); - LogOutputTensorSummary(O, Prefix + "Where"); - return O; - } - - /// - Tensor IOps.Flatten(Tensor X) - { - var O = m_Ops.Flatten(X); - LogLayerSummary(X.shape + " = " + O.shape); - return O; - } - - /// - Tensor IOps.Reshape(Tensor X, TensorShape shape) - { - var O = m_Ops.Reshape(X, shape); - LogLayerSummary(X.shape + " $ " + O.shape); - return O; - } - - /// - Tensor IOps.Expand(Tensor X, TensorShape shape) - { - var O = m_Ops.Expand(X, shape); - LogLayerSummary(X.shape + " $ " + O.shape); - return O; - } - - /// - Tensor IOps.Transpose(Tensor X) - { - var O = m_Ops.Transpose(X); - LogLayerSummary(X.shape + " T " + O.shape); - return O; - } - - /// - Tensor IOps.Transpose(Tensor X, int[] permutations) - { - var O = m_Ops.Transpose(X, permutations); - LogLayerSummary(X.shape + " T " + O.shape); - return O; - } - - /// - Tensor IOps.Gather(Tensor[] tensors, int axis) - { - var O = m_Ops.Gather(tensors,axis); - LogLayerSummary("{" + tensors[0].shape + "," + tensors[1].shape + "," + axis + "} # " + O.shape); - LogOutputTensorSummary(O, Prefix + "Gather"); - return O; - } - - /// - Tensor IOps.ScatterND(Tensor X, Tensor indices, Tensor updates, Layer.ScatterNDReductionMode reduction) - { - var O = m_Ops.ScatterND(X, indices, updates, reduction); - LogLayerSummary("{" + X.shape + "," + indices.shape + "," + updates.shape + "," + reduction + "} # " + O.shape); - LogOutputTensorSummary(O, Prefix + "Gather"); - return O; - } - - /// - Tensor IOps.NonMaxSuppression(Tensor[] tensors, int maxOutputBoxesPerClass, float iouThreshold, float scoreThreshold, int centerPointBox) - { - var O = m_Ops.NonMaxSuppression(tensors, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, centerPointBox); - LogLayerSummary($"{string.Join(",", Enumerable.Select(tensors, t => t.shape.ToString()))} centerPointBox: {centerPointBox} # {O.shape}"); - LogOutputTensorSummary(O, Prefix + nameof(IOps.NonMaxSuppression)); - return O; - } - - /// - public Tensor[] LSTM(Tensor X, Tensor[] W, Tensor[] R, Tensor[] Wb, Tensor[] Rb, Tensor hidden, Tensor cell) - { - var O = m_Ops.LSTM(X, W, R, Wb, Rb, hidden, cell); - LogLayerSummary($"X: {X.shape} hidden: {hidden.shape} cell: {cell.shape}"); - LogOutputTensorSummary(O[0], Prefix + nameof(IOps.LSTM)); - return O; - } - - /// - Tensor IOps.Concat(Tensor[] tensors, int axis) - { - var O = m_Ops.Concat(tensors, axis); - LogLayerSummary("{" + tensors.Length + "} # " + O.shape); // @TODO: print input dimensions - LogOutputTensorSummary(O, Prefix + "Concat"); - return O; - } - - /// - Tensor IOps.StridedSlice(Tensor X, int[] starts, int[] ends, int[] strides) - { - var O = m_Ops.StridedSlice(X, starts, ends, strides); - LogLayerSummary(X.shape + " | " + O.shape); - LogOutputTensorSummary(O, Prefix + "StridedSlice"); - return O; - } - - /// - Tensor IOps.Tile(Tensor X, int[] repeats) - { - var O = m_Ops.Tile(X, repeats); - LogLayerSummary(X.shape + " % " + O.shape); - LogOutputTensorSummary(O, Prefix + "Tile"); - return O; - } - - /// - Tensor IOps.Shape(Tensor X, int axis) - { - LogLayerSummary($"{X.shape}"); - var O = m_Ops.Shape(X, axis); - LogOutputTensorSummary(O, Prefix + nameof(IOps.Shape)); - return O; - } - - - /// - Tensor IOps.ConstantOfShape(TensorShape X, DataType type, float value) - { - LogLayerSummary($"ConstantOfShape {value}"); - var O = m_Ops.ConstantOfShape(X, type, value); - LogOutputTensorSummary(O, Prefix + nameof(IOps.ConstantOfShape)); - return O; - } - - /// - Tensor IOps.Copy(Tensor x) - { - var O = m_Ops.Copy(x); - LogLayerSummary("!(" + x.shape +" )"); - LogOutputTensorSummary(O, "Copy"); - return O; - } - - /// - Tensor IOps.Prepare(Tensor X) - { - if (m_UseUnityLogFile) - D.Log("!" + X.shape); - return m_Ops.Prepare(X); - } - - /// - Tensor IOps.PrepareNoAlloc(Tensor X) - { - D.Log("!" + X.shape); - return m_Ops.PrepareNoAlloc(X); - } - - /// - void IOps.ResetAllocator(bool keepCachedMemory) - { - m_Ops.ResetAllocator(keepCachedMemory); - } - - /// - void IOps.SetModelExecutionsReporter(IModelExecutionsReporter executionsReporter) - { - m_Ops.SetModelExecutionsReporter(executionsReporter); - } - - /// - IModelExecutionsReporter IOps.GetModelExecutionsReporter() - { - return m_Ops.GetModelExecutionsReporter(); - } - - private void LogLayerSummary(string summary) - { - if (m_UseUnityLogFile) - D.Log(summary); -#if ENABLE_BARRACUDA_STATS - m_Ops.GetModelExecutionsReporter()?.SetLayerSummary(summary); -#endif //ENABLE_BARRACUDA_STATS - } - - private void LogOutputTensorSummary(Tensor O, string messagePrefix, int size = 32) - { - if (m_UseUnityLogFile) - O.PrintDataPart(size, messagePrefix); - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Backends/VerboseOps.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Backends/VerboseOps.cs.meta deleted file mode 100644 index ac1bd3a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Backends/VerboseOps.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 652e588fca30240cf89d82db18ad71a8 -timeCreated: 1506427659 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/BackwardsCompatibility.cs b/Packages/com.unity.barracuda/Runtime/Core/BackwardsCompatibility.cs deleted file mode 100644 index b2de962..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/BackwardsCompatibility.cs +++ /dev/null @@ -1,428 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda { - -/// -/// Deprecated APIs, left here only for backwards compatibility -/// -public static class DeprecatedTensorExtensions -{ - /// - /// Deprecated, use `AdjustPadToPool` version with pool as an array instead - /// - /// `Tensor` - /// pool tuple - /// stride - /// padding - /// shape as int array - [ObsoleteAttribute("Use AdjustPadToPool version with pool as an array instead.", false)] - public static int[] AdjustPadToPool(this Tensor tensor, ValueTuple pool, int[] stride, int[] pad) - { - unsafe - { - int* pPool = stackalloc int[2]; - pPool[0] = pool.Item1; - pPool[1] = pool.Item2; - return tensor.shape.AdjustPadToPool(pPool, stride, pad); - } - } - - /// - /// Deprecated, use `AdjustPadToPool` version with pool as an array instead - /// - /// `TensorShape` - /// pool tuple - /// stride - /// padding - /// shape as int array - [ObsoleteAttribute("Use AdjustPadToPool version with pool as an array instead.", false)] - public static int[] AdjustPadToPool(this TensorShape shape, ValueTuple pool, int[] stride, int[] pad) - { - unsafe - { - int* pPool = stackalloc int[2]; - pPool[0] = pool.Item1; - pPool[1] = pool.Item2; - - return shape.AdjustPadToPool(pPool, stride, pad); - } - } - - /// - /// Deprecated. Use UploadToDevice instead - /// - /// Tensor - /// ITensorData - /// Force cache invalidation - [ObsoleteAttribute("Use UploadToDevice instead.", false)] - public static void PinToDeviceAndUploadToIt(this Tensor self, ITensorData onDevice, bool forceInvalidateCache = true) - { - self.UploadToDevice(onDevice, forceInvalidateCache); - } - - /// - /// Deprecated. Use AttachToDevice instead - /// - /// Tensor - /// ITensorData - [ObsoleteAttribute("Use AttachToDevice instead.", false)] - public static void PinToDeviceAndDownloadFromIt(this Tensor self, ITensorData onDevice) - { - self.AttachToDevice(onDevice); - } - - /// - /// Deprecated. Use DetachFromDevice instead - /// - /// Tensor - /// Call dispose when unpinned - /// - [ObsoleteAttribute("Use DetachFromDevice instead.", false)] - public static ITensorData Unpin(this Tensor self, bool disposeUnpinned = true) - { - return self.DetachFromDevice(disposeUnpinned); - } - - /// - /// Deprecated. Use AttachToDevice instead - /// - /// Tensor - /// ITensorData - [ObsoleteAttribute("Use AttachToDevice instead.", false)] - public static void CastOnDevice(this Tensor self, ITensorData onDevice) - { - self.AttachToDevice(onDevice); - } - - #region Tensor - // @SEE: Tensor.cs - // public ITensorData UnpinAndDisposeTensor() - // public float[] readonlyArray { get { PrepareCacheForAccess(); return m_Cache; } } - // public int readonlyArrayOffset { get { return 0; } } - #endregion -} - -/// -/// Deprecated `TestSet` extensions -/// -public static class DeprecatedTestSetExtensions -{ - /// - /// Deprecated. Use `GetInputShape` version returning a TensorShape instead - /// - /// `TestSet` - /// input index - /// input shape as array - [ObsoleteAttribute("Use GetInputShape version returning a TensorShape instead.", false)] - public static int[] GetInputShape(this TestSet self, int idx = 0) - { - var shape = self.GetInputShape(idx); - Assert.IsTrue(shape.Is4D()); - return shape.ToArray(); - } - - /// - /// Deprecated. Use `GetOutputShape` version returning a TensorShape instead - /// - /// `TestSet` - /// output index - /// shape as int array - [ObsoleteAttribute("Use GetOutputShape version returning a TensorShape instead.", false)] - public static int[] GetOutputShape(this TestSet self, int idx = 0) - { - var shape = self.GetOutputShape(idx); - Assert.IsTrue(shape.Is4D()); - return shape.ToArray(); - } -} - -/// -/// Deprecated ITensorData extensions -/// -public static class DeprecatedTensorDataExtensions -{ - /// - /// Deprecated. Use maxCapacity extensions - /// - /// Tensor - /// max Tensor capacity - [ObsoleteAttribute("Use maxCapacity instead.", false)] - public static int GetMaxCount(this ITensorData self) - { - return self.maxCapacity; - } -} - -/// -/// Deprecated IWorker extensions -/// -public static class DeprecatedWorkerExtensions -{ - #region Inputs - /// - /// Deprecated. Use SetInput instead - /// - /// IWorker - /// input Tensor - [ObsoleteAttribute("Use SetInput instead.", false)] - public static void AddInput(this IWorker worker, Tensor x) - { - worker.SetInput(x); - } - - /// - /// Deprecated. Use SetInput instead - /// - /// IWorker - /// input Tensor name - /// input Tensor - [ObsoleteAttribute("Use SetInput instead.", false)] - public static void AddInput(this IWorker worker, string name, Tensor x) - { - worker.SetInput(name, x); - } - #endregion - - #region Outputs - /// - /// Deprecated. Use PeekOutput instead - /// - /// IWorker - /// output Tensor - [ObsoleteAttribute("Use PeekOutput instead.", false)] - public static Tensor Peek(this IWorker worker) - { - return worker.PeekOutput(); - } - - /// - /// Deprecated. Use PeekOutput instead - /// - /// IWorker - /// output Tensor name - /// output Tensor - [ObsoleteAttribute("Use PeekOutput instead.", false)] - public static Tensor Peek(this IWorker worker, string name) - { - return worker.PeekOutput(name); - } - #endregion - - #region Schedule one layer at a time - /// - /// Deprecated. Use StartManualSchedule instead - /// - /// IWorker - /// Manual schedule iterator - [ObsoleteAttribute("Use StartManualSchedule instead.", false)] - public static IEnumerator ExecuteAsync(this IWorker worker) - { - return worker.StartManualSchedule(); - } - - /// - /// Deprecated. Use StartManualSchedule instead - /// - /// IWorker - /// input Tensor - /// Manual schedule iterator - [ObsoleteAttribute("Use StartManualSchedule instead.", false)] - public static IEnumerator ExecuteAsync(this IWorker worker, Tensor input) - { - return worker.StartManualSchedule(input); - } - - /// - /// Deprecated. Use StartManualSchedule instead - /// - /// IWorker - /// input Tensor Dictionary - /// Manual schedule iterator - [ObsoleteAttribute("Use StartManualSchedule instead.", false)] - public static IEnumerator ExecuteAsync(this IWorker worker, IDictionary inputs) - { - return worker.StartManualSchedule(inputs); - } - - /// - /// Deprecated. Use FlushSchedule instead - /// - /// IWorker - [ObsoleteAttribute("Use FlushSchedule instead.", false)] - public static void WaitForCompletion(this IWorker worker) - { - worker.FlushSchedule(blocking:true); - } - - /// - /// Deprecated. Use scheduleProgress instead - /// - /// IWorker - /// Manual schedule progress (0 = 0%, 1 = 100% complete) - [ObsoleteAttribute("Use scheduleProgress instead.", false)] - public static float GetAsyncProgress(this IWorker worker) - { - return worker.scheduleProgress; - } - #endregion - - #region Outputs - - /// - /// Deprecated. Use Execute followed by CopyOutput and PrepareCacheForAccess instead - /// - /// IWorker - /// input Tensor - /// output Tensor - [ObsoleteAttribute("Use Execute followed by CopyOutput and PrepareCacheForAccess instead.", false)] - public static Tensor ExecuteAndWaitForCompletion(this IWorker worker, Tensor input) - { - worker.Execute(input); - return worker.CopyOutput(); - } - - /// - /// Deprecated. Use Execute followed by CopyOutput and PrepareCacheForAccess instead - /// - /// IWorker - /// input Tensor Dictionary - /// output Tensor - [ObsoleteAttribute("Use Execute followed by CopyOutput and PrepareCacheForAccess instead.", false)] - public static Tensor ExecuteAndWaitForCompletion(this IWorker worker, IDictionary inputs) - { - worker.Execute(inputs); - return worker.CopyOutput(); - } - - /// - /// Deprecated. Use PeekOutput followed by TakeOwnership or DeepCopy instead - /// - /// IWorker - /// output Tensor - [ObsoleteAttribute("Use PeekOutput followed by TakeOwnership or DeepCopy instead.", false)] - public static Tensor FetchAndTakeOwnership(this IWorker worker) - { - var output = worker.PeekOutput(); - output.TakeOwnership(); - return output; - - } - - /// - /// Deprecated. Use PeekOutput followed by TakeOwnership or DeepCopy instead - /// - /// IWorker - /// output Tensor name - /// output Tensor - [ObsoleteAttribute("Use PeekOutput followed by TakeOwnership or DeepCopy instead.", false)] - public static Tensor FetchAndTakeOwnership(this IWorker worker, string name) - { - var output = worker.PeekOutput(name); - output.TakeOwnership(); - return output; - } - - /// - /// Deprecated. Use CopyOutput instead - /// - /// IWorker - /// copy of the output Tensor - [ObsoleteAttribute("Use CopyOutput instead.", false)] - public static Tensor Fetch(this IWorker worker) - { - return worker.CopyOutput(); - } - - /// - /// Deprecated. Use CopyOutput instead - /// - /// IWorker - /// output Tensor name - /// copy of the output Tensor - [ObsoleteAttribute("Use CopyOutput instead.", false)] - public static Tensor Fetch(this IWorker worker, string name) - { - return worker.CopyOutput(name); - } - #endregion -} - -/// -/// Deprecated. Use WorkerFactory class instead -/// -[ObsoleteAttribute("Use WorkerFactory class instead.", false)] -public class BarracudaWorkerFactory : WorkerFactory -{ - /// - /// Device type enum - /// - public enum Flags - { - /// - /// GPU - /// - Compute = Device.GPU, - - /// - /// CPU - /// - CSharp = Device.CPU - } - - /// - /// Compare against Flags enum - /// - /// type - /// flags - /// True if matches - public static bool IsType(Type type, Flags flags) - { - return IsType(type, (Device)flags); - } -} - -/// -/// Deprecated. Use Tensor.ToRenderTexture method instead -/// -[ObsoleteAttribute("Use Tensor.ToRenderTexture method instead.", false)] -public class BarracudaTextureUtils -{ - /// - /// Copy Tensor data to RenderTexture - /// - /// Tensor - /// target RenderTexture - /// batch - /// from channel - /// scale - /// bias - public static void TensorToRenderTexture(Tensor x, RenderTexture target, - int batch = 0, int fromChannel = 0, float scale = 1.0f, float bias = 0f) - { - x.ToRenderTexture(target, batch, fromChannel, scale, bias); - } - - /// - /// Copy Tensor data to RenderTexture - /// - /// Tensor - /// batch - /// from channel - /// scale - /// bias - /// RenderTexture created from Tensor data - public static RenderTexture TensorToRenderTexture(Tensor x, - int batch = 0, int fromChannel = 0, float scale = 1.0f, float bias = 0f) - { - return x.ToRenderTexture(batch, fromChannel, scale, bias); - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/BackwardsCompatibility.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/BackwardsCompatibility.cs.meta deleted file mode 100644 index 8b20162..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/BackwardsCompatibility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d8be23f67617e4158b42ccaa1fc437ea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Barracuda.cs b/Packages/com.unity.barracuda/Runtime/Core/Barracuda.cs deleted file mode 100644 index 6f3414c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Barracuda.cs +++ /dev/null @@ -1,965 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; // CustomYieldInstruction -using UnityEngine.Assertions; - -namespace Unity.Barracuda { - -/// -/// The main interface to execute neural networks (a.k.a models). -/// `IWorker` abstracts implementation details associated with various hardware devices (CPU, GPU and NPU in the future) -/// that can execute neural networks and provides clean and simple interface to: -/// 1) specify inputs, 2) schedule the work and 3) retrieve outputs. -/// Internally `IWorker` translates description of the neural network provided by `Model` instance -/// into the set of operations that are sent to hardware device for execution in a non-blocking (asynchronous) manner. -/// -/// The following is a simple example of image classification using pretrained neural network: -/// -/// using UnityEngine; -/// using Unity.Barracuda; -/// -/// public class ImageRecognitionSample : MonoBehaviour -/// { -/// // small ready to use image classification neural network in ONNX format can be obtained from https://github.com/onnx/models/tree/master/vision/classification/mobilenet -/// public NNModel onnxAsset; -/// public Texture2D imageToRecognise; -/// -/// private IWorker worker; -/// void Start() -/// { -/// worker = onnxAsset.CreateWorker(); -/// } -/// -/// void Update() -/// { -/// // convert texture into Tensor of shape [1, imageToRecognise.height, imageToRecognise.width, 3] -/// using (var input = new Tensor(imageToRecognise, channels:3)) -/// { -/// // execute neural network with specific input and get results back -/// var output = worker.Execute(input).PeekOutput(); -/// -/// // the following line will access values of the output tensor causing the main thread to block until neural network execution is done -/// var indexWithHighestProbability = output.ArgMax()[0]; -/// -/// UnityEngine.Debug.Log($"Image was recognised as class number: {indexWithHighestProbability}"); -/// } -/// } -/// -/// void OnDisable() -/// { -/// worker.Dispose(); -/// } -/// } -/// -/// -/// The following example demonstrates the use of coroutine to continue smooth app execution while neural network executes in the background: -/// -/// using UnityEngine; -/// using Unity.Barracuda; -/// using System.Collections; -/// public class CoroutineImageRecognitionSample : MonoBehaviour -/// { -/// // small ready to use image classification neural network in ONNX format can be obtained from https://github.com/onnx/models/tree/master/vision/classification/mobilenet -/// public NNModel onnxAsset; -/// public Texture2D imageToRecognise; -/// -/// private IWorker worker; -/// void Start() -/// { -/// worker = onnxAsset.CreateWorker(); -/// StartCoroutine(ImageRecognitionCoroutine()); -/// } -/// -/// IEnumerator ImageRecognitionCoroutine() -/// { -/// while (true) -/// { -/// // convert texture into Tensor of shape [1, imageToRecognise.height, imageToRecognise.width, 3] -/// using (var input = new Tensor(imageToRecognise, channels:3)) -/// { -/// // execute neural network with specific input and get results back -/// var output = worker.Execute(input).PeekOutput(); -/// -/// // allow main thread to run until neural network execution has finished -/// yield return new WaitForCompletion(output); -/// -/// var indexWithHighestProbability = output.ArgMax()[0]; -/// UnityEngine.Debug.Log($"Image was recognised as class number: {indexWithHighestProbability}"); -/// } -/// -/// // wait until a new image is provided -/// var previousImage = imageToRecognise; -/// while (imageToRecognise == previousImage) -/// yield return null; -/// } -/// } -/// -/// void OnDisable() -/// { -/// worker.Dispose(); -/// } -/// } -/// -/// -/// Use `WorkerFactory.CreateWorker` or `Model.CreateWorker` to create new worker instance. -/// -public interface IWorker : IDisposable -{ - #region Inputs - /// - /// Optional API to prepare network execution for inputs of particular shapes. - /// Useful to initialize execution device ahead of the first call to `Execute`. - /// - /// Dictionary of tensor name -> input shapes - /// expected type of the inputs - void PrepareForInput(IDictionary inputShapes, DataType dataType = DataType.Float); - - /// - /// Specify single tensor `x` as the only input for the network. - /// Useful when network has only one input and caller does not need to specify input's name. - /// - /// input Tensor - void SetInput(Tensor x); - - /// - /// Assign tensor `x` to the named input of the network. String `name` specifies the name of the input. - /// - /// Tensor name - /// Tensor - void SetInput(string name, Tensor x); - #endregion - - #region Schedule the whole network - /// - /// Non-blocking API that schedules network execution in one go. - /// - /// IWorker instance - IWorker Execute(); - - - /// - /// Non-blocking API that takes single `input` tensor and schedules network execution in one go. - /// Useful when network have only one input as input name is not needed. - /// - /// input Tensor - /// IWorker instance - IWorker Execute(Tensor input); - - - /// - /// Non-blocking API that takes multiple input tensors and schedules network execution in one go. - /// - /// input Tensor Dictionary: name -> Tensor - /// IWorker instance - IWorker Execute(IDictionary inputs); - #endregion - - #region Schedule one layer at a time - /// - /// Non-blocking API that allows manual scheduling of the model one layer at the time. - /// Call `MoveNext` on the `IEnumerator` obtained from calling this function to schedule next layer of the model. - /// - /// Manual schedule iterator - IEnumerator StartManualSchedule(); - - /// - /// Non-blocking API that takes single `input` tensor and schedules network execution one layer at the time. - /// Call `MoveNext` on the `IEnumerator` obtained from calling this function to schedule next layer of the model. - /// - /// input Tensor - /// Manual schedule iterator - IEnumerator StartManualSchedule(Tensor input); - - /// - /// Non-blocking API that takes mutliple input tensors and schedules network execution one layer at the time. - /// Call `MoveNext` on the `IEnumerator` obtained from calling this function to schedule next layer of the model. - /// - /// input Tensor Dictionary: name -> Tensor - /// Manual schedule iterator - IEnumerator StartManualSchedule(IDictionary inputs); - - /// - /// Non-blocking API that starts immediate execution on the part of the network that was scheduled so far. - /// Optional `blocking` flag can force this function to block until execution is complete. - /// - /// if blocking True, wait for completion - void FlushSchedule(bool blocking = false); - - /// - /// Reports the fraction (from 0.0 to 1.0) of the model that was scheduled for the execution since the last call to `StartManualSchedule`. - /// This property will return 0.0 immediately after calling `StartManualSchedule` and will return 1.0 once the complete model was scheduled. - /// This property will monotonuosly increase with the every iteration of `IEnumerator` that was obtained by calling `StartManualSchedule`. - /// - float scheduleProgress { get; } - #endregion - - #region Outputs - /// - /// Non-blocking API that returns a reference to the main output tensor. This reference will be valid only until the next `Execute()` or `Dispose()` method is called on the worker. - /// Useful when network has only one output. - /// IMPORTANT: if you want tensor to outlive the worker, use `CopyOutput()` method or follow with `TakeOwnership()` call on the tensor. - /// - /// output Tensor - Tensor PeekOutput(); - - /// - /// Non-blocking API that returns a reference to output tensor by specified `name`. This reference will be valid only until the next `Execute()` or `Dispose()` method is called on the worker. - /// IMPORTANT: if you want tensor to outlive the worker, use `CopyOutput()` method or follow with `TakeOwnership()` call on the tensor. - /// - /// output name - /// output Tensor - Tensor PeekOutput(string name); - #endregion - - /// - /// Returns references to constants tensors for a layer. This reference might be valid only until the next `Execute()` or `Dispose()` method is called on the worker. - /// IMPORTANT: if you want tensor to outlive the worker, use `CopyOutput()` method or follow with `TakeOwnership()` call on the tensor, also worker Execute() - /// or PrepareForInput() should have been called at least once for the tensors to exist. - /// - /// Layer name - /// array of constant Tensors - Tensor[] PeekConstants(string layerName); - - /// - /// Returns a string summary after execution. - /// - /// string summary after execution - string Summary(); -} - -/// -/// IWorker interface extensions -/// -public static class WorkerExtensions -{ - // @TODO: add optional targetDevice argument of type WorkerFactory.Device - /// - /// Returns CPU copy of the first output tensor. - /// This method is a blocking call and will wait until network execution is completed. - /// Useful when network has only one output. - /// - /// IWorker - /// output Tensor - public static Tensor CopyOutput(this IWorker worker) - { - // @TODO: implement as PeekOutput()+DeepCopy() instead of Unpin()+TakeOwnership() - var output = worker.PeekOutput(); - output.DetachFromDevice(); // detach will readback to CPU and - // give allocator a chance to reuse allocated buffer - output.TakeOwnership(); - return output; - } - - // @TODO: add optional targetDevice argument of type WorkerFactory.Device - /// - /// Returns CPU copy of output tensor by name. - /// This method is a blocking call and will wait until network execution is completed. - /// - /// IWorker - /// output Tensor name - /// output Tensor - public static Tensor CopyOutput(this IWorker worker, string name) - { - // @TODO: implement as PeekOutput()+DeepCopy() instead of Unpin()+TakeOwnership() - var output = worker.PeekOutput(name); - output.DetachFromDevice(); // detach will readback to CPU and - // give allocator a chance to reuse allocated buffer - output.TakeOwnership(); - return output; - } -} - -/// -/// Interface for device dependent representation of Tensor data. -/// -public interface ITensorData : IDisposable, ITensorDataStatistics -{ - /// - /// Reserve uninitialized memory. - /// - /// element count to reserve - void Reserve(int count); - - /// - /// Initialize with `data`. - /// `shape` is the TensorShape (and thus length) of the data to copy. - /// `managedBufferStartIndex` is the offset where to start the copy in the `data` - /// - /// data as `float` array - /// Tensor shape - /// managed buffer start index - void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0); - - /// - /// Schedule an asynchronous download from device memory. - /// `count` is the number of element to readback. - /// - /// count of elements to download - /// `false` until data from device arrives to CPU and is ready for access - bool ScheduleAsyncDownload(int count); - - /// - /// Returns an array filled with the values of a tensor. - /// Depending on the implementation and underlying device this array might be a copy or direct reference to the tensor values. - /// This is a blocking call, unless data from device was requested via `ScheduleAsyncDownload` beforehand and has already arrived. - /// - /// the TensorShape (and thus length) of the data to copy - /// Tensor data as `float` arrary - float[] Download(TensorShape shape); - - /// - /// Returns an array filled with the values of multiple tensors that share the same tensorData on device. - /// Depending on the implementation and underlying device this array might be a copy or direct reference to tensor values, no conversion from on device memory layout will occur. - /// This is a blocking call, unless data from device was requested via `ScheduleAsyncDownload` beforehand and has already arrived. - /// - /// This function outputs `offset` from the beginning of the array to location of values for specific tensor. `offset` parameters is specified in float elements - /// array filled with the values of multiple tensors that share the same tensorData on device - BarracudaArray SharedAccess(out int offset); -} - -/// -/// Job system dependency fences for the memory resource -/// -public interface IDependableMemoryResource -{ - /// - /// Read fence - /// Returns job handle that can be used as `dependsOn` argument when scheduling data consumer job. - /// Consumer job will start execution once Tensor data is ready for read access. - /// - Unity.Jobs.JobHandle fence { get; set; } - - /// - /// Write fence - /// Returns job handle that can be used as `dependsOn` argument when scheduling data producer job. - /// Producer job will start execution once Tensor data is ready for write access. - /// - Unity.Jobs.JobHandle reuse { get; set; } - - /// - /// Raw memory pointer for the resource - /// - unsafe void* rawPtr { get; } -} - -/// -/// Interface for device dependent representation of Tensor data that provides fences for scheduling data job. -/// -public interface IDependableTensorData : IDependableMemoryResource, ITensorData -{ -} - -/// -/// Object that represent memory (recurrent state) between the executions of a given model. -/// -public class RecurrentState : IDisposable -{ - private int m_BatchSize = 1; - private Model m_Model; - private Tensor[] m_Memories; - - int InferBatchSize(int batchSize, int newBatchSize, string memoryName) - { - if (batchSize < 0) - batchSize = newBatchSize; - else - { - Assert.IsTrue(batchSize != -1); - if (batchSize != newBatchSize) - throw new ArgumentException("Batch size for all memories of the model must be the same value. " + - $"Expected batch size of {batchSize}, but got {newBatchSize} for memory `{memoryName}`"); - } - return batchSize; - } - - /// - /// Constructs recurrent state for a specific model - /// - /// the associated model - /// has to match the batch dimension of the input tensor(s). Specifying -1 will use batch size of the memory tensors as declared in the model - /// optional dictionary of named tensors that can be used as a memory. If name of the tensor matches the memory, tensor will be removed from the dictionary and used as memory - public RecurrentState(Model model, int batchSize = -1, Dictionary grabFromInputs = null) - { - bool overrideModelBatchSize = batchSize > 0; - - m_Model = model; - m_Memories = new Tensor[m_Model.memories.Count]; - - var index = 0; - foreach (var memory in m_Model.memories) - { - var memoryName = memory.input; - if (grabFromInputs != null && grabFromInputs.ContainsKey(memoryName)) - { - // steal input from the inputs and use it as a memory - var inputTensorToBecomeMemory = grabFromInputs[memoryName]; - m_Memories[index++] = inputTensorToBecomeMemory; - grabFromInputs.Remove(memoryName); - - batchSize = InferBatchSize(batchSize, inputTensorToBecomeMemory.batch, memoryName); - } - else - { - if (!overrideModelBatchSize) - batchSize = InferBatchSize(batchSize, memory.shape.batch, memoryName); - - // create memory tensor - var shape = new TensorShape(batchSize, memory.shape.height, memory.shape.width, memory.shape.channels); - m_Memories[index++] = new Tensor(shape); - } - } - - m_BatchSize = batchSize; - } - - /// - /// Finalize RecurrentState - /// - ~RecurrentState() - { - Dispose(); - } - - /// - /// Dispose RecurrentState - /// - public virtual void Dispose() - { - if (m_Memories == null) - return; - - foreach (var x in m_Memories) - x.Dispose(); - - m_Memories = null; - } - - /// - /// Returns batch dimension used for the memories. - /// - /// batch dimension used for the memories - public int GetBatchSize() - { - return m_BatchSize; - } - - /// - /// Internal callback called before the execution of the model. - /// This callback prepares model for the next iteration according to the memory. - /// - /// IWorker - public void BeforeExecution(IWorker worker) - { - Assert.AreEqual(m_Model.memories.Count, m_Memories.Length); - - var index = 0; - foreach (var memory in m_Model.memories) - worker.SetInput(memory.input, m_Memories[index++]); - } - - /// - /// Internal callback called after execution of the model finished. - /// This callback stores results of the current iteration in the memory. - /// - /// IWorker - public void AfterExecution(IWorker worker) - { - Assert.AreEqual(m_Model.memories.Count, m_Memories.Length); - - var index = 0; - foreach (var memory in m_Model.memories) - { - var newTensor = worker.CopyOutput(memory.output); - Assert.IsTrue(newTensor.tensorOnDevice != m_Memories[index]); - m_Memories[index].Dispose(); - m_Memories[index] = newTensor; - index++; - } - } -} - -/// -/// Factory to create worker that executes specified model on a particular device (GPU, CPU, etc) using particular backend. -/// See `IWorker` for usage of the worker itself. -/// -public class WorkerFactory -{ - /// - /// Supported device type - /// - public enum Device - { - /// - /// GPU - /// - GPU = 1 << 8, - - /// - /// CPU - /// - CPU = 1 << 9, - - /// - /// Auto - /// - Auto = 1 << 15, - - // aliases - /// - /// Alias for GPU - /// - Compute = GPU, - - /// - /// Alias for CPU - /// - CSharp = CPU, - } - - /// - /// Backend type - /// - public enum Type - { - /// - /// Auto - /// - Auto = 0 | Device.Auto, - - /// - /// Compute Precompiled, least CPU overhead when scheduling - /// - ComputePrecompiled = 0 | Device.GPU, - - /// - /// Fast Compute implementation - /// - Compute = 1 | Device.GPU, - - /// - /// Reference Compute implementation, very slow - /// - ComputeRef = 2 | Device.GPU, - - /// - /// Pixel Shader implementation, slower than compute - /// - PixelShader = 3 | Device.GPU, - - /// - /// Unity Burst implementation, fastest CPU option - /// - CSharpBurst = 0 | Device.CPU, - - /// - /// Fast C# implementation when Burst is not available - /// - CSharp = 1 | Device.CPU, - - /// - /// Reference C# implementation, very very slow - /// - CSharpRef = 2 | Device.CPU - } - - /// - /// Worker configuration - /// `compareAgainstType` if different than the worker `type`, the model will be run on both backend and result of every layer will be compared, checking for divergence. Great for debugging, but very slow because of the sync needed. - /// `verbose` will log scheduling of layers execution to the console (default == false). - /// `compareLogLevel` define how difference will be reported (default == Warning). - /// `compareEpsilon` the maximum tolerance before a difference is reported (default == 0.0001f). - /// - public struct WorkerConfiguration { - /// - /// Print debug information on model execution to the console - /// - public bool verbose; - - /// - /// Compare layer by layer outputs against other worker type - /// - public Type compareAgainstType; - - /// - /// Comparison log level - /// - public CompareOpsUtils.LogLevel compareLogLevel; - - /// - /// Comparison error tolerance - /// - public float compareEpsilon; - - /// - /// If true the worker is allowed to take ownership of the weights memory from the model - /// this is useful so worker to limit memory pressure when the worker need to copy those - /// weight to a different device. - /// - public bool takeoverWeights; - - /// - /// Construct worker configuration - /// - /// Compare layer by layer outputs against other worker type - /// Print debug information on model execution to the console - /// Comparison log level - /// Comparison error tolerance - /// Prefer BLAS usage over default implementation - public WorkerConfiguration(Type compareAgainstType, bool verbose=false, CompareOpsUtils.LogLevel compareLogLevel = CompareOpsUtils.LogLevel.Warning, float compareEpsilon = 0.0001f, bool takeoverWeights = false) - { - this.verbose = verbose; - this.compareAgainstType = compareAgainstType; - this.compareLogLevel = compareLogLevel; - this.compareEpsilon = compareEpsilon; - this.takeoverWeights = takeoverWeights; - } - } - - /// - /// Create a worker with explicitly specified backend `type` to execute the given `model`. - /// - /// backend type to use. For example `WorkerFactory.Type.Compute` specifies the fast GPU path - /// the associated model. See ModelLoader.cs - /// the additional outputs to track but not directly specified by the model - /// by specifying this list of outputs, all other non-specified outputs will be discarded - /// will log scheduling of layers execution to the console - /// if different than `type` model will be run on those two backend and result of every layer will be compared, checking for divergence. Great for debugging, but very slow because of the sync needed - /// if `compareAgainstType` is used difference will be reported as error is this is true or warning otherwise - /// Worker instance - public static IWorker CreateWorker(Type type, Model model, string[] additionalOutputs, string[] trimOutputs, bool verbose, Type compareAgainstType, CompareOpsUtils.LogLevel differenceLogLevel=CompareOpsUtils.LogLevel.Warning) - { - var workerConfiguration = new WorkerConfiguration(type, verbose); - workerConfiguration.compareAgainstType = compareAgainstType; - workerConfiguration.compareLogLevel = differenceLogLevel; - return BarracudaBackendsFactory.CreateWorker(type, model, additionalOutputs, trimOutputs, workerConfiguration); - } - - /// - /// Create a worker with explicitly specified backend `type` to execute the given `model`. - /// - /// backend type to use. For example `WorkerFactory.Type.Compute` specifies the fast GPU path - /// the associated model. See ModelLoader.cs - /// the additional outputs to track but not directly specified by the model - /// by specifying this list of outputs, all other non-specified outputs will be discarded - /// define configurations such as logging and comparison backend, see WorkerConfiguration API docs - /// execution reporter to use to track models executions - /// Worker instance - public static IWorker CreateWorker(Type type, Model model, string[] additionalOutputs, string[] trimOutputs, WorkerConfiguration workerConfiguration, IModelExecutionsReporter modelExecutionsReporter = null) - { - return BarracudaBackendsFactory.CreateWorker(type, model, additionalOutputs, trimOutputs, workerConfiguration, modelExecutionsReporter); - } - - /// - /// Create a worker that will execute `model` using the best backend that is available for a given `device` type. - /// - /// the associated model. See ModelLoader.cs - /// the additional outputs to track but not directly specified by the model - /// by specifying this list of outputs, all other non-specified outputs will be discarded - /// the device type to run worker on. For example `WorkerFactory.Device.GPU` specifies the fast GPU path - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreateWorker(Model model, string[] additionalOutputs, string[] trimOutputs, Device device = Device.Auto, bool verbose = false) - { - var type = GetBestTypeForDevice(device); - var workerConfiguration = new WorkerConfiguration(type, verbose); - return CreateWorker(type, model, additionalOutputs, trimOutputs, workerConfiguration); - } - - /// - /// Create a worker with explicitly specified backend `type` to execute the given `model`. - /// - /// backend type to use. For example `WorkerFactory.Type.Compute` specifies the fast GPU path - /// the associated model. See ModelLoader.cs - /// will log scheduling of layers execution to the console - /// Worker instance - public static IWorker CreateWorker(Type type, Model model, bool verbose) - { - var workerConfiguration = new WorkerConfiguration(type, verbose); - return CreateWorker(type, model, null, null, workerConfiguration); - } - - /// - /// Create a worker with explicitly specified backend `type` to execute the given `model`. - /// - /// backend type to use. For example `WorkerFactory.Type.Compute` specifies the fast GPU path - /// the associated model. See ModelLoader.cs - /// the additional outputs to track but not directly specified by the model - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreateWorker(Type type, Model model, string[] additionalOutputs, bool verbose = false) - { - var workerConfiguration = new WorkerConfiguration(type, verbose); - return CreateWorker(type, model, additionalOutputs, null, workerConfiguration); - } - - /// - /// Create a worker with explicitly specified backend `type` to execute the given `model`. - /// - /// backend type to use. For example `WorkerFactory.Type.Compute` specifies the fast GPU path - /// the associated model. See ModelLoader.cs - /// the additional outputs to track but not directly specified by the model - /// by specifying this list of outputs, all other non-specified outputs will be discarded - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreateWorker(Type type, Model model, string[] additionalOutputs = null, string[] trimOutputs = null, bool verbose = false) - { - var workerConfiguration = new WorkerConfiguration(type, verbose); - return CreateWorker(type, model, additionalOutputs, trimOutputs, workerConfiguration); - } - - /// - /// Create a worker with explicitly specified backend `type` to execute the given `model`. - /// - /// backend type to use. For example `WorkerFactory.Type.Compute` specifies the fast GPU path - /// the associated model. See ModelLoader.cs - /// will log scheduling of layers execution to the console - /// if different than `type` model will be run on those two backend and result of every layer will be compared, checking for divergence. Great for debugging, but very slow because of the sync needed - /// if `compareAgainstType` is used difference will be reported as error is this is true or warning otherwise - /// Worker instance - public static IWorker CreateWorker(Type type, Model model, bool verbose, Type compareAgainstType, CompareOpsUtils.LogLevel differenceLogLevel=CompareOpsUtils.LogLevel.Warning) - { - var workerConfiguration = new WorkerConfiguration(type, verbose); - workerConfiguration.compareAgainstType = compareAgainstType; - workerConfiguration.compareLogLevel = differenceLogLevel; - return CreateWorker(type, model, additionalOutputs:null, trimOutputs:null, workerConfiguration); - } - - /// - /// Create a worker with explicitly specified backend `type` to execute the given `model`. - /// - /// backend type to use. For example `WorkerFactory.Type.Compute` specifies the fast GPU path - /// the associated model. See ModelLoader.cs - /// define configurations such as logging and comparison backend, see WorkerConfiguration API docs - /// Worker instance - public static IWorker CreateWorker(Type type, Model model, WorkerConfiguration workerConfiguration) - { - return CreateWorker(type, model, additionalOutputs:null, trimOutputs:null, workerConfiguration); - } - - /// - /// Create a worker that will execute `model` using the best backend that is available for a given `device` type. - /// - /// the associated model. See ModelLoader.cs - /// will log scheduling of layers execution to the console - /// Worker instance - public static IWorker CreateWorker(Model model, bool verbose = false) - {; - return CreateWorker(model, Device.Auto, verbose); - } - - /// - /// Create a worker that will execute `model` using the best backend that is available for a given `device` type. - /// - /// the associated model. See ModelLoader.cs - /// the preferred device for execution. For example `WorkerFactory.Device.GPU` specifies the fast GPU path - /// will log scheduling of layers execution to the console - /// Worker instance - public static IWorker CreateWorker(Model model, Device device, bool verbose = false) - { - return CreateWorker(model, additionalOutputs:null, device, verbose); - } - - /// - /// Create a worker that will execute `model` using the best backend that is available for a given `device` type. - /// - /// the associated model. See ModelLoader.cs - /// the additional outputs to track but not directly specified by the model - /// the device type to run worker on. For example `WorkerFactory.Device.GPU` specifies the fast GPU path - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreateWorker(Model model, string[] additionalOutputs, Device device = Device.Auto, bool verbose = false) - { - return CreateWorker(model, additionalOutputs, trimOutputs:null, device, verbose); - } - - /// - /// Create a worker using the reference CPU backend for the given `model`. - /// - /// the associated model. See ModelLoader.cs - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreateReferenceCPUWorker(Model model, bool verbose = false) - { - return CreateWorker(Type.CSharpRef, model, verbose); - } - - /// - /// Create a worker using the reference GPU backend for the given `model`. - /// - /// the associated model. See ModelLoader.cs - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreateReferenceComputeWorker(Model model, bool verbose = false) - { - return CreateWorker(Type.ComputeRef, model, verbose); - } - - /// - /// Create a worker using the precompiled GPU backend for the given `model`. - /// - /// the associated model. See ModelLoader.cs - /// - /// Worker instance - public static IWorker CreateComputeWorker(Model model, bool verbose = false) - { - return CreateWorker(Type.ComputePrecompiled, model, verbose); - } - - /// - /// Create a worker using the reference GPU backend for the given `model`. - /// - /// the associated model. See ModelLoader.cs - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreatePixelShaderWorker(Model model, bool verbose = false) - { - return CreateWorker(Type.PixelShader, model, verbose); - } - - - /// - /// Check if a backend is of a given type. - /// For example: IsType(Type.CSharpRef, Device.GPU) == true - /// - /// type to check against - /// device to check against - /// `true` if backend is of specified type - /// thrown if type is `Type.Auto` - public static bool IsType(Type type, Device device) - { - type = BarracudaBackendsFactory.ResolveAutoType(type); - if (type == Type.Auto) - throw new ArgumentException($"Auto type is ambiguous in this context and not supported"); - return ((int)type & (int)device) == (int)device; - } - - /// - /// Returns the best backend type that can run on a `device` given the `model`. - /// - /// device - /// Best worker type for specified `device` - public static Type GetBestTypeForDevice(Device device) - { - return BarracudaBackendsFactory.GetBestTypeForDevice(device); - } - - /// - /// Validate if a backend of `type` is supported, otherwise return a fallback type. - /// - /// type - /// returns `type` if valid, otherwise returns fallback type - public static Type ValidateType(Type type) - { - return BarracudaBackendsFactory.ValidateType(type); - } -} - -/// -/// Suspends the coroutine execution until worker has completed execution on a device and -/// contents of the specified tensor are downloaded to the main CPU memory. -/// `WaitForCompletion` is not necessary and should NOT be used, unless tensor contents are accessed on CPU! -/// `WaitForCompletion` can only be used with a `yield` statement in coroutines. -/// -public class WaitForCompletion : CustomYieldInstruction -{ - private Tensor m_Tensor; - - /// - /// Returns `true` while results are not yet ready - /// - public override bool keepWaiting - { - get - { - bool cpuCacheIsReady = m_Tensor.PrepareCacheForAccess(blocking:false); - return !cpuCacheIsReady; - } - } - - /// - /// Suspends the coroutine execution until worker has completed execution on a device and - /// contents of the specified tensor are downloaded to the main CPU memory. - /// - /// `Tensor` that will be downloaded once worker execution is finished - public WaitForCompletion(Tensor tensor) - { - m_Tensor = tensor; - } -} - -/// -/// Extensions for `Model` class -/// -public static class ModelExtensions -{ - /// - /// Create a worker that will execute `model` using the best backend that is available for a given `device` type. - /// This is just a convenience function that internally calls `ModelLoader.Load` followed by ``WorkerFactory.CreateWorker`. - /// - /// the associated Model to execute - /// the preferred device for execution. For example `WorkerFactory.Device.GPU` specifies the fast GPU path - /// will log scheduling of layers execution to the console - /// Worker instance - public static IWorker CreateWorker(this Model model, - WorkerFactory.Device device = WorkerFactory.Device.Auto, bool verbose = false) - { - return WorkerFactory.CreateWorker(model, device, verbose); - } - - /// - /// Create a worker that will execute `model` using the best backend that is available for a given `device` type. - /// This is just a convenience function that internally calls `ModelLoader.Load` followed by ``WorkerFactory.CreateWorker`. - /// - /// the associated Model to execute - /// are the additional outputs to track but not directly specified by the model - /// by specifying this list of outputs, all other non-specified outputs will be discarded - /// the device type to run worker on. For example `WorkerFactory.Device.GPU` specifies the fast GPU path - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreateWorker(this Model model, - string[] additionalOutputs, string[] trimOutputs, WorkerFactory.Device device = WorkerFactory.Device.Auto, bool verbose = false) - { - return WorkerFactory.CreateWorker(model, additionalOutputs, trimOutputs, device, verbose); - } -} - -/// -/// Extensions for `NNModel` class -/// -public static class NNModelExtensions -{ - /// - /// Create a worker that will execute `asset` using the best backend that is available for a given `device` type. - /// This is just a convenience function that internally calls `ModelLoader.Load` followed by ``WorkerFactory.CreateWorker`. - /// - /// the associated NNModel asset - /// the preferred device for execution. For example `WorkerFactory.Device.GPU` specifies the fast GPU path - /// will log scheduling of layers execution to the console - /// Worker instance - public static IWorker CreateWorker(this NNModel asset, - WorkerFactory.Device device = WorkerFactory.Device.Auto, bool verbose = false) - { - var model = ModelLoader.Load(asset); - return model.CreateWorker(device, verbose); - } - - /// - /// Create a worker that will execute `asset` using the best backend that is available for a given `device` type. - /// This is just a convenience function that internally calls `ModelLoader.Load` followed by ``WorkerFactory.CreateWorker`. - /// - /// the associated NNModel asset - /// the additional outputs to track but not directly specified by the model - /// by specifying this list of outputs, all other non-specified outputs will be discarded - /// the device type to run worker on. For example `WorkerFactory.Device.GPU` specifies the fast GPU path - /// will log scheduling of layers execution to the console (default == false) - /// Worker instance - public static IWorker CreateWorker(this NNModel asset, - string[] additionalOutputs, string[] trimOutputs, WorkerFactory.Device device = WorkerFactory.Device.Auto, bool verbose = false) - { - var model = ModelLoader.Load(asset); - return model.CreateWorker(additionalOutputs, trimOutputs, device, verbose); - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Barracuda.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Barracuda.cs.meta deleted file mode 100644 index da15bc9..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Barracuda.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 9d9abde4165354254b69822280e8a22b -timeCreated: 1495554326 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/BarracudaArray.cs b/Packages/com.unity.barracuda/Runtime/Core/BarracudaArray.cs deleted file mode 100644 index 8d808c8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/BarracudaArray.cs +++ /dev/null @@ -1,545 +0,0 @@ -using System; -using System.Runtime.ConstrainedExecution; -using System.Runtime.InteropServices; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Mathematics; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda -{ - -///see https://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/safehandle.cs -internal class NativeMemorySafeHandle : SafeHandle -{ - public readonly Allocator m_AllocatorLabel; - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - public unsafe NativeMemorySafeHandle(long size, int alignment, Allocator allocator) : base(IntPtr.Zero, true) - { - m_AllocatorLabel = allocator; - if (size > 0) - SetHandle((IntPtr)UnsafeUtility.Malloc(size, alignment, allocator)); - } - - public override bool IsInvalid { - get { return handle == IntPtr.Zero; } - } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - protected override unsafe bool ReleaseHandle() - { - UnsafeUtility.Free((void*)handle, m_AllocatorLabel); - return true; - } -} - -internal class PinnedMemorySafeHandle : SafeHandle -{ - private readonly GCHandle m_GCHandle; - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - public PinnedMemorySafeHandle(object managedObject) : base(IntPtr.Zero, true) - { - m_GCHandle = GCHandle.Alloc(managedObject, GCHandleType.Pinned); - IntPtr pinnedPtr = m_GCHandle.AddrOfPinnedObject(); - SetHandle(pinnedPtr); - } - - public override bool IsInvalid { - get { return handle == IntPtr.Zero; } - } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - protected override bool ReleaseHandle() - { - m_GCHandle.Free(); - return true; - } -} - -/// -/// A BarracudaArrayFromManagedArray exposes a buffer of managed memory as if it was native memory (by pinning it). -/// -public class BarracudaArrayFromManagedArray : BarracudaArray -{ - private readonly int m_PinnedMemoryByteOffset; - - public BarracudaArrayFromManagedArray(float[] srcData, int srcOffset = 0) : this(srcData, srcOffset, sizeof(float), DataType.Float, srcData.Length-srcOffset) - { - } - - public BarracudaArrayFromManagedArray(byte[] srcData, int srcOffset, DataType destType, int numDestElement) : this(srcData, srcOffset, sizeof(byte), destType, numDestElement) - { - } - - private unsafe BarracudaArrayFromManagedArray(Array srcData, int srcElementOffset, int srcElementSize, DataType destElementType, int numDestElement) : base(new PinnedMemorySafeHandle(srcData), destElementType, numDestElement) - { - m_PinnedMemoryByteOffset = srcElementSize * srcElementOffset; - - //Safety checks - int requiredAlignment = DataAlignmentSize(destElementType); - int srcLenghtInByte = (srcData.Length - srcElementOffset) * srcElementSize; - int dstLenghtInByte = numDestElement * DataItemSize(destElementType); - IntPtr pinnedPtrWithOffset = (IntPtr) base.RawPtr + m_PinnedMemoryByteOffset; - if (srcElementOffset > srcData.Length) - throw new ArgumentOutOfRangeException(nameof (srcElementOffset), "SrcElementOffset must be <= srcData.Length"); - if (dstLenghtInByte > srcLenghtInByte) - throw new ArgumentOutOfRangeException(nameof (numDestElement), "NumDestElement too big for srcData and srcElementOffset"); - - if (pinnedPtrWithOffset.ToInt64() % requiredAlignment != 0) - throw new InvalidOperationException($"The BarracudaArrayFromManagedArray source ptr (including offset) need to be aligned on {requiredAlignment} bytes for the data to be express as {destElementType}."); - - var neededSrcPaddedLengthInByte = LengthWithPaddingForGPUCopy(destElementType, numDestElement) * DataItemSize(destElementType); - if (srcLenghtInByte < neededSrcPaddedLengthInByte) - throw new InvalidOperationException($"The BarracudaArrayFromManagedArray source ptr (including offset) is to small to account for extra padding needing for type {destElementType}."); - } - - public override unsafe void* RawPtr => (byte*) base.RawPtr + m_PinnedMemoryByteOffset; -} - -public enum DataType -{ - Float, - Half -} - -/// -/// A BarracudaArray exposes a buffer of native memory to managed code. -/// -public class BarracudaArray : IDisposable -{ - protected readonly SafeHandle m_SafeHandle; - private readonly Allocator m_Allocator; - private readonly int m_Length; - private readonly DataType m_DataType; - - #region helpers - public static int DataItemSize(DataType dataType) - { - if (dataType == DataType.Float) - return UnsafeUtility.SizeOf(); - if (dataType == DataType.Half) - return UnsafeUtility.SizeOf(); - - throw new NotImplementedException($"Type {dataType} not supported."); - } - - public static int DataAlignmentSize(DataType dataType) - { - if (dataType == DataType.Float) - return UnsafeUtility.AlignOf(); - if (dataType == DataType.Half) - return UnsafeUtility.AlignOf(); - - throw new NotImplementedException($"Type {dataType} not supported."); - } - - public static int LengthWithPaddingForGPUCopy(DataType dataType, int length) - { - if (dataType == DataType.Float) - return length; - if (dataType == DataType.Half) - return length + (length % 2); - - throw new NotImplementedException($"Type {dataType} not supported."); - } - - private void CheckElementAccess(DataType dataType, long index) - { - //Disabled by default for performance reasons. - #if ENABLE_BARRACUDA_DEBUG - if (Disposed) - throw new InvalidOperationException("The BarracudaArray was disposed."); - if (index <0 || index >= m_Length) - throw new IndexOutOfRangeException($"Accessing BarracudaArray of length {m_Length} at index {index}, data type is {m_DataType}."); - if (dataType != m_DataType) - throw new InvalidOperationException($"Accessing BarracudaArray of data type {m_DataType} as if it was {dataType}."); - #endif - } - #endregion - - protected BarracudaArray(SafeHandle safeHandle, DataType dataType, int dataLength) - { - m_DataType = dataType; - m_Length = dataLength; - m_SafeHandle = safeHandle; - m_Allocator = Allocator.Persistent; - } - - public BarracudaArray(int length, DataType dataType = DataType.Float, Allocator allocator = Allocator.Persistent) - { - if (!UnsafeUtility.IsValidAllocator(allocator)) - throw new InvalidOperationException("The BarracudaArray should use a valid allocator."); - if (length < 0) - throw new ArgumentOutOfRangeException(nameof (length), "Length must be >= 0"); - - m_DataType = dataType; - m_Length = length; - m_SafeHandle = new NativeMemorySafeHandle(LengthWithPaddingForGPUCopy(m_DataType, m_Length) * DataItemSize(dataType), DataAlignmentSize(dataType), allocator); - m_Allocator = allocator; - } - - public unsafe void ZeroMemory() - { - var numByteToClear = LengthWithPaddingForGPUCopy(m_DataType, m_Length) * DataItemSize(m_DataType); - UnsafeUtility.MemClear(RawPtr, numByteToClear); - } - - public virtual void Dispose() - { - m_SafeHandle.Dispose(); - } - - #region properties - public DataType Type => m_DataType; - - public int SizeOfType => DataItemSize(m_DataType); - - public int Length => m_Length; - public long LongLength => m_Length; - - public virtual unsafe void* RawPtr - { - get - { - if (Disposed) - throw new InvalidOperationException("The BarracudaArray was disposed."); - return (void*)m_SafeHandle.DangerousGetHandle(); - } - } - - public bool Disposed => m_SafeHandle.IsClosed; - - #endregion - - #region indexers and single access accessor - - public unsafe float* AddressAt(long index) - { - Assert.AreEqual(DataType.Float, m_DataType); - return (float*) RawPtr + index; - } - - public unsafe half* HalfAddressAt(long index) - { - Assert.AreEqual(DataType.Half, m_DataType); - return (half*) RawPtr + index; - } - - public unsafe void* RawAddressAt(long index) - { - if (m_DataType == DataType.Half) - return HalfAddressAt(index); - else - return AddressAt(index); - } - - public float this[long index] - { - get => this[(int)index]; - set => this[(int)index] = value; - } - public float this[int index] - { - get - { - switch (m_DataType) - { - case DataType.Float: - return GetFloat(index); - default: - return GetHalf(index); - } - } - set - { - switch (m_DataType) - { - case DataType.Float: - SetFloat(index, value); - break; - default: - SetHalf(index, (half) value); - break; - } - } - } - - public unsafe float GetFloat(int index) - { - CheckElementAccess(DataType.Float, index); - return UnsafeUtility.ReadArrayElement(RawPtr, index); - } - public unsafe half GetHalf(int index) - { - CheckElementAccess(DataType.Half, index); - return UnsafeUtility.ReadArrayElement(RawPtr, index); - } - public unsafe void SetFloat(int index, float value) - { - CheckElementAccess(DataType.Float, index); - UnsafeUtility.WriteArrayElement(RawPtr, index, value); - } - public unsafe void SetHalf(int index, half value) - { - CheckElementAccess(DataType.Half, index); - UnsafeUtility.WriteArrayElement(RawPtr, index, value); - } - #endregion - - #region copy to other memory containers - public void UploadToComputeBuffer(ComputeBuffer buffer) - { - UploadToComputeBuffer(buffer, 0, 0, m_Length); - } - - public unsafe void UploadToComputeBuffer(ComputeBuffer buffer, int elementStartIndex, int computeBufferStartIndex, int numElementToCopy) - { - if (numElementToCopy == 0) - return; - if (m_DataType == DataType.Float) - { - NativeArray nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(RawPtr, m_Length, m_Allocator); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, AtomicSafetyHandle.Create()); -#endif - buffer.SetData(nativeArray, elementStartIndex, computeBufferStartIndex, numElementToCopy); - } - else if (m_DataType == DataType.Half) - { - if (elementStartIndex % 2 == 1 || computeBufferStartIndex % 2 == 1) - throw new ArgumentException($"For half buffer type nativeBufferStartIndex and computeBufferStartIndex should be modulo of 2."); - - numElementToCopy += numElementToCopy % 2; - - int uintBufferViewLength = LengthWithPaddingForGPUCopy(m_DataType, m_Length) / 2; - NativeArray nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(RawPtr, uintBufferViewLength, m_Allocator); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, AtomicSafetyHandle.Create()); -#endif - //TODO fp16 should computeBufferStartIndex be expressed in half or uint? For now in half - buffer.SetData(nativeArray, elementStartIndex/2, computeBufferStartIndex/2, numElementToCopy/2); - } - else - { - throw new NotImplementedException($"Type {m_DataType} not supported."); - } - } - - /// - /// Warning, this return a copy! Do not use to modify a BarracudaArray - /// - public static implicit operator float[](BarracudaArray barracudaArray) - { - var floatArray = new float[barracudaArray.Length]; - Copy(barracudaArray, 0, floatArray, 0, barracudaArray.Length); - return floatArray; - } - - public void CopyTo(BarracudaArray dst, int dstOffset) - { - Copy(this, 0, dst, dstOffset, Length); - } - - public void CopyTo(BarracudaArray dst, long dstOffset) - { - Copy(this, 0, dst, (int)dstOffset, Length); - } - - public static void Copy(BarracudaArray sourceArray, BarracudaArray destinationArray, int length = -1) - { - Copy(sourceArray, 0, destinationArray, 0, length); - } - - public static void Copy(float[] sourceArray, BarracudaArray destinationArray, int length = -1) - { - Copy(sourceArray, 0, destinationArray, 0, length); - } - - public static unsafe void Copy( - BarracudaArray sourceArray, - int sourceIndex, - BarracudaArray destinationArray, - int destinationIndex, - int length) - { - if (length < 0) - length = sourceArray.Length; - if (length == 0) - return; - if (sourceIndex+length > sourceArray.Length) - throw new ArgumentException($"Cannot copy {length} element from sourceIndex {sourceIndex} and Barracuda array of length {sourceArray.Length}."); - if (destinationIndex+length > destinationArray.Length) - throw new ArgumentException($"Cannot copy {length} element to sourceIndex {destinationIndex} and Barracuda array of length {destinationArray.Length}."); - - //Same type we can do a memcopy - if (sourceArray.m_DataType == destinationArray.m_DataType) - { - int itemSize = DataItemSize(sourceArray.m_DataType); - void* srcPtr = (byte*)sourceArray.RawPtr + sourceIndex * itemSize; - void* dstPtr = (byte*)destinationArray.RawPtr + destinationIndex * itemSize; - UnsafeUtility.MemCpy(dstPtr, srcPtr, length * itemSize); - } - else//different type, we need to iterate and cast - { - for (var i=0; i < length; ++i) - { - //this will use float as intermediate/common representation - destinationArray[destinationIndex+i] = sourceArray[sourceIndex+i]; - } - } - } - - public static unsafe void Copy( - BarracudaArray sourceArray, - int sourceIndex, - float[] destinationArray, - int destinationIndex, - int length) - { - if (length < 0) - length = sourceArray.Length; - if (length == 0) - return; - if (sourceIndex+length > sourceArray.Length) - throw new ArgumentException($"Cannot copy {length} element from sourceIndex {sourceIndex} and Barracuda array of length {sourceArray.Length}."); - if (destinationIndex+length > destinationArray.Length) - throw new ArgumentException($"Cannot copy {length} element to sourceIndex {destinationIndex} and array of length {destinationArray.Length}."); - - //Same type we can do a memcopy - if (sourceArray.m_DataType == DataType.Float) - { - fixed (void* dstPtr = &destinationArray[destinationIndex]) - { - int itemSize = DataItemSize(sourceArray.m_DataType); - void* srcPtr = (byte*)sourceArray.RawPtr + sourceIndex * itemSize; - UnsafeUtility.MemCpy(dstPtr, srcPtr, length * itemSize); - } - } - else//different type, we need to iterate and cast - { - for (var i=0; i < length; ++i) - { - //this will use float as intermediate/common representation - destinationArray[destinationIndex+i] = sourceArray[sourceIndex+i]; - } - } - } - - public static unsafe void BlockCopy( - BarracudaArray sourceArray, - int sourceByteOffset, - byte[] destinationArray, - int destinationByteOffset, - int lengthInBytes) - { - int itemSize = sourceArray.SizeOfType; - int srcLengthBytes = sourceArray.Length * itemSize; - - if (lengthInBytes == 0) - return; - if (lengthInBytes < 0) - lengthInBytes = srcLengthBytes; - - if (sourceByteOffset+lengthInBytes > srcLengthBytes) - throw new ArgumentException($"Cannot copy {lengthInBytes} bytes from sourceByteOffset {sourceByteOffset} and BarracudaArray of {srcLengthBytes} num bytes."); - if (destinationByteOffset+lengthInBytes > destinationArray.Length) - throw new ArgumentException($"Cannot copy {lengthInBytes} bytes to destinationByteOffset {destinationByteOffset} and byte[] array of {destinationArray.Length} num bytes."); - - fixed (void* dstPtr = &destinationArray[destinationByteOffset]) - { - void* srcPtr = (byte*)sourceArray.RawPtr + sourceByteOffset; - UnsafeUtility.MemCpy(dstPtr, srcPtr, lengthInBytes); - } - } - - public static unsafe void BlockCopy( - byte[] sourceArray, - int sourceByteOffset, - BarracudaArray destinationArray, - int destinationByteOffset, - int lengthInBytes) - { - if (lengthInBytes == 0) - return; - if (lengthInBytes < 0) - lengthInBytes = sourceArray.Length; - - if (sourceByteOffset+lengthInBytes > sourceArray.Length) - throw new ArgumentException($"Cannot copy {lengthInBytes} bytes from sourceByteOffset {sourceByteOffset} and byte[] array of {sourceArray.Length} num bytes."); - var fullDestPaddedSizeInByte = LengthWithPaddingForGPUCopy(destinationArray.Type, destinationArray.Length) * DataItemSize(destinationArray.Type); - if (destinationByteOffset+lengthInBytes > fullDestPaddedSizeInByte) - throw new ArgumentException($"Cannot copy {lengthInBytes} bytes to destinationByteOffset {destinationByteOffset} and byte[] array of {destinationArray.Length} num bytes."); - - void* dstPtr = (byte*)destinationArray.RawPtr + destinationByteOffset; - fixed (void* srcPtr = &sourceArray[sourceByteOffset]) - { - UnsafeUtility.MemCpy(dstPtr, srcPtr, lengthInBytes); - } - } - - public static void Copy( - float[] sourceArray, - int sourceIndex, - BarracudaArray destinationArray, - long destinationIndex, - int length) - { - Copy(sourceArray, sourceIndex, destinationArray, (int)destinationIndex, length); - } - - public static unsafe void Copy( - float[] sourceArray, - int sourceIndex, - BarracudaArray destinationArray, - int destinationIndex, - int length) - { - if (length < 0) - length = sourceArray.Length; - if (length == 0) - return; - if (sourceIndex+length > sourceArray.Length) - throw new ArgumentException($"Cannot copy {length} element from sourceIndex {sourceIndex} and Barracuda array of length {sourceArray.Length}."); - if (destinationIndex+length > destinationArray.Length) - throw new ArgumentException($"Cannot copy {length} element to sourceIndex {destinationIndex} and Barracuda array of length {destinationArray.Length}."); - - //Same type we can do a memcopy - if (destinationArray.m_DataType == DataType.Float) - { - fixed (void* srcPtr = &sourceArray[sourceIndex]) - { - int itemSize = DataItemSize(destinationArray.m_DataType); - void* dstPtr = (byte*)destinationArray.RawPtr + destinationIndex * itemSize; - UnsafeUtility.MemCpy(dstPtr, srcPtr, length * itemSize); - } - } - else//different type, we need to iterate and cast - { - for (var i=0; i < length; ++i) - { - //this will use float as intermediate/common representation - destinationArray[destinationIndex+i] = sourceArray[sourceIndex+i]; - } - } - } - #endregion -} - -static class BarracudaArrayExtensionHelper -{ - public static void CopyToBarracudaArray(this float[] sourceArray, BarracudaArray destinationArray, int destinationIndex) - { - BarracudaArray.Copy(sourceArray, 0, destinationArray, destinationIndex, sourceArray.Length); - } - - public static void CopyToBarracudaArray(this float[] sourceArray, BarracudaArray destinationArray, long destinationIndex) - { - BarracudaArray.Copy(sourceArray, 0, destinationArray, (int)destinationIndex, sourceArray.Length); - } -} - - -} // namespace Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/BarracudaArray.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/BarracudaArray.cs.meta deleted file mode 100644 index e37f24b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/BarracudaArray.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 49caea3e61ce5e549a46e06997276d98 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler.meta deleted file mode 100644 index 1f06f80..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 33416e2127feb6442aae546257f8aaed -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes.meta deleted file mode 100644 index c44f060..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4a0547a72e91f8f4dbe87d7a743c177c -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ConcatenateTransposesPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ConcatenateTransposesPass.cs deleted file mode 100644 index a6a93b3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ConcatenateTransposesPass.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes.Optimization -{ - class ConcatenateTransposesPass : IModelPass - { - public void Run(ref Model model) - { - int previousLayerCount; - do - { - // Continue to reduce until no more reductions can happen - previousLayerCount = model.layers.Count; - ConcatenateTransposes(ref model); - } while (model.layers.Count < previousLayerCount); - } - - void ConcatenateTransposes(ref Model model) - { - - var transposeReferences = new Dictionary(); - var layerDownstreamCounts = new Dictionary(); - for (int l = 0; l < model.layers.Count; ++l) - { - Layer layer = model.layers[l]; - - layerDownstreamCounts[layer.name] = 0; - - foreach (var input in layer.inputs) - { - if (layerDownstreamCounts.ContainsKey(input)) - layerDownstreamCounts[input] += 1; - } - - if (layer.type != Layer.Type.Transpose) - continue; - - transposeReferences[layer.name] = l; - } - - var remap = new Dictionary(); - - for (int l = 0; l < model.layers.Count; ++l) - { - Layer layer = model.layers[l]; - if (layer.type != Layer.Type.Transpose) - continue; - - string input = layer.inputs[0]; - - if (!transposeReferences.ContainsKey(input)) - continue; - - if (layerDownstreamCounts[input] != 1) - continue; - - Layer previousLayer = model.layers[transposeReferences[input]]; - - if (previousLayer.flags.HasFlag(Layer.Flags.Preserve) && layer.flags.HasFlag(Layer.Flags.Preserve)) - continue; - - // previous layer is a transpose and current layer is the only downstream layer - var permutations = MergeTranspose(previousLayer.pool, layer.pool); - - bool reverseMerge = previousLayer.flags.HasFlag(Layer.Flags.Preserve); - - // merge previous into current unless previous cannot be removed, else reverse - if (reverseMerge) - { - remap[layer.name] = previousLayer.name; - previousLayer.pool = permutations; - } - else - { - remap[previousLayer.name] = layer.name; - layer.pool = permutations; - layer.inputs = previousLayer.inputs.ToArray(); - } - } - - for (int l = 0; l < model.layers.Count; ++l) - { - Layer layer = model.layers[l]; - for (int i = 0; i < layer.inputs.Length; i++) - { - var input = layer.inputs[i]; - if (remap.ContainsKey(input)) - model.layers[l].inputs[i] = remap[input]; - } - } - - model.layers.RemoveAll(l => remap.ContainsKey(l.name)); - } - - int[] MergeTranspose(int[] transpose0, int[] tranpose1) - { - int[] permutations = new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - if (transpose0.Length == 4) - { - permutations[2] = TensorExtensions.Convert4DTo8DAxis(transpose0[0]); - permutations[5] = TensorExtensions.Convert4DTo8DAxis(transpose0[1]); - permutations[6] = TensorExtensions.Convert4DTo8DAxis(transpose0[2]); - permutations[7] = TensorExtensions.Convert4DTo8DAxis(transpose0[3]); - } - else - { - permutations[0] = transpose0[0]; - permutations[1] = transpose0[1]; - permutations[2] = transpose0[2]; - permutations[3] = transpose0[3]; - permutations[4] = transpose0[4]; - permutations[5] = transpose0[5]; - permutations[6] = transpose0[6]; - permutations[7] = transpose0[7]; - } - - int[] combinePermutations = new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - if (tranpose1.Length == 4) - { - combinePermutations[2] = TensorExtensions.Convert4DTo8DAxis(tranpose1[0]); - combinePermutations[5] = TensorExtensions.Convert4DTo8DAxis(tranpose1[1]); - combinePermutations[6] = TensorExtensions.Convert4DTo8DAxis(tranpose1[2]); - combinePermutations[7] = TensorExtensions.Convert4DTo8DAxis(tranpose1[3]); - } - else - { - combinePermutations[0] = tranpose1[0]; - combinePermutations[1] = tranpose1[1]; - combinePermutations[2] = tranpose1[2]; - combinePermutations[3] = tranpose1[3]; - combinePermutations[4] = tranpose1[4]; - combinePermutations[5] = tranpose1[5]; - combinePermutations[6] = tranpose1[6]; - combinePermutations[7] = tranpose1[7]; - } - - permutations = TensorExtensions.Permute(permutations, combinePermutations); - - return permutations; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ConcatenateTransposesPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ConcatenateTransposesPass.cs.meta deleted file mode 100644 index b5056cc..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ConcatenateTransposesPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 986232e7f6f7e1f4b8b61bb6945dec66 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ContractToSimplerLayerPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ContractToSimplerLayerPass.cs deleted file mode 100644 index 35271b9..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ContractToSimplerLayerPass.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes.Optimization -{ - class ContractToSimplerLayerPass : IModelPass - { - public void Run(ref Model model) - { - for (int l = 0; l < model.layers.Count; ++l) - { - Layer layer = model.layers[l]; - - if (layer.type == Layer.Type.Concat) - { - model.layers[l] = ContractConcat(layer); - } - } - } - - private Layer ContractConcat(Layer layer) - { - if (layer.inputs.Any(o => o != layer.inputs[0])) - return layer; - - Layer newLayer = new Layer(layer.name, Layer.Type.Tile); - - newLayer.type = Layer.Type.Tile; - - newLayer.pool = new[] { 1, 1, 1, 1, 1, 1, 1, 1 }; - newLayer.pool[layer.axis] = layer.inputs.Length; - newLayer.inputs = new[] { layer.inputs[0] }; - - return newLayer; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ContractToSimplerLayerPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ContractToSimplerLayerPass.cs.meta deleted file mode 100644 index 82986a6..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ContractToSimplerLayerPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 132240a1842182b43b5e63a2794ca833 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseActivationsPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseActivationsPass.cs deleted file mode 100644 index 64109e4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseActivationsPass.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes.Optimization -{ - class FuseActivationPass : IModelPass - { - public void Run(ref Model model) - { - //Fused activation - var fusableActivations = model.layers.Where(l => l.type == Layer.Type.Activation && IsActivationFusable(l.activation)).ToList(); - foreach (var activationLayer in fusableActivations) - { - if (activationLayer.inputs.Length != 1) - continue; - - var mainLayer = model.layers.Find(l => l.name == activationLayer.inputs[0]); - if (mainLayer == null) - continue; - - if (!IsLayerSupportingActivationFusing(mainLayer.type)) - continue; - - if (mainLayer.activation != Layer.Activation.None) - continue; - - if (model.outputs.Contains(mainLayer.name)) - continue; - - if (model.memories.Exists(m => m.output == mainLayer.name)) - continue; - - //Need to check that no other layers uses mainLayer directly. - //Activation in the graph below can not be fused because (concat) layer needs raw output of (conv) layer - //conv -> relu -----. - // \ v - // `---------> concat - if (model.layers.Exists(l => l != activationLayer && l.inputs.Contains(mainLayer.name))) - continue; - - if (activationLayer.flags.HasFlag(Layer.Flags.Preserve)) - continue; - - FuseActivation(ref model, mainLayer, activationLayer); - } - } - - public static bool IsLayerSupportingActivationFusing(Layer.Type layerType) - { - return layerType == Layer.Type.Dense || - layerType == Layer.Type.Conv2D || - layerType == Layer.Type.Conv3D || - layerType == Layer.Type.DepthwiseConv2D || - layerType == Layer.Type.Conv2DTrans || - layerType == Layer.Type.Normalization; - } - - public static bool IsActivationFusable(Layer.Activation activationType) - { - var fusedActivationType = (Layer.FusedActivation) activationType; - switch (fusedActivationType) - { - case Layer.FusedActivation.None: - case Layer.FusedActivation.Relu: - case Layer.FusedActivation.Tanh: - case Layer.FusedActivation.Softplus: - case Layer.FusedActivation.Sigmoid: - case Layer.FusedActivation.Relu6: - case Layer.FusedActivation.Swish: - case Layer.FusedActivation.Neg: - case Layer.FusedActivation.Sqrt: - case Layer.FusedActivation.Exp: - case Layer.FusedActivation.Log: - case Layer.FusedActivation.Acos: - case Layer.FusedActivation.Acosh: - case Layer.FusedActivation.Asin: - case Layer.FusedActivation.Asinh: - case Layer.FusedActivation.Atan: - case Layer.FusedActivation.Atanh: - case Layer.FusedActivation.Cos: - case Layer.FusedActivation.Cosh: - case Layer.FusedActivation.Sin: - case Layer.FusedActivation.Sinh: - case Layer.FusedActivation.Tan: - case Layer.FusedActivation.Erf: - return true; - default: - return false; - } - } - - static private void FuseActivation(ref Model model, Layer mainLayer, Layer activationToFuse) - { - //patch `mainLayer` - mainLayer.activation = activationToFuse.activation; - - //patch all layers depending on `activationToFuse` - foreach (var l in model.layers) - { - for (int i = 0; i < l.inputs.Length; ++i) - { - if (l.inputs[i] == activationToFuse.name) - l.inputs[i] = mainLayer.name; - } - } - - //remove `activationToFuse` if not an output, if an output make it an identity layer instead. - if (model.outputs.Contains(activationToFuse.name) || model.memories.Exists(m => m.output == activationToFuse.name)) - { - activationToFuse.type = Layer.Type.Nop; - activationToFuse.activation = Layer.Activation.None; - } - else - model.layers.Remove(activationToFuse); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseActivationsPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseActivationsPass.cs.meta deleted file mode 100644 index ee4a47f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseActivationsPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: eee50504d5dd3e145bcb624a23c08ee0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseConstantsPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseConstantsPass.cs deleted file mode 100644 index 22d9163..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseConstantsPass.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace Unity.Barracuda.Compiler.Passes.Optimization -{ - class FuseConstantsPass : IModelPass - { - public void Run(ref Model model) - { - FuseConstants(ref model); - } - - public static void FuseConstants(ref Model model) - { - var knownLayersValue = new Dictionary(); - var newKnownLayers = new HashSet(); - var keepLayers = new HashSet(); - - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - if (layer.flags == Layer.Flags.Preserve) - keepLayers.Add(layer.name); - - // NN is a directed graph, if we just fused constants + shapes, update following nodes - // TODO optimization, pass in index, or add shape - if (ModelOptimizer.IsLayerConstant(layer)) - knownLayersValue[layer.name] = new Tensor(layer.datasets[0].shape, layer.weights); - - bool allInputsAreKnown = layer.inputs.Length > 0 ? knownLayersValue.ContainsKey(layer.inputs[0]) : false; - for (int i = 1; i < layer.inputs.Length; i++) - allInputsAreKnown &= knownLayersValue.ContainsKey(layer.inputs[i]); - - // if all inputs are known, execute layer - if (!allInputsAreKnown) - continue; - - var layerInputs = new Dictionary(); - var opsModel = new Model(); - for (int i = 0; i < layer.inputs.Length; i++) - { - Model.Input input; - input.name = layer.inputs[i]; - input.shape = knownLayersValue[input.name].shape.ToArray(); - input.rank = knownLayersValue[input.name].shape.dimensions; - - opsModel.inputs.Add(input); - layerInputs[input.name] = knownLayersValue[input.name]; - } - opsModel.layers.Add(layer); - opsModel.outputs.Add(layer.name); - - // bake - var useCPUforBaking = WorkerFactory.Device.CPU; - using (var worker = WorkerFactory.CreateWorker(opsModel, useCPUforBaking)) - { - // TODO use ModelIR2RunnableNCHWPass - var bakedConstant = worker.Execute(layerInputs).PeekOutput(); - bakedConstant.TakeOwnership(); - knownLayersValue[layer.name] = bakedConstant; - newKnownLayers.Add(layer.name); - } - } - - // remove new baked layers since we will insert constants for those - model.layers.RemoveAll(x => newKnownLayers.Contains(x.name) && !keepLayers.Contains(x.name)); - - // TODO use ModelBuilder? - foreach (var l in newKnownLayers) - { - if (keepLayers.Contains(l)) - continue; - - var name = l; - var tensor = knownLayersValue[name]; - Layer c = new Layer(name, Layer.Type.Load); - - c.datasets = new Layer.DataSet[1]; - c.datasets[0].name = name; - c.datasets[0].shape = tensor.shape; - c.datasets[0].itemSizeInBytes = 4; - c.datasets[0].length = tensor.shape.length; - c.datasets[0].offset = 0; - - c.axis = tensor.shape.dimensions; - - c.weights = new BarracudaArray(tensor.length); - BarracudaArray.Copy(tensor.ToReadOnlyArray(), c.weights, tensor.length); - model.layers.Insert(0, c); - } - - // clear allocated tensors - foreach (var l in knownLayersValue) - l.Value.Dispose(); - - // remove unused constants - var removeUnusedLayersPass = new Cleanup.RemoveUnusedLayersPass(); - removeUnusedLayersPass.Run(ref model); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseConstantsPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseConstantsPass.cs.meta deleted file mode 100644 index 4c5c3a3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseConstantsPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8b70c806d0c69b04bbbfaf86c0797340 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseDense3Pass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseDense3Pass.cs deleted file mode 100644 index 2165fcd..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseDense3Pass.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes.Optimization -{ - class FuseDense3Pass : IModelPass - { - public void Run(ref Model model) - { - // MatMul (rank3) + known input -> Add/Sub => Dense3 - var constLayers = new Dictionary(); - foreach (var l in model.layers) - { - if (l.type == Layer.Type.Load) - constLayers[l.name] = l; - } - var preserve = new HashSet( - model.memories.Select(mem => mem.input).Concat( - model.memories.Select(mem => mem.output)).Concat( - model.outputs)); - - - var removeLayers = new HashSet(); - var remap = new Dictionary(); - - for (int l = 0; l < model.layers.Count - 1; ++l) - { - Layer layer = model.layers[l]; - - List downStreamLayers = GetDownStreamLayers(model, layer.name); - - if (!IsLayerDense3(layer, downStreamLayers, constLayers)) - continue; - - if (preserve.Contains(layer.name) || preserve.Contains(downStreamLayers[0].name)) - continue; - - string weights = (layer.inputs.Where(x => constLayers.ContainsKey(x)).ToList())[0]; - Layer constWeights = constLayers[weights]; - var weightArray = constWeights.weights; - var weightShape = constWeights.datasets[0].shape; - - Layer downStreamLayer = downStreamLayers[0]; - string bias = (downStreamLayer.inputs.Where(x => x != layer.name).ToList())[0]; - Layer constBias = constLayers[bias]; - TensorShape biasShape = new TensorShape(1, 1, 1, Mathf.Max(weightShape.channels, constBias.datasets[0].shape.length)); - var biasArray = constBias.weights; - - var inputs = layer.inputs.Where(x => x != weights).ToArray(); - - Layer mergedLayer = new Layer(layer.name, Layer.Type.Dense3); - - mergedLayer.inputs = inputs; - - mergedLayer.datasets = new Layer.DataSet[2]; - mergedLayer.datasets[0].name = $"{mergedLayer.name}/W"; - mergedLayer.datasets[0].shape = weightShape; - mergedLayer.datasets[0].itemSizeInBytes = 4; - mergedLayer.datasets[0].length = weightShape.length; - mergedLayer.datasets[0].offset = 0; - mergedLayer.datasets[1].name = $"{mergedLayer.name}/B"; - mergedLayer.datasets[1].shape = biasShape; - mergedLayer.datasets[1].itemSizeInBytes = 4; - mergedLayer.datasets[1].length = biasShape.length; - mergedLayer.datasets[1].offset = weightShape.length; - mergedLayer.weights = new BarracudaArray(weightShape.length + biasShape.length); - - weightArray.CopyTo(mergedLayer.weights, 0); - if (constBias.datasets[0].shape.length == 1) - { - for (int i = 0; i < biasShape.length; i++) - mergedLayer.weights[mergedLayer.datasets[1].offset + i] = biasArray[0]; - } - else - biasArray.CopyTo(mergedLayer.weights, mergedLayer.datasets[1].offset); - - - model.layers[l] = mergedLayer; - - if (!preserve.Contains(constWeights.name)) - removeLayers.Add(constWeights.name); - removeLayers.Add(downStreamLayer.name); - if (!preserve.Contains(constBias.name)) - removeLayers.Add(constBias.name); - remap[downStreamLayer.name] = mergedLayer.name; - } - - model.layers.RemoveAll(l => removeLayers.Contains(l.name)); - for (int l = 0; l < model.layers.Count; ++l) - { - Layer layer = model.layers[l]; - for (int i = 0; i < layer.inputs.Length; i++) - { - var input = layer.inputs[i]; - if (remap.ContainsKey(input)) - model.layers[l].inputs[i] = remap[input]; - } - } - } - - List GetDownStreamLayers(Model model, string name) - { - return model.layers.Where(x => x.inputs.Contains(name)).ToList(); - } - - bool IsLayerDense3(Layer layer, List downStreamLayers, Dictionary constLayers) - { - if (layer.type != Layer.Type.MatMul) - return false; - if (!(layer.pool.Length == 2 && (layer.pool[0] == 3 && layer.pool[1] < 3))) - return false; - if (!(constLayers.ContainsKey(layer.inputs[0]) || constLayers.ContainsKey(layer.inputs[1]))) - return false; - if (downStreamLayers.Count != 1) - return false; - Layer downstreamLayer = downStreamLayers[0]; - if (!(downstreamLayer.type == Layer.Type.Add || downstreamLayer.type == Layer.Type.Sub)) - return false; - string input = (downstreamLayer.inputs.Where(x => x != layer.name).ToList())[0]; - if (!constLayers.ContainsKey(input)) - return false; - Layer constAdd = constLayers[input]; - if (constAdd.axis > 1) - return false; - return true; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseDense3Pass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseDense3Pass.cs.meta deleted file mode 100644 index d84e0bf..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseDense3Pass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bd04fbb03eb179446a6bb54828a340c4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseLinearLayersPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseLinearLayersPass.cs deleted file mode 100644 index 560e825..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseLinearLayersPass.cs +++ /dev/null @@ -1,226 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes.Optimization -{ - class FuseLinearLayersPass : IModelPass - { - public void Run(ref Model model) - { - var constantLayers = new Dictionary(); - foreach (var l in model.layers) - { - if (IsLayerConstant(l)) - constantLayers[l.name] = l; - } - - // pack mathops const inputs into layer database - PackConstantsForMathOps(model, constantLayers); - - var remap = new Dictionary(); - var mergedLayers = new HashSet(); - - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - - bool isLayerLinear = LinearLayerFusing.IsLayerLinear(layer, constantLayers); - bool isLayerPreserved = layer.flags.HasFlag(Layer.Flags.Preserve); - bool layerHasActivation = IsLayerFusedActivation(layer); - - if (!isLayerLinear) - continue; - - // if layer has an activation, we fuse it, but treat it as non linear for future children - if (!layerHasActivation) - { - remap[layer.name] = layer.name; - } - - // Multi input nodes can only fuse constants and same inputs - // only merge constants. @TODO: fuse equal input nodes - var nonLinearInputs = layer.inputs.Where(x => !remap.ContainsKey(x) && !constantLayers.ContainsKey(x)).ToList(); - var linearInputs = layer.inputs.Where(x => remap.ContainsKey(x)).ToList(); - - // merge layer with one linearInput and eventual constants - if (nonLinearInputs.Count > 0 || linearInputs.Count > 1) - continue; - - var input = linearInputs[0]; - - // input is a linear layer, fuse it - int inputLayerIndex = model.layers.FindIndex(x => x.name == remap[input]); - Layer inputLayer = model.layers[inputLayerIndex]; - - if (!AreLayersFusable(inputLayer, layer)) - continue; - - // convention: layer will be fused into inputLayer - // => fused layer will have the same inputs as inputLayer - Layer fusedLayer = FuseConsecutiveLayers(inputLayer, layer); - - // if isLayerPreserved : - // new complexity = fusedLayer + inputLayer - // else - // new complexity = fusedLayer - // test if new complexity is worth the merge - long layerComplexity = LayerComplextity(layer); - long inputComplexity = LayerComplextity(inputLayer); - long oldComplexity = inputComplexity + layerComplexity; - long newComplexity = LayerComplextity(fusedLayer) + (isLayerPreserved ? inputComplexity : 0); - if (newComplexity > oldComplexity) - continue; - - if (layerHasActivation) - { - fusedLayer.activation = layer.activation; - } - - bool hasNoSkipConnection = (model.GetDownStreamLayersCount(input) == 1); - // if input has more than 1 child, we can't override input with fused result - // same if input is preserved - if (!hasNoSkipConnection || model.layers.Any(p => p.flags.HasFlag(Layer.Flags.Preserve) && p.name == input)) - { - fusedLayer.name = layer.name; - model.layers[l] = fusedLayer; - continue; - } - - // preserve layer if output/memory - if (isLayerPreserved) - { - // cannot merge layer into input: - // remove input, no need to remap as inputs == input.inputs - fusedLayer.name = layer.name; - mergedLayers.Add(inputLayer); - model.layers[l] = fusedLayer; - } - else - { - // merge layer into input - // remove current and remap input names - mergedLayers.Add(layer); - remap[layer.name] = fusedLayer.name; - model.layers[inputLayerIndex] = fusedLayer; - } - } - - // remove merged layers - model.layers.RemoveAll(x => mergedLayers.Contains(x)); - - // update remapped inputs - for (int l = 0; l < model.layers.Count; ++l) - { - Layer layer = model.layers[l]; - for (int i = 0; i < layer.inputs.Length; ++i) - { - var input = layer.inputs[i]; - if (remap.ContainsKey(input)) - model.layers[l].inputs[i] = remap[input]; - } - } - - // unpack maths ops const inputs into new const layer - UnpackConstantsForMathOps(model); - - // remove unused constants - foreach (var l in model.layers) - foreach (var i in l.inputs) - { - if (constantLayers.ContainsKey(i)) - constantLayers.Remove(i); - } - model.layers.RemoveAll(x => constantLayers.ContainsKey(x.name) && - !x.flags.HasFlag(Layer.Flags.Preserve)); - } - - public static bool IsLayerConstant(Layer layer) - { - return layer.type == Layer.Type.Load; - } - static bool IsLayerFusedActivation(Layer layer) - { - return layer.activation != Layer.Activation.None; - } - - static StaticLayerOppComplexity m_LayerComplexity = new StaticLayerOppComplexity(); - static long LayerComplextity(Layer l) { return m_LayerComplexity.LayerComplextity(l); } - - static LinearLayerFusing linearLayerFuser = new LinearLayerFusing(); - static Layer FuseConsecutiveLayers(Layer previous, Layer current) - { - return linearLayerFuser.FuseLayers(previous, current); - } - static bool AreLayersFusable(Layer l0, Layer l1) - { - // can't fuse if input has a fused activation or if fusing code not implemented - return !IsLayerFusedActivation(l0) && linearLayerFuser.AreLayersFusable(l0, l1); - } - - private static void PackConstantsForMathOps(Model model, Dictionary constantLayers) - { - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - - if (!LinearLayerFusing.IsLayerLinearMathOp(layer)) - continue; - var constInputs = layer.inputs.Count(x => constantLayers.ContainsKey(x)); - // @TODO fuse multi const inputs here - if (!(layer.inputs.Length == 2 && constInputs == 1)) - continue; - - var constInput = layer.inputs.ToList().Find(x => constantLayers.ContainsKey(x)); - - layer.datasets = new Layer.DataSet[constantLayers[constInput].datasets.Length]; - Array.Copy(constantLayers[constInput].datasets, layer.datasets, constantLayers[constInput].datasets.Length); - layer.weights = new BarracudaArray(constantLayers[constInput].weights.Length); - BarracudaArray.Copy(constantLayers[constInput].weights, layer.weights, constantLayers[constInput].weights.Length); - - layer.axis = constantLayers[constInput].axis; // rank TODO name correctly - - model.layers[l].inputs = layer.inputs.Where(x => x != constInput).ToArray(); - } - } - - private static void UnpackConstantsForMathOps(Model model) - { - List newConstants = new List(); - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - if (!LinearLayerFusing.IsLayerLinearMathOp(layer)) - continue; - - if (layer.datasets == null || layer.datasets.Length != 1) - continue; - - var name = "c" + layer.name; - Layer constInput = new Layer(name, Layer.Type.Load); - - constInput.datasets = new Layer.DataSet[layer.datasets.Length]; - Array.Copy(layer.datasets, constInput.datasets, layer.datasets.Length); - for (int d = 0; d < constInput.datasets.Length; ++d) - constInput.datasets[d].name = name; - - constInput.weights = new BarracudaArray(layer.weights.Length); - BarracudaArray.Copy(layer.weights, constInput.weights, layer.weights.Length); - - constInput.axis = layer.axis; // rank TODO rename - - Array.Resize(ref layer.inputs, layer.inputs.Length + 1); - layer.inputs[layer.inputs.Length - 1] = constInput.name; - - newConstants.Add(constInput); - - layer.datasets = new Layer.DataSet[0]; - layer.weights = new BarracudaArray(0);//TODO fp16 - } - newConstants.AddRange(model.layers); - model.layers = newConstants; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseLinearLayersPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseLinearLayersPass.cs.meta deleted file mode 100644 index 7836bd7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/FuseLinearLayersPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8961907c32645b740a401bdd3a36504d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IModelPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IModelPass.cs deleted file mode 100644 index ecd69f6..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IModelPass.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace Unity.Barracuda.Compiler.Passes -{ - interface IModelPass - { - /// - /// Run a pass over the whole model modifying in-place - /// - /// Model to modify - void Run(ref Model model); - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IModelPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IModelPass.cs.meta deleted file mode 100644 index 46bf29e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IModelPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 75540cfd84109804fb1570850352a2e6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IRShapeInferenceAndConstantFusing.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IRShapeInferenceAndConstantFusing.cs deleted file mode 100644 index 6403179..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IRShapeInferenceAndConstantFusing.cs +++ /dev/null @@ -1,654 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes -{ - class IRShapeInferenceAndConstantFusing : IModelPass - { - public void Run(ref Model model) - { - Run(ref model, null); - } - - //TODO this pass is handling data transformation in a destructive way and thus loss validation information. - //find a cleaner way to report import warnings. - public void Run(ref Model model, List warnings) - { - IDictionary inputShapes = new Dictionary(); - IDictionary inputRanks = new Dictionary(); - List inputs = model.inputs; - foreach (var i in inputs) - { - inputRanks[i.name] = i.rank; - if (!ModelAnalyzer.IsInputShapeAcceptablyKnowForShapeInference(i)) - continue; - inputShapes[i.name] = new TensorShape(i.shape); - } - FuseShapesIntoConstants(ref model, inputShapes, inputRanks, ref warnings); - } - - private static Tensor ShapeToNCHWTensor(TensorShape shape, int rank) - { - switch (rank) - { - case 0: - return new Tensor(new TensorShape(1), new float[] { 0 }); - case 1: - return new Tensor(new TensorShape(1), new float[] { shape.batch }); - case 2: - return new Tensor(new TensorShape(2), new float[] { shape.batch, shape.height }); - case 3: - return new Tensor(new TensorShape(3), new float[] { shape.batch, shape.height, shape.width }); - case 4: - return new Tensor(new TensorShape(4), new float[] { shape.batch, shape.height, shape.width, shape.channels }); - case 5: - return new Tensor(new TensorShape(5), new float[] { shape.batch, shape.depth, shape.height, shape.width, shape.channels }); - default: - return new Tensor(new TensorShape(8), new float[] { shape.sequenceLength, shape.numberOfDirections, shape.batch, shape.extraDimension, shape.depth, shape.height, shape.width, shape.channels }); - } - } - - private void FuseShapesIntoConstants(ref Model model, IDictionary shapesByName, IDictionary ranksByName, ref List warnings) - { - var toRunnableNCHW = new IntermediateToRunnableNCHWPass(); - - var knownLayersValue = new Dictionary(); - var newKnownLayers = new HashSet(); - var keepLayers = new HashSet(); - - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - if (layer.flags == Layer.Flags.Preserve) - keepLayers.Add(layer.name); - - // NN is a directed graph, if we just fused constants + shapes, update following nodes - // re-evaluate shapes - FuseInputsIntoLayer(ref layer, knownLayersValue, ranksByName, warnings); - // TODO optimization, pass in index, or add shape - IRShapeInferenceHelper.RankInference.UpdateKnownTensorRanks(model, ranksByName); - IRShapeInferenceHelper.ShapeInference.UpdateKnownTensorShapesNCHW(model, ref ranksByName, ref shapesByName); - - if (ModelOptimizer.IsLayerConstant(layer)) - knownLayersValue[layer.name] = new Tensor(layer.datasets[0].shape, layer.weights); - else if (layer.type == Layer.Type.Shape) - { - // assert inputs.Lenght == 1 - var input = layer.inputs[0]; - if (shapesByName.ContainsKey(input) && shapesByName[input] != null && - ranksByName.ContainsKey(input) && ranksByName[input] != null - ) - { - var shape = shapesByName[input].Value; - var rank = ranksByName[input].Value; - knownLayersValue[layer.name] = ShapeToNCHWTensor(shape, rank); - newKnownLayers.Add(layer.name); - continue; - } - } - - bool allInputsAreKnown = layer.inputs.Length > 0 ? knownLayersValue.ContainsKey(layer.inputs[0]) : false; - for (int i = 1; i < layer.inputs.Length; i++) - allInputsAreKnown &= knownLayersValue.ContainsKey(layer.inputs[i]); - - // if all inputs are known, execute layer - if (!allInputsAreKnown) - continue; - - var layerInputs = new Dictionary(); - var opsModel = new Model(); - opsModel.layout = "iNCHW"; - for (int i = 0; i < layer.inputs.Length; i++) - { - Model.Input input; - input.name = layer.inputs[i]; - input.shape = shapesByName[input.name].Value.ToArray(); - input.rank = ranksByName[input.name].Value; - - opsModel.inputs.Add(input); - layerInputs[input.name] = knownLayersValue[input.name]; - } - Layer newLayer = new Layer(layer.name.ToString(), layer.activation); - newLayer.type = layer.type; - newLayer.activation = layer.activation; - newLayer.pad = layer.pad.ToArray(); - newLayer.stride = layer.stride.ToArray(); - newLayer.pool = layer.pool.ToArray(); - newLayer.axis = layer.axis; - newLayer.alpha = layer.alpha; - newLayer.beta = layer.beta; - newLayer.inputs = layer.inputs.ToArray(); - newLayer.datasets = layer.datasets; - newLayer.weights = layer.weights; - if(layer.outputs != null) - newLayer.outputs = layer.outputs.ToArray(); - if (layer.axes != null) - newLayer.axes = layer.axes.ToArray(); - - - opsModel.layers.Add(newLayer); - opsModel.outputs.Add(newLayer.name); - - toRunnableNCHW.Run(ref opsModel); - - // bake - var useCPUforBaking = WorkerFactory.Device.CPU; - using (var worker = WorkerFactory.CreateWorker(opsModel, useCPUforBaking)) - { - var bakedConstant = worker.Execute(layerInputs).CopyOutput(); - knownLayersValue[layer.name] = bakedConstant; - newKnownLayers.Add(layer.name); - } - } - - // remove new baked layers since we will insert constants for those - model.layers.RemoveAll(x => newKnownLayers.Contains(x.name) && !keepLayers.Contains(x.name)); - - // TODO use ModelBuilder? - foreach (var l in newKnownLayers) - { - if (keepLayers.Contains(l)) - continue; - - var name = l; - var tensor = knownLayersValue[name]; - Layer c = new Layer(name, Layer.Type.Load); - - c.datasets = new Layer.DataSet[1]; - c.datasets[0].name = name; - c.datasets[0].shape = tensor.shape; - c.datasets[0].itemSizeInBytes = 4; - c.datasets[0].length = tensor.shape.length; - c.datasets[0].offset = 0; - - c.axis = ranksByName[c.name].Value; - - c.weights = new BarracudaArray(tensor.length); - BarracudaArray.Copy(tensor.ToReadOnlyArray(), c.weights, tensor.length); - model.layers.Insert(0,c); - } - - foreach (var l in knownLayersValue) - l.Value.Dispose(); - - // TODO remove? - // remove unused constants - var removeUnusedLayersPass = new Cleanup.RemoveUnusedLayersPass(); - removeUnusedLayersPass.Run(ref model); - } - - // TODO: refactor with FuseShapesIntoConstants - public void InferAllShapes(Model model, ref IDictionary shapesByName, ref IDictionary ranksByName) - { - var toRunnableNCHW = new IntermediateToRunnableNCHWPass(); - - var knownLayersValue = new Dictionary(); - var newKnownLayers = new HashSet(); - var keepLayers = new HashSet(); - - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - if (layer.flags == Layer.Flags.Preserve) - keepLayers.Add(layer.name); - - // NN is a directed graph, if we just fused constants + shapes, update following nodes - // re-evaluate shapes - FuseInputsIntoLayer(ref layer, knownLayersValue, ranksByName, null);//TODO handle potential folding errors/warnings - // TODO optimization, pass in index, or add shape - IRShapeInferenceHelper.ShapeInference.UpdateKnownTensorShapesNCHW(model, ref ranksByName, ref shapesByName); - IRShapeInferenceHelper.RankInference.UpdateKnownTensorRanks(model, ranksByName); - - if (ModelOptimizer.IsLayerConstant(layer)) - knownLayersValue[layer.name] = new Tensor(layer.datasets[0].shape, layer.weights); - else if (layer.type == Layer.Type.Shape) - { - // assert inputs.Lenght == 1 - var input = layer.inputs[0]; - if (shapesByName.ContainsKey(input) && shapesByName[input] != null && - ranksByName.ContainsKey(input) && ranksByName[input] != null - ) - { - var shape = shapesByName[input].Value; - var rank = ranksByName[input].Value; - knownLayersValue[layer.name] = ShapeToNCHWTensor(shape, rank); - newKnownLayers.Add(layer.name); - continue; - } - } - - bool allInputsAreKnown = layer.inputs.Length > 0 ? knownLayersValue.ContainsKey(layer.inputs[0]) : false; - for (int i = 1; i < layer.inputs.Length; i++) - allInputsAreKnown &= knownLayersValue.ContainsKey(layer.inputs[i]); - - // if all inputs are known, execute layer - if (!allInputsAreKnown) - continue; - - var layerInputs = new Dictionary(); - var opsModel = new Model(); - opsModel.layout = "iNCHW"; - for (int i = 0; i < layer.inputs.Length; i++) - { - Model.Input input; - input.name = layer.inputs[i]; - input.shape = shapesByName[input.name].Value.ToArray(); - input.rank = ranksByName[input.name].Value; - - opsModel.inputs.Add(input); - layerInputs[input.name] = knownLayersValue[input.name]; - } - Layer newLayer = new Layer(layer.name.ToString(), layer.activation); - newLayer.type = layer.type; - newLayer.activation = layer.activation; - newLayer.pad = layer.pad.ToArray(); - newLayer.stride = layer.stride.ToArray(); - newLayer.pool = layer.pool.ToArray(); - newLayer.axis = layer.axis; - newLayer.alpha = layer.alpha; - newLayer.beta = layer.beta; - newLayer.inputs = layer.inputs.ToArray(); - newLayer.datasets = layer.datasets; - newLayer.weights = layer.weights; - if (layer.outputs != null) - newLayer.outputs = layer.outputs.ToArray(); - if (layer.axes != null) - newLayer.axes = layer.axes.ToArray(); - - - opsModel.layers.Add(newLayer); - opsModel.outputs.Add(newLayer.name); - - toRunnableNCHW.Run(ref opsModel); - - toRunnableNCHW.Run(ref opsModel); - - // bake - var useCPUforBaking = WorkerFactory.Device.CPU; - using (var worker = WorkerFactory.CreateWorker(opsModel, useCPUforBaking)) - { - var bakedConstant = worker.Execute(layerInputs).PeekOutput(); - bakedConstant.TakeOwnership(); - knownLayersValue[layer.name] = bakedConstant; - newKnownLayers.Add(layer.name); - } - } - - // clear allocated tensors - foreach (var l in knownLayersValue) - l.Value.Dispose(); - - // remove unused constants - var removeUnusedLayersPass = new Cleanup.RemoveUnusedLayersPass(); - removeUnusedLayersPass.Run(ref model); - } - - private bool IsLayerKnown(string name, Dictionary knownLayersValue) - { - return knownLayersValue.ContainsKey(name) && (name != null); - } - - public void FuseInputsIntoLayer(ref Layer layer, Dictionary knownLayersValue, IDictionary ranksByName, List warnings) - { - switch (layer.type) - { - case Layer.Type.Border2D: - case Layer.Type.Border3D: - case Layer.Type.Pad2DEdge: - case Layer.Type.Pad2DReflect: - case Layer.Type.Pad2DSymmetric: - { - if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - - float[] padsFloat = knownLayersValue[layer.inputs[1]].ToReadOnlyArray(); - layer.inputs = new[] { layer.inputs[0] }; - var pads = Array.ConvertAll(padsFloat, x => (int)x); - - var starts = pads.Take(pads.Length / 2).ToArray(); - var ends = pads.Skip(pads.Length / 2).ToArray(); - bool[] dimHavePadding = new bool[starts.Length]; - for (int i = 0; i < starts.Length; ++i) { - dimHavePadding[i] = starts[i] != 0 && ends[i] != 0; - } - - if (dimHavePadding.SequenceEqual(new bool []{ false, true, true, false })) - { - // Look like this padding operator is defined over NHWC layout - // We skip first and last dimension thus - starts = starts.Skip(1).Take(2).ToArray(); - ends = ends.Skip(1).Take(2).ToArray(); - layer.axes = new int[] { -1 };// Mark the layer padding as being imported as NHWC layout - } - else - { - // Skip non-spatial dimensions N, C (NCHW layout) - starts = starts.Skip(2).ToArray(); - ends = ends.Skip(2).ToArray(); - } - - switch (starts.Length) - { - case 1: layer.pad = new [] { starts[0], 0, ends[0], 0 }; break; // 1D W => W_ - case 2: layer.pad = new [] { starts[1], starts[0], ends[1], ends[0] }; break; // 2D HW => WH - default: layer.pad = new [] { starts[2], starts[1], starts[0], ends[2], ends[1], ends[0] }; break; // 3D DHW => WHD - } - - float value = 0.0f; - if (layer.inputs.Length >= 3 && IsLayerKnown(layer.inputs[2], knownLayersValue)) - value = knownLayersValue[layer.inputs[2]].ToReadOnlyArray()[0]; - - layer.beta = value; - return; - } - case Layer.Type.Upsample2D: - { - if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - - float[] scales = knownLayersValue[layer.inputs[1]].ToReadOnlyArray(); - - if (scales[0] == 1 && scales[1] == 1 && scales[2] < 1.0f && scales[3] < 1.0f && layer.axis >= 0.0f) - { - ValidationHelper.AppendWarning(scales.All(x => Mathf.Approximately(1f / x, Mathf.Round(1f / x))), - layer.name, $"Only inverse of scale values which produce integer are currently supported. Inverse of scale value will be rounded to closest integer.", ref warnings, MessageType.Warning); - - scales = new[] { scales[2], scales[3] }; - layer.type = Layer.Type.AvgPool2D; - layer.pad = new[] { 0, 0, 0, 0 }; - var inverseScalesRoundedToInt = scales.Select(x => (int)Mathf.Round(1f / x)).ToArray(); - layer.stride = inverseScalesRoundedToInt; - layer.pool = inverseScalesRoundedToInt; - } - else - { - ValidationHelper.AppendWarning(scales.All(x => Mathf.Approximately(x, Mathf.Round(x))), - layer.name, $"Only integer scale values are currently supported. Scale value will be rounded to closest integer value.", ref warnings, MessageType.Warning); - - layer.inputs = new[] { layer.inputs[0] }; - layer.pool = Array.ConvertAll(scales, x => (int)x); - } - return; - } - case Layer.Type.Resample2D: - { - if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - - int[] sizes = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => (int)x); - - layer.inputs = new[] { layer.inputs[0] }; - layer.pool = sizes; - return; - } - case Layer.Type.Expand: - { - if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - - float[] shapeValue = knownLayersValue[layer.inputs[1]].ToReadOnlyArray(); - var shape = new int[shapeValue.Length]; - for (int i = 0; i < shapeValue.Length; i++) - shape[i] = (int)shapeValue[i]; - - layer.pool = shape; - layer.inputs = new[] { layer.inputs[0] }; - return; - } - case Layer.Type.MatMul: - { - var input0 = layer.inputs[0]; var input1 = layer.inputs[1]; - if (!ranksByName.ContainsKey(input0) || !ranksByName[input0].HasValue) - return; - if (!ranksByName.ContainsKey(input1) || !ranksByName[input1].HasValue) - return; - int rank0 = ranksByName[input0].Value; - int rank1 = ranksByName[input1].Value; - - if(rank0 > 2 || rank1 > 2) - return; - - if (!IsLayerKnown(input1, knownLayersValue)) - return; - - layer.type = Layer.Type.Dense; - - var weight = knownLayersValue[input1]; - weight = weight.Reshape(new TensorShape(weight.batch, weight.height)); - var biasShape = new TensorShape(1, 1, 1, weight.shape.channels); - - layer.inputs = new [] { input0 }; - layer.datasets = new Layer.DataSet[2]; - layer.datasets[0].name = $"{layer.name}/W"; - layer.datasets[0].shape = weight.shape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = weight.shape.length; - layer.datasets[0].offset = 0; - layer.datasets[1].name = $"{layer.name}/B"; - layer.datasets[1].shape = biasShape; - layer.datasets[1].itemSizeInBytes = 4; - layer.datasets[1].length = biasShape.length; - layer.datasets[1].offset = weight.shape.length; - layer.weights = new BarracudaArray(weight.shape.length + biasShape.length); - - weight.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - var zeroBias = new float[biasShape.length]; - zeroBias.CopyToBarracudaArray(layer.weights, weight.shape.length); - return; - } - case Layer.Type.Tile: - { - if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - - var shape = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => (int)x); - layer.pool = shape; - - layer.inputs = new[] { layer.inputs[0] }; - return; - } - case Layer.Type.Reshape: - { - if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - - float[] shapeValue = knownLayersValue[layer.inputs[1]].ToReadOnlyArray(); - var shape = new int[shapeValue.Length]; - for (int i = 0; i < shapeValue.Length; i++) - shape[i] = (int)shapeValue[i]; - - layer.pool = shape; - layer.inputs = new[] { layer.inputs[0] }; - return; - } - case Layer.Type.ConstantOfShape: - { - if (layer.inputs.Length < 1 || !IsLayerKnown(layer.inputs[0], knownLayersValue)) - return; - - Tensor input = knownLayersValue[layer.inputs[0]]; - var shape = Array.ConvertAll(input.ToReadOnlyArray(), x => (int)x); - var tensorShape = IRShapeInferenceHelper.ShapeInference.OnnxLayoutToTensorShape(shape); - - - layer.type = Layer.Type.Load; - - - layer.axis = shape.Length; - layer.datasets = new Layer.DataSet[1]; - layer.datasets[0].name = layer.name; - layer.datasets[0].shape = tensorShape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = tensorShape.length; - layer.datasets[0].offset = 0; - layer.weights = new BarracudaArray(tensorShape.length); - - var tensor = new Tensor(tensorShape); - tensor.Fill(layer.alpha); - tensor.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - - layer.inputs = new string[0]; - return; - } - case Layer.Type.LSTM: - { - if (layer.inputs.Length <= 3 || !knownLayersValue.TryGetValue(layer.inputs[1], out Tensor W) - || !knownLayersValue.TryGetValue(layer.inputs[2], out Tensor R) - || !knownLayersValue.TryGetValue(layer.inputs[3], out Tensor B)) - return; - - var ops = new ReferenceCPUOps(); - using (var td = new TensorScope()) - { - TensorScope.F _ = td._; - - W = _(ops.Transpose(W, new[] { 2, 0, 3, 1 })); - R = _(ops.Transpose(R, new[] { 2, 0, 3, 1 })); - B = _(ops.Transpose(B, new[] { 0, 2, 3, 1 })); - - OpsUtils.BakeConstantWRBIntoLSTMLayer(layer, W, R, B); - } - - layer.inputs = new[] { layer.inputs[0], layer.inputs[4], layer.inputs[5] }; - - return; - } - case Layer.Type.Activation: - { - if (layer.activation == Layer.Activation.None) - { - if (layer.inputs.Length < 1 || !IsLayerKnown(layer.inputs[0], knownLayersValue)) - return; - - Tensor input = knownLayersValue[layer.inputs[0]]; - var tensorShape = input.shape; - - layer.type = Layer.Type.Load; - - int rank = input.dimensions; - if (ranksByName[layer.name] != null) - rank = ranksByName[layer.name].Value; - - layer.axis = rank; - layer.datasets = new Layer.DataSet[1]; - layer.datasets[0].name = layer.name; - layer.datasets[0].shape = tensorShape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = tensorShape.length; - layer.datasets[0].offset = 0; - layer.weights = new BarracudaArray(tensorShape.length); - - input.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - - layer.inputs = new string[0]; - } - - return; - } - case Layer.Type.Range: - { - if (layer.inputs.Length < 3 || !IsLayerKnown(layer.inputs[0], knownLayersValue) || !IsLayerKnown(layer.inputs[1], knownLayersValue) || !IsLayerKnown(layer.inputs[2], knownLayersValue)) - return; - - Tensor input0 = knownLayersValue[layer.inputs[0]]; - Tensor input1 = knownLayersValue[layer.inputs[1]]; - Tensor input2 = knownLayersValue[layer.inputs[2]]; - - var start = input0[0]; - var limit = input1[0]; - var delta = input2[0]; - - int nbOfElements = Mathf.Max((int)Mathf.Ceil((limit - start) / delta), 0); - - layer.type = Layer.Type.Load; - - layer.axis = 1; - layer.datasets = new Layer.DataSet[1]; - layer.datasets[0].name = layer.name; - layer.datasets[0].shape = new TensorShape(nbOfElements, 1); - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = nbOfElements; - layer.datasets[0].offset = 0; - layer.weights = new BarracudaArray(nbOfElements); - - for(int i=0; i < nbOfElements; ++i) - { - layer.weights[i] = start + (i * delta); - } - - layer.inputs = new string[0]; - return; - } - case Layer.Type.StridedSlice: - { - if (layer.inputs.Length <= 1 || - !IsLayerKnown(layer.inputs[1], knownLayersValue) || !IsLayerKnown(layer.inputs[2], knownLayersValue) || !IsLayerKnown(layer.inputs[3], knownLayersValue) || !IsLayerKnown(layer.inputs[4], knownLayersValue)) - return; - - var starts = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => x <= (float)int.MinValue ? int.MinValue : x >= (float)int.MaxValue ? int.MaxValue : (int)x); - var ends = Array.ConvertAll(knownLayersValue[layer.inputs[2]].ToReadOnlyArray(), x => x <= (float)int.MinValue ? int.MinValue : x >= (float)int.MaxValue ? int.MaxValue : (int)x); - - var strides = Enumerable.Repeat(1, starts.Length).Select(v => (int)v).ToArray(); - if (layer.inputs.Length >= 4) - strides = Array.ConvertAll(knownLayersValue[layer.inputs[3]].ToReadOnlyArray(), x => (int)x); - var axes = Enumerable.Range(0, starts.Length).Select(v => (int)v).ToArray(); - if (layer.inputs.Length == 5) - axes = Array.ConvertAll(knownLayersValue[layer.inputs[4]].ToReadOnlyArray(), x => (int)x); - - layer.pad = starts; - layer.pool = ends; - layer.stride = strides; - layer.axes = axes; - - layer.inputs = new[] { layer.inputs[0] }; - - return; - } - case Layer.Type.Squeeze: - { - if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - - int[] axes = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => (int)x); - - layer.pool = axes; - layer.inputs = new[] { layer.inputs[0] }; - return; - } - case Layer.Type.Unsqueeze: - { - if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - - int[] axes = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => (int)x); - - layer.pool = axes; - layer.inputs = new[] { layer.inputs[0] }; - return; - } - case Layer.Type.Pad: - { - if (layer.inputs.Length <= 1) - return; - if (layer.inputs.Length == 2 && !IsLayerKnown(layer.inputs[1], knownLayersValue)) - return; - if (layer.inputs.Length == 3 && !IsLayerKnown(layer.inputs[1], knownLayersValue) && !IsLayerKnown(layer.inputs[2], knownLayersValue)) - return; - - float value = (layer.inputs.Length == 2) ? layer.beta : knownLayersValue[layer.inputs[2]].ToReadOnlyArray()[0]; - int[] pads = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => (int)x); - - layer.beta = value; - layer.pad = pads; - layer.inputs = (layer.inputs.Length == 2) ? new [] { layer.inputs[0] } : new [] { layer.inputs[0], layer.inputs[1] }; - return; - } - default: - return; - } - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IRShapeInferenceAndConstantFusing.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IRShapeInferenceAndConstantFusing.cs.meta deleted file mode 100644 index b27e294..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IRShapeInferenceAndConstantFusing.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 03f82a59b77ab084ba54b5e0006f44e7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IValidateModelPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IValidateModelPass.cs deleted file mode 100644 index e20b459..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IValidateModelPass.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace Unity.Barracuda.Compiler.Passes -{ - interface IValidateModelPass - { - /// - /// Run a pass over the whole model - /// - /// Model to validate - void Run(Model model, ref List warnings); - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IValidateModelPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IValidateModelPass.cs.meta deleted file mode 100644 index 16b712e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IValidateModelPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 05c77109349b63249bc1e1ea7fa9ac3e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNCHWPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNCHWPass.cs deleted file mode 100644 index a2185d6..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNCHWPass.cs +++ /dev/null @@ -1,660 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Unity.Barracuda.Compiler.Passes -{ - class IntermediateToRunnableNCHWPass : IModelPass - { - readonly int[] k_ToNCHW = { 0, 3, 1, 2 }; - readonly int[] k_ToNHWC = { 0, 2, 3, 1 }; - readonly int[] k_FromNCHtoN1WC = { 0, 3, 2, 1 }; - readonly int[] k_FromN1WCtoNCH = { 0, 3, 2, 1 }; - - public void Run(ref Model model) - { - if (model.layout != "iNCHW") - return; - - IDictionary ranksByName; - IDictionary shapesByName; - IRShapeInferenceHelper.RankInference.ListTemporaryTensorRanks(model, out ranksByName); - var inputShapes = new Dictionary(); - foreach (var i in model.inputs) - { - if (!ModelAnalyzer.IsInputShapeAcceptablyKnowForShapeInference(i)) - continue; - inputShapes[i.name] = new TensorShape(i.shape); - } - - IRShapeInferenceHelper.ShapeInference.ListTemporaryTensorShapesNCHW(model, inputShapes, ref ranksByName, out shapesByName); - - var nchw = model.ShallowCopy(); - nchw.layers.Clear(); - nchw.layout = "NCHW"; - - var modelBuilder = new ModelBuilder(nchw); - - var rewriters = new Dictionary>(); - var layerRenames = new Dictionary(); - var inputRemaps = new Dictionary(); - - // return true if layer should be included in rewritten model, false if it was replaced - rewriters.Add(Layer.Type.Unsqueeze, (layer, net) => - { - if (layer.pool.Length > 1) - // Multiple axes unsupported; leave layer as-is - return true; - - string input0 = layer.inputs[0]; - - if (!shapesByName.TryGetValue(input0, out TensorShape? input0Shape) || !input0Shape.HasValue) - throw new Exception($"Must have input shape for {input0} for Unsqueeze"); - - if (!ranksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} for Unsqueeze"); - - int rank = input0Rank.Value; - - if (rank >= 4) - // Only 4D unsqueezes of rank 3 or less are supported - return true; - - int axis = layer.pool[0]; - if (axis < 0) - axis = rank + axis; - - int[] shape8D = input0Shape.Value.ToArray(); // 8D - List shape = new List(); - shape.Add(shape8D[TensorShape.DataBatch]); - if (rank > 1) - shape.Add(shape8D[TensorShape.H]); // C in NCHW - if (rank > 2) - shape.Add(shape8D[TensorShape.W]); // H in NCHW - shape.Insert(axis, 1); - shape.AddRange(Enumerable.Repeat(1, 4 - shape.Count)); - - net.Reshape(layer.name, input0, shape.ToArray()); - - return false; - }); - rewriters.Add(Layer.Type.Squeeze, (layer, net) => - { - if (layer.pool.Length > 1) - // Multiple axes unsupported; leave layer as-is - return true; - - string input0 = layer.inputs[0]; - - // Replace w/ a Transpose since Barracuda tensors are full rank - if (!ranksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} for Squeeze"); - - int rank = input0Rank.Value; - int axis = layer.pool[0]; - if (axis < 0) - axis = rank + axis; - - var transpose = SqueezeAxisPermutation(rank, axis); - net.Transpose(layer.name, input0, transpose); - - return false; - }); - rewriters.Add(Layer.Type.NonMaxSuppression, (layer, net) => - { - string boxes = layer.inputs[0]; - string scores = layer.inputs[1]; - - Layer boxesTransposed = net.Transpose($"Transpose_For_{boxes}", boxes, k_FromNCHtoN1WC); - Layer scoresTransposed = net.Transpose($"Transpose_For_{scores}", scores, k_FromNCHtoN1WC); - - // Most of the layer stays intact - string originalLayerName = layer.name; - layer.name = $"{layer.name}_NHWC"; - layer.inputs[0] = boxesTransposed.name; - layer.inputs[1] = scoresTransposed.name; - net.model.layers.Add(layer); - - net.Transpose(originalLayerName, layer.name, k_ToNCHW); - - return false; - }); - rewriters.Add(Layer.Type.Activation, (layer, net) => - { - return true; - }); - // Pad - rewriters.Add(Layer.Type.Border2D, TransposeInput0); - rewriters.Add(Layer.Type.Pad2DReflect, TransposeInput0); - rewriters.Add(Layer.Type.Pad2DEdge, TransposeInput0); - - rewriters.Add(Layer.Type.GlobalAvgPool2D, TransposeInput0); - rewriters.Add(Layer.Type.GlobalMaxPool2D, TransposeInput0); - - // Upsample - rewriters.Add(Layer.Type.Upsample2D, (layer, net) => - { - if (layer.inputs.Length > 1) - return TransposeInput01(layer, net); // Upsample usage - else - return TransposeInput0(layer, net); // Resize usage - }); - rewriters.Add(Layer.Type.Upsample3D, TransposeInput01); // Upsample usage - rewriters.Add(Layer.Type.AvgPool2D, TransposeInput0); // ModelBuilder: Resize2D - - // Resize: could be Resample2D, AvgPool2D, or Upsample2D - rewriters.Add(Layer.Type.Resample2D, TransposeInput0); - - // Gemm - rewriters.Add(Layer.Type.Dense, TransposeInput0); - rewriters.Add(Layer.Type.MatMul, TransposeInput01UsingRank); - - // Conv - rewriters.Add(Layer.Type.DepthwiseConv2D, Transpose0UsingRank); - rewriters.Add(Layer.Type.Conv2D, Transpose0UsingRank); - rewriters.Add(Layer.Type.Conv3D, Transpose0UsingRank); - rewriters.Add(Layer.Type.Conv2DTrans, Transpose0UsingRank); - - // BatchNormalization - rewriters.Add(Layer.Type.ScaleBias, Transpose0UsingRank); - - // InstanceNormalization - rewriters.Add(Layer.Type.Normalization, Transpose0UsingRank); - - // broadcastable ops - rewriters.Add(Layer.Type.Add, TransposeForBroadcast); - rewriters.Add(Layer.Type.Mul, TransposeForBroadcast); - rewriters.Add(Layer.Type.Sub, TransposeForBroadcast); - rewriters.Add(Layer.Type.Div, TransposeForBroadcast); - - - rewriters.Add(Layer.Type.StridedSlice, SliceToBarracuda); - rewriters.Add(Layer.Type.Gather, GatherToBarracuda); - rewriters.Add(Layer.Type.Concat, AxisToBarracuda); - rewriters.Add(Layer.Type.Tile, ShapeToBarracuda); - rewriters.Add(Layer.Type.Reshape, ShapeToBarracuda); - rewriters.Add(Layer.Type.Transpose, TransposeToBarracuda); - rewriters.Add(Layer.Type.Expand, (layer, net) => - { - string input0 = layer.inputs[0]; - Model.Input input0Info = net.model.inputs.First(i => i.name == layer.inputs[0]); - - var rank0 = input0Info.rank; - var size = layer.pool.ToList(); - - if (rank0 >= size.Count) - { - for (int i = 0; i < rank0 - size.Count; i++) - size.Insert(0, 1); - layer.pool = size.ToArray(); - return ShapeToBarracuda(layer, net); - } - - // inputShape needs to be unsqueezed - var transpose = RankChangePermutationBarracuda(rank0, size.Count); - Layer nchwTranspose = net.Transpose($"Transpose_{input0}_For_{layer.name}", input0, transpose); - - ShapeToBarracuda(layer, net); - - net.Expand(layer.name, nchwTranspose, layer.pool); - - return false; - }); - rewriters.Add(Layer.Type.OneHot, (layer, net) => - { - string input0 = layer.inputs[0]; - Model.Input input0Info = net.model.inputs.First(i => i.name == layer.inputs[0]); - - Layer input0Transposed = net.Transpose($"Transpose_For_{input0}", input0, k_ToNHWC); - - // Most of the layer stays intact - string originalLayerName = layer.name; - layer.name = $"{layer.name}_NHWC"; - layer.inputs[0] = input0Transposed.name; - layer.axis = input0Info.rank; - net.model.layers.Add(layer); - - // OneHot outputRank = inputRank + 1 - net.Transpose(originalLayerName, layer.name, input0Info.rank == 2 ? k_FromN1WCtoNCH : k_ToNCHW); - - return false; - }); - - // Reduce - rewriters.Add(Layer.Type.ReduceL1, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceL2, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceMax, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceMean, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceMin, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceProd, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceSum, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceLogSum, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceSumSquare, AxisToBarracuda); - rewriters.Add(Layer.Type.ReduceLogSumExp, AxisToBarracuda); - - foreach (var l in model.layers) - { - if (!rewriters.TryGetValue(l.type, out Func rw) || rw(l, modelBuilder)) - { - nchw.layers.Add(l); - } - } - - model = nchw; - } - - bool AxisToBarracuda(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - Model.Input input0Info = net.model.inputs.First(i => i.name == layer.inputs[0]); - - var onnxRank = input0Info.rank; - if (layer.axis < 0) - layer.axis += onnxRank; - - switch (onnxRank) - { - case 6: - layer.axis += 2; - break; - case 5: - layer.axis = layer.axis + (layer.axis == 0 ? 2 : 3); - break; - default: - layer.axis = layer.axis + (layer.axis == 0 ? 2 : 4); - break; - } - - return true; - } - - bool GatherToBarracuda(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - Model.Input input0Info = net.model.inputs.First(i => i.name == layer.inputs[0]); - - string input1 = layer.inputs[1]; - Model.Input input1Info = net.model.inputs.First(i => i.name == layer.inputs[1]); - - layer.pool = new[] { input0Info.rank, input1Info.rank }; - - return AxisToBarracuda(layer, net); - } - - bool TransposeToBarracuda(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - Model.Input input0Info = net.model.inputs.First(i => i.name == layer.inputs[0]); - - var onnxTranspose = layer.pool; - - var rank = input0Info.rank; - switch (rank) - { - case 2: - { - // onnx : 5,7 => 5,7,1,1 / 7,5 - layer.pool = new[] { layer.pool[0], layer.pool[1], 2, 3 }; - return true; - } - case 3: - { - // onnx : 5,7,3 => 5,7,3,1 / 7,5,3,1 / 7,3,5,1 ... - layer.pool = new[] { layer.pool[0], layer.pool[1], layer.pool[2], 3 }; - return true; - } - case 4: - { - return true; - } - default: - throw new ArgumentException($"Unsupported transpose"); - } - } - - bool ShapeToBarracuda(Layer layer, ModelBuilder net) - { - var size = layer.pool; - - // Don't use Tensorshape as this can remove a wild card - const int _ = 1; - if (size.Length == 1) - layer.pool = new[] { _, _, size[0], _, _, 1, 1, 1 }; // [1,1,N,1,1,1,1,1] - else if (size.Length == 2) - layer.pool = new[] { _, _, size[0], _, _, size[1], 1, 1 }; // [1,1,N,1,C,1,1,1] - else if (size.Length == 3) - layer.pool = new[] { _, _, size[0], _, _, size[1], size[2], 1 }; // [1,1,N,1,1,C,W,1] - else if (size.Length == 4) - layer.pool = new[] { _, _, size[0], _, _, size[1], size[2], size[3] }; // [1,1,N,1,1,C,H,W] - else if (size.Length == 5) - layer.pool = new[] { _, _, size[0], _, size[1], size[2], size[3], size[4] }; // [1,1,N,1,D,H,W,C] - else if (size.Length == 6) - layer.pool = new[] { _, _, size[0], size[1], size[2], size[3], size[4], size[5] }; // [1,1,N,T,D,H,W,C] - else - layer.pool = new[] { size[0], size[1], size[2], size[3], size[4], size[5], size[6], size[7] }; // [S,R,N,T,D,H,W,C] - - return true; - } - - static int[] SqueezeAxisPermutation(int rank, int axis) - { - var identity = new[] { 0, 1, 2, 3 }; - - if (rank == 5) - { - // axis: 0 1 2 3 4 - // ONNX: NCDHW CDHW NDHW NCHW NCDW NCDH - // { 0,1,2,3,4,5,6,7} - // _,_,N,_,C,D,H,W - if (axis == 0) - return new[] { 0, 1, 4, 3, 5, 6, 7, 2 }; - if (axis == 1) - return new[] { 0, 1, 2, 3, 5, 6, 7, 4 }; - if (axis == 2) - return new[] { 0, 1, 2, 3, 4, 6, 7, 5 }; - if (axis == 3) - return new[] { 0, 1, 2, 3, 4, 5, 7, 6 }; - - return new[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - } - if (rank == 4) - { - // axis: 0 1 2 3 - // ONNX: NCHW CHW NHW NCW NCH - if (axis == 0) - return new[] { 1, 2, 3, 0 }; - if (axis == 1) - return new[] { 0, 2, 3, 1 }; - if (axis == 2) - return new[] { 0, 1, 3, 2 }; - - return identity; - } - if (rank == 3) - { - // axis: 0 1 2 - // ONNX: NCH CH NH NC - if (axis == 0) - return new[] { 1, 2, 0, 3 }; - if (axis == 1) - return new[] { 0, 2, 1, 3 }; - - return identity; - } - if (rank == 2) - { - // axis: 0 1 - // ONNX: NC C N - if (axis == 0) - return new[] { 1, 0, 2, 3 }; - - return identity; - } - if (rank == 1) - return identity; - - throw new InvalidOperationException($"Not supported Squeeze operation with rank {rank}"); - } - - bool SliceToBarracuda(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - Model.Input input0Info = net.model.inputs.First(i => i.name == layer.inputs[0]); - int rank = input0Info.rank; - - var starts = layer.pad; - var ends = layer.pool; - var steps = layer.stride; - var axes = layer.axes; - - var onnxStarts = Enumerable.Repeat(0, rank).ToArray(); - var onnxEnds = Enumerable.Repeat(int.MaxValue, rank).ToArray(); // by default copy the whole axis till the end - var onnxSteps = Enumerable.Repeat(1, rank).ToArray(); - - // NOTE: begin=0, end=0, stride=1 <= full range from existing axis - // begin=0, end=inf,stride=1 <= full range from existing axis - // begin=0, end=X, stride=1 <= full range from existing axis, if X==last element on this axis - // begin=0, end=0, stride=0 <= new axis OR shrink axis to single 1st element - // begin=N, end=N, stride=0 <= shrink axis to single Nth element - // These notes are copied from TensorExtensions.ApplyStridedSlice(...) - - for (int i = 0; i < axes.Length; ++i) - { - var axis = axes[i]; - if (axis < 0) - axis += rank; - axis = Math.Min(Math.Max(axis, 0), rank); - - onnxStarts[axis] = starts[i]; - onnxEnds[axis] = ends[i]; - onnxSteps[axis] = steps[i]; - } - - switch (rank) - { - case 1: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, 0, 0, 0 }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, 1, 1, 1 }; - break; - case 2: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, onnxStarts[1], 0, 0 }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, onnxEnds[1], int.MaxValue, int.MaxValue }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, onnxSteps[1], 1, 1 }; - break; - case 3: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, onnxStarts[1], onnxStarts[2], 0 }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, onnxEnds[1], onnxEnds[2], int.MaxValue }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, onnxSteps[1], onnxSteps[2], 1 }; - break; - case 4: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, onnxStarts[1], onnxStarts[2], onnxStarts[3] }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, onnxEnds[1], onnxEnds[2], onnxEnds[3] }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, onnxSteps[1], onnxSteps[2], onnxSteps[3] }; - break; - default: - throw new ArgumentException($"Unsupported tensor rank {rank} for StridedSlice"); - } - - return true; - } - - bool Transpose0UsingRank(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - Model.Input input0Info = net.model.inputs.First(i => i.name == layer.inputs[0]); - - Layer input0Transposed = net.Transpose($"Transpose_For_{input0}", input0, input0Info.rank == 3 ? k_FromNCHtoN1WC : k_ToNHWC); - - // Most of the layer stays intact - string originalLayerName = layer.name; - layer.name = $"{layer.name}_NHWC"; - layer.inputs[0] = input0Transposed.name; - net.model.layers.Add(layer); - - net.Transpose(originalLayerName, layer.name, input0Info.rank == 3 ? k_FromN1WCtoNCH : k_ToNCHW); - - return false; - } - bool TransposeInput01UsingRank(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - Model.Input input0Info = net.model.inputs.First(i => i.name == layer.inputs[0]); - - string input1 = layer.inputs[1]; - Model.Input input1Info = net.model.inputs.First(i => i.name == layer.inputs[1]); - - Layer input0Transposed = net.Transpose($"Transpose_For_{input0}", input0, input0Info.rank == 3 ? k_FromNCHtoN1WC : k_ToNHWC); - Layer input1Transposed = net.Transpose($"Transpose_For_{input1}", input1, input1Info.rank == 3 ? k_FromNCHtoN1WC : k_ToNHWC); - - string originalLayerName = layer.name; - layer.name = $"{layer.name}_NHWC"; - layer.inputs[0] = input0Transposed.name; - layer.inputs[1] = input1Transposed.name; - net.model.layers.Add(layer); - - net.Transpose(originalLayerName, layer.name, input0Info.rank == 3 ? k_FromN1WCtoNCH : k_ToNCHW); - - return false; - } - - bool TransposeForBroadcast(Layer layer, ModelBuilder net) - { - int maxRankI = 0; - for(int i = 0; i < layer.inputs.Length; i++) - { - Model.Input inputInfo = net.model.inputs.First(x => x.name == layer.inputs[i]); - maxRankI = Math.Max(maxRankI, inputInfo.rank); - } - - List insertedTranspose = new List(); - for (int i = 0; i < layer.inputs.Length; i++) - { - string input = layer.inputs[i]; - Model.Input inputInfo = net.model.inputs.First(x => x.name == layer.inputs[i]); - int inputRank = inputInfo.rank; - - var transpose = GetTransposeForBroadCast(inputRank, maxRankI); - Layer inputTransposed = net.Transpose($"Transpose_For_{input}", input, transpose); - insertedTranspose.Add(inputTransposed); - } - - string originalLayerName = layer.name; - layer.name = $"{layer.name}_NHWC"; - for (int i = 0; i < layer.inputs.Length; i++) - { - layer.inputs[i] = insertedTranspose[i].name; - - } - net.model.layers.Add(layer); - - net.Transpose(originalLayerName, layer.name, new [] { 0, 1, 2, 3 }); - - return false; - } - - int[] GetTransposeForBroadCast(int rank0, int rank1) - { - if (rank0 == rank1) - return new[] { 0, 1, 2, 3 }; - - if (rank1 == 0 || rank1 == 1) - return new[] { 0, 1, 2, 3 }; - if (rank1 == 2) - { - // 3 + 53 => 1,3 - if (rank0 == 0 || rank0 == 1) - return new[] { 1, 0, 2, 3 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else if (rank1 == 3) - { - // 3 + 753 => 1,1,3 - if (rank0 == 0 || rank0 == 1) - return new[] { 1, 2, 0, 3 }; - // 53 + 753 => 1,5,3 - else if (rank0 == 2) - return new[] { 2, 0, 1, 3 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else if (rank1 == 4) - { - // 3 + 9753 => 1,1,1,3 - if (rank0 == 0 || rank0 == 1) - return new[] { 1, 2, 3, 0 }; - // 53 + 9753 => 1,1,5,3 - else if (rank0 == 2) - return new[] { 2, 3, 0, 1 }; - // 753 + 9753 => 1,1,5,3 - else if (rank0 == 3) - return new[] { 3, 0, 1, 2 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - - bool TransposeInput01(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - string input1 = layer.inputs[1]; - - Layer input0Transposed = net.Transpose($"Transpose_For_{input0}", input0, k_ToNHWC); - Layer input1Transposed = net.Transpose($"Transpose_For_{input1}", input1, k_ToNHWC); - string originalLayerName = layer.name; - layer.name = $"{layer.name}_NHWC"; - layer.inputs[0] = input0Transposed.name; - layer.inputs[1] = input1Transposed.name; - net.model.layers.Add(layer); - - net.Transpose(originalLayerName, layer.name, k_ToNCHW); - - return false; - } - - bool TransposeInput0(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - - Layer input0Transposed = net.Transpose($"Transpose_For_{input0}", input0, k_ToNHWC); - string originalLayerName = layer.name; - layer.name = $"{layer.name}_NHWC"; - layer.inputs[0] = input0Transposed.name; - net.model.layers.Add(layer); - - net.Transpose(originalLayerName, layer.name, k_ToNCHW); - - return false; - } - - private static int[] RankChangePermutationBarracuda(int rank0, int rank1) - { - var identity = new[] { 0, 1, 2, 3 }; - if (rank0 == 0) - return identity; - else if (rank0 == 1) - { - // ONNX: - // 8 -> 1,8 - // 8 -> 1,1,8 - // 8 -> 1,1,1,8 - if (rank1 == 0 || rank1 == 1) - return identity; - else if (rank1 == 2) - return new[] { 1, 0, 2, 3 }; - else if (rank1 == 3) - return new[] { 1, 2, 0, 3 }; - else if (rank1 == 4) - return new[] { 1, 2, 3, 0 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else if (rank0 == 2) - { - // ONNX: - // 28 -> 1,2,8 - // 28 -> 1,1,2,8 - if (rank1 == 3) - return new[] { 2, 0, 1, 3 }; - else if (rank1 == 4) - return new[] { 2, 3, 0, 1 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else if (rank0 == 3) - { - // ONNX: - // 5,2,8 -> 1,5,2,8 - if (rank1 == 4) - return new[] { 3, 0, 1, 2 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNCHWPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNCHWPass.cs.meta deleted file mode 100644 index d9631a3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNCHWPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8384be851ddf23b4590eb033de15c828 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNHWCPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNHWCPass.cs deleted file mode 100644 index c34697b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNHWCPass.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Unity.Barracuda.Compiler.Passes -{ - class IntermediateToRunnableNHWCPass : IModelPass - { - public bool Optimize { get; set; } = false; - - public void Run(ref Model model) - { - var warnings = new List(); - var shapeInferencePass = new IRShapeInferenceAndConstantFusing(); - shapeInferencePass.Run(ref model, warnings); - - if (Optimize) - { - // Optimization - var linearLayerFusingPass = new Optimization.FuseLinearLayersPass(); - linearLayerFusingPass.Run(ref model); - var activationFusingPass = new Optimization.FuseActivationPass(); - activationFusingPass.Run(ref model); - - // Cleanup - var removeUnusedPass = new Cleanup.RemoveUnusedLayersPass(); - removeUnusedPass.Run(ref model); - var removeNoOpPass = new Cleanup.RemoveNoOpsPass(); - removeNoOpPass.Run(ref model); - } - - // TODO, put asserts in ImporterWarning? - var validateNCHWPass = new ValidateNCHWPass(); - validateNCHWPass.Run(model, ref warnings); - - // to runnable NHWC - var nhwcPass = new NCHWToNHWCPass(); - nhwcPass.Run(ref model); - - // optimizations - if (Optimize) - { - var contractToSimplerLayerPass = new Optimization.ContractToSimplerLayerPass(); - contractToSimplerLayerPass.Run(ref model); - - var concatenateTransposesPass = new Optimization.ConcatenateTransposesPass(); - concatenateTransposesPass.Run(ref model); - - var dense3FusingPass = new Optimization.FuseDense3Pass(); - dense3FusingPass.Run(ref model); - } - - var validateNHWCPass = new ValidateNHWCPass(); - validateNHWCPass.Run(model, ref warnings); - - model.Warnings.AddRange(warnings); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNHWCPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNHWCPass.cs.meta deleted file mode 100644 index 0880f39..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/IntermediateToRunnableNHWCPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1aa1e7bc4236198449f487337e83ea15 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/LayoutTransposesRemovalHelper.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/LayoutTransposesRemovalHelper.cs deleted file mode 100644 index a5779e4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/LayoutTransposesRemovalHelper.cs +++ /dev/null @@ -1,258 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes -{ - class LayoutTransposeRemovalHelper - { - List nhwcImporters = new List { "tf2onnx", "keras2onnx" }; - public bool IsImporterLikelyNHWCLayout(string importer) { return nhwcImporters.Exists(x => importer.Contains(x)); } - private bool IsLayerNecessarilyNCHWOnnx(Layer layer) - { - return layer.type == Layer.Type.Conv2D || - layer.type == Layer.Type.Conv3D || - layer.type == Layer.Type.Conv2DTrans || - layer.type == Layer.Type.Conv3DTrans || - layer.type == Layer.Type.DepthwiseConv2D || - layer.type == Layer.Type.DepthToSpace || - layer.type == Layer.Type.SpaceToDepth; - } - - private static bool IsLayerTranpose(Layer layer) { return layer.type == Layer.Type.Transpose; } - private static bool IsLayerReshape(Layer layer) { return layer.type == Layer.Type.Reshape; } - private static bool IsLayerSqueeze(Layer layer) { return layer.type == Layer.Type.Squeeze; } - private static bool IsLayerFlatten(Layer layer) { return layer.type == Layer.Type.Flatten; } - private static bool IsLayerConst(Layer layer) { return layer.type == Layer.Type.Load; } - private static bool IsLayerRandom(Layer layer) { return layer.type == Layer.Type.RandomNormal || layer.type == Layer.Type.RandomUniform; } - private static bool IsReshapeTransposeToNCHW(Layer layer, TensorShape inputShape) - { - if (layer.inputs.Length > 1) - return false; - var newShape = layer.pool; - if (newShape.Length != 4) - return false; - if ((newShape[0] != inputShape.batch) && (newShape[0] != -1) && (newShape[0] != 0)) - return false; - if (newShape[1] == inputShape.channels && newShape[2] == inputShape.height && newShape[3] == inputShape.width) - return true; - return false; - } - private static bool IsReshapeTransposeToNHWC(Layer layer, TensorShape inputShape) - { - // TODO take onnx shape - if (layer.inputs.Length > 1) - return false; - var newShape = layer.pool; - if (newShape.Length != 4) - return false; - if ((newShape[0] != inputShape.batch) && (newShape[0] != -1) && (newShape[0] != 0)) - return false; - if (newShape[3] == inputShape.height && newShape[1] == inputShape.width && newShape[2] == inputShape.channels) - return true; - return false; - } - private bool IsSqueezeTransposeToNHWC(Layer layer, int inputRank) - { - var squeezedRank = IRShapeInferenceHelper.RankInference.InferOutputRank(layer, new int?[] { inputRank }, new TensorShape?[] { null }); - return (inputRank == 4) && (squeezedRank <= 2); - } - - private bool IsLayerChangingLayoutToNHWC(Layer layer, IDictionary shapesByName, IDictionary ranksByName) - { - return (IsLayerTranpose(layer) && Enumerable.SequenceEqual(layer.pool, new[] { 0, 2, 3, 1 })) || - (IsLayerReshape(layer) && (shapesByName[layer.inputs[0]] != null) && IsReshapeTransposeToNHWC(layer, shapesByName[layer.inputs[0]].Value)) || - (IsLayerSqueeze(layer) && (ranksByName[layer.inputs[0]] != null) && IsSqueezeTransposeToNHWC(layer, ranksByName[layer.inputs[0]].Value)); - } - - private bool IsLayerChangingLayoutToNCHW(Layer layer, IDictionary shapesByName, IDictionary ranksByName) - { - return (IsLayerTranpose(layer) && Enumerable.SequenceEqual(layer.pool, new[] { 0, 3, 1, 2 })) || - (IsLayerReshape(layer) && (shapesByName[layer.inputs[0]] != null) && IsReshapeTransposeToNCHW(layer, shapesByName[layer.inputs[0]].Value)); - } - - public enum ChannelsOrder - { - NHWC, - NCHW, - TransposeToNHWC, - TransposeToNCHW, - // used only in InferAllLayersChannelOrder - NativeNCHW - } - - private enum FlowDirection - { - Seed, - Downstream, - Upstream - } - - // works on IRModel - public bool InferAllLayersChannelOrder(Model model, out Dictionary layerChannelOrder) - { - layerChannelOrder = new Dictionary(); - - IDictionary shapesByName = new Dictionary(); - IDictionary ranksByName = new Dictionary(); - foreach (var i in model.inputs) - { - ranksByName[i.name] = i.rank; - if (!ModelAnalyzer.IsInputShapeAcceptablyKnowForShapeInference(i)) - continue; - shapesByName[i.name] = new TensorShape(i.shape); - } - - IRShapeInferenceAndConstantFusing shapeInferencePass = new IRShapeInferenceAndConstantFusing(); - shapeInferencePass.InferAllShapes(model, ref shapesByName, ref ranksByName); - - // flood-fill approach: NCHW layout is propagated from NCHW ops - // * onnx-nchw ops are flagged as being native nchw - // * nchw layout is propagated to upstream and downstream nodes - // foreach node: - // take layout being propagated to - // if T or T-1 flip layout depending on upstream/downstream direction - // - stop if layout is the same as previously propagated - // - native nchw layout has priority - Queue<(string, ChannelsOrder, FlowDirection)> layersToInferLayout = new Queue<(string, ChannelsOrder, FlowDirection)>(); - for (int l = 0; l < model.layers.Count; l++) - { - var layer = model.layers[l]; - if (!IsLayerNecessarilyNCHWOnnx(layer)) - continue; - - layersToInferLayout.Enqueue((layer.name, ChannelsOrder.NativeNCHW, FlowDirection.Seed)); - } - - while (layersToInferLayout.Any()) - { - (string, ChannelsOrder, FlowDirection) layerData = layersToInferLayout.Dequeue(); - string name = layerData.Item1; - ChannelsOrder deducedChannelOrder = layerData.Item2; - // 0: in-place native - // 1: downstream - // 2: upstream - FlowDirection flowDirection = layerData.Item3; - - - if (!layerChannelOrder.ContainsKey(name)) - layerChannelOrder[name] = deducedChannelOrder; - else if (deducedChannelOrder == layerChannelOrder[name]) - continue; - else if (layerChannelOrder[name] == ChannelsOrder.NativeNCHW) - continue; - // heuristic to stop ping-pong loop, prioritize NHWC over NCHW as it implies less transposes - // if incoming is NativeNCHW always propagate that - // TODO: count # of transpose swaps - else if (layerChannelOrder[name] == ChannelsOrder.NHWC && deducedChannelOrder != ChannelsOrder.NativeNCHW) - continue; - - Layer layer; - bool found = ModelAnalyzer.FindLayerByName(model, name, out layer); - if (IsLayerChangingLayoutToNHWC(layer, shapesByName, ranksByName)) - { - // NCHW -> T -> NHWC - if (((deducedChannelOrder == ChannelsOrder.NCHW) || (deducedChannelOrder == ChannelsOrder.NativeNCHW)) && (flowDirection == FlowDirection.Downstream)) - deducedChannelOrder = ChannelsOrder.TransposeToNHWC; - // NCHW <- T <- NHWC - else if ((deducedChannelOrder == ChannelsOrder.NHWC) && (flowDirection == FlowDirection.Upstream)) - deducedChannelOrder = ChannelsOrder.TransposeToNHWC; - } - else if (IsLayerChangingLayoutToNCHW(layer, shapesByName, ranksByName)) - { - // NHWC -> T-1 -> NCHW - if ((deducedChannelOrder == ChannelsOrder.NHWC) && (flowDirection == FlowDirection.Downstream)) - deducedChannelOrder = ChannelsOrder.TransposeToNCHW; - // NHWC <- T-1 <- NCHW - else if (((deducedChannelOrder == ChannelsOrder.NCHW) || (deducedChannelOrder == ChannelsOrder.NativeNCHW)) && (flowDirection == FlowDirection.Upstream)) - deducedChannelOrder = ChannelsOrder.TransposeToNCHW; - } - - if ((deducedChannelOrder == ChannelsOrder.TransposeToNCHW || deducedChannelOrder == ChannelsOrder.TransposeToNHWC) && (deducedChannelOrder == layerChannelOrder[name])) - continue; - - layerChannelOrder[name] = deducedChannelOrder; - - foreach (var input in layer.inputs) - { - if(deducedChannelOrder == ChannelsOrder.TransposeToNCHW) - layersToInferLayout.Enqueue((input, ChannelsOrder.NHWC, FlowDirection.Upstream)); - else if(deducedChannelOrder == ChannelsOrder.TransposeToNHWC) - layersToInferLayout.Enqueue((input, ChannelsOrder.NCHW, FlowDirection.Upstream)); - else - layersToInferLayout.Enqueue((input, deducedChannelOrder, FlowDirection.Upstream)); - } - - var outputs = ModelAnalyzer.FindLayerOutputs(model, layer.name); - foreach (var output in outputs) - { - if (deducedChannelOrder == ChannelsOrder.TransposeToNCHW) - layersToInferLayout.Enqueue((output, ChannelsOrder.NCHW, FlowDirection.Downstream)); - else if (deducedChannelOrder == ChannelsOrder.TransposeToNHWC) - layersToInferLayout.Enqueue((output, ChannelsOrder.NHWC, FlowDirection.Downstream)); - else - layersToInferLayout.Enqueue((output, deducedChannelOrder, FlowDirection.Downstream)); - } - } - - bool modelExportedASNHWC = false; - foreach (string key in layerChannelOrder.Keys.ToList()) - { - var value = layerChannelOrder[key]; - if (value == ChannelsOrder.NativeNCHW) - layerChannelOrder[key] = ChannelsOrder.NCHW; - - if (value == ChannelsOrder.NHWC) - modelExportedASNHWC = true; - } - - return modelExportedASNHWC; - } - - public void RemoveAllChannelLayoutTransposes(ref Model model, Dictionary layerChannelOrder) - { - // TODO transpose inputs? here - Dictionary transposesToRemove = new Dictionary(); - - for (int l = 0; l < model.layers.Count; l++) - { - var layer = model.layers[l]; - - if (!layerChannelOrder.ContainsKey(layer.name)) - continue; - - if (!((layerChannelOrder[layer.name] == ChannelsOrder.TransposeToNCHW) || (layerChannelOrder[layer.name] == ChannelsOrder.TransposeToNHWC))) - continue; - - // find all layers that have layer has input - // if transpose is output, replace it with a noop - if (model.outputs.Contains(layer.name)) - { - string[] inputs = layer.inputs; - layer = new Layer(layer.name, Layer.Activation.None); - layer.inputs = inputs; - model.layers[l] = layer; - - continue; - } - // add it - transposesToRemove[layer.name] = layer; - } - - for (int l = 0; l < model.layers.Count; l++) - { - var layer = model.layers[l]; - for(int i = 0; i < layer.inputs.Length; i++) - { - var input = layer.inputs[i]; - if (transposesToRemove.TryGetValue(input, out Layer transpose)) - layer.inputs[i] = transpose.inputs[0]; - } - } - - model.layers = model.layers.Except(transposesToRemove.Values).ToList(); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/LayoutTransposesRemovalHelper.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/LayoutTransposesRemovalHelper.cs.meta deleted file mode 100644 index 1694a4f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/LayoutTransposesRemovalHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8b73e9089343fdd4d97083b0cf749878 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC.meta deleted file mode 100644 index 5a4e8d4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 8c0d64bb9d0e37e4fb54d7cf626f6ba0 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectForBroadcast.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectForBroadcast.cs deleted file mode 100644 index 52e3bee..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectForBroadcast.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Unity.Barracuda.Compiler.Passes -{ - partial class NCHWToNHWCPass - { - int[] GetPermutationForBroadcast(int targetRank, int rank, bool isNHWC = false) - { - int[] permutations = new[] { 0, 1, 2, 3 }; - - if (rank == 0 || targetRank == 1) - return permutations; - - switch (targetRank) - { - case 2: - // ONNX: 5,7 + 7 - // Barracuda: 5,_,_,7 + 7,_,_,- => _,_,_,7 - permutations = new[] { 1, 2, 3, 0 }; - break; - case 3: - // ONNX: 5,7,3 + 3 - // Barracuda: 5,_,3,7 + 3,_,_,_ => _,_,3,_ - if (rank == 1) - permutations = new[] { 1, 2, 0, 3 }; - - // ONNX: 5,7,3 + 7,3 - // Barracuda: 5,_,3,7 + 7,_,_,3 => _,_,3,7 - else if (rank == 2) - permutations = new[] { 1, 2, 3, 0 }; - - break; - case 4: - // ONNX: 2,5,7,3 + 3 - // Barracuda: 2,7,3,5 + 3,_,_,_ => _,_,3,_ - if (rank == 1) - permutations = new[] { 1, 2, 0, 3 }; - - // ONNX: 2,5,7,3 + 7,3 - // Barracuda: 2,7,3,5 + 7,_,_,3 => _,7,3,_ - else if (rank == 2) - permutations = new[] { 1, 0, 3, 2 }; - - // ONNX: 2,5,7,3 + 5,7,3 - // Barracuda: 2,7,3,5 + 5,_,3,7 => _,7,3,5 - else if (rank == 3) - permutations = new[] { 1, 3, 2, 0 }; - break; - } - - if (isNHWC) - { - switch (targetRank) - { - case 2: - // ONNX: 5,7 + 7 - // Barracuda: 5,_,_,7 + 7,_,_,- => _,_,_,7 - permutations = new[] { 1, 2, 3, 0 }; - break; - case 3: - // ONNX: 5,7,3 + 3 - // Barracuda: 5,_,7,3 + 3,_,_,_ => _,_,_,3 - if (rank == 1) - permutations = new[] { 1, 2, 3, 0 }; - - // ONNX: 5,7,3 + 7,3 - // Barracuda: 5,_,7,3 + 7,_,_,3 => _,_,7,3 - else if (rank == 2) - permutations = new[] { 1, 2, 0, 3 }; - - break; - case 4: - // ONNX: 2,5,7,3 + 3 - // Barracuda: 2,5,7,3 + 3,_,_,_ => _,_,_,3 - if (rank == 1) - permutations = new[] { 1, 2, 3, 0 }; - - // ONNX: 2,5,7,3 + 7,3 - // Barracuda: 2,5,7,3 + 7,_,_,3 => _,_,7,3, - else if (rank == 2) - permutations = new[] { 1, 2, 0, 3 }; - - // ONNX: 2,5,7,3 + 5,7,3 - // Barracuda: 2,5,7,3 + 5,_,7,3 => _,5,7,3 - else if (rank == 3) - permutations = new[] { 1, 0, 2, 3 }; - break; - } - } - return permutations; - } - - void CorrectConstantsForBroadCast(ref Model nhwc) - { - List correctedConstants = new List(); - for (int l = 0; l < nhwc.layers.Count; l++) - { - Layer layer = nhwc.layers[l]; - for (int i = 0; i < layer.inputs.Length; i++) - { - var input = layer.inputs[i]; - - if (!ModelAnalyzer.IsLayerBroacastable(layer)) - continue; - - if (!m_RanksByName.ContainsKey(input) || !m_RanksByName.ContainsKey(layer.name)) - continue; - - Layer inputLayer; - bool found = ModelAnalyzer.FindLayerByName(nhwc, input, out inputLayer); - if (!found) - continue; - - if (!ModelOptimizer.IsLayerConstant(inputLayer)) - continue; - - if (m_RanksByName[input] < 1 || m_RanksByName[input] == m_RanksByName[layer.name]) - continue; - if (inputLayer.weights.Length == 1) - continue; - - if (m_RanksByName[input] > m_RanksByName[layer.name]) - throw new Exception($"constant must be lower rank than input for broadcast to work, TODO add transpose before input"); - - Layer correctedConstLayer = new Layer("c_" + inputLayer.name + "For_" + layer.name, Layer.Type.Load); - - // transpose dataset - correctedConstLayer.datasets = new Layer.DataSet[1]; - Array.Copy(inputLayer.datasets, correctedConstLayer.datasets, inputLayer.datasets.Length); - correctedConstLayer.datasets[0].name = correctedConstLayer.name; - - - correctedConstLayer.weights = new BarracudaArray(inputLayer.weights.Length); - - var X = inputLayer.DataSetToTensor(0); - - var rank = m_RanksByName[layer.name].Value; - - var inputRank = m_RanksByName[input].Value; - int[] permutations = GetPermutationForBroadcast(rank, inputRank, (m_isModelExportedFromNHWC && (m_layersChannelOrder[layer.name] == LayoutTransposeRemovalHelper.ChannelsOrder.NHWC))); - - var O = m_Ops.Transpose(X, permutations); - correctedConstLayer.ApplyTensorToDataSet(O, 0); - O.Dispose(); - X.Dispose(); - - correctedConstants.Add(correctedConstLayer); - layer.inputs[i] = correctedConstLayer.name; - } - - nhwc.layers[l] = layer; - } - - foreach (var l in correctedConstants) - { - nhwc.layers.Insert(0, l); - } - } - - void CorrectDynamicInputsForBroadCast(ref Model nhwc) - { - // for dynamic shape layers, we cannot insert transpose as we are generating correct output - Dictionary broadcastSkippableLayers = new Dictionary(); - for (int l = 0; l < nhwc.layers.Count; l++) - { - Layer layer = nhwc.layers[l]; - if (ModelAnalyzer.IsLayerBroadcastSkippable(layer)) - broadcastSkippableLayers.Add(layer.name, true); - } - - // insert transposes before broadcastalbe ops - for (int l = 0; l < nhwc.layers.Count; l++) - { - Layer layer = nhwc.layers[l]; - if (!ModelAnalyzer.IsLayerBroacastable(layer)) - continue; - - if (!m_RanksByName.ContainsKey(layer.name) || m_RanksByName[layer.name] == null) - continue; - - int maxRank = m_RanksByName[layer.name].Value; - if (maxRank <= 1) - continue; - - for (int i = 0; i < layer.inputs.Length; i++) - { - string input = layer.inputs[i]; - - if (!m_RanksByName.ContainsKey(input) || m_RanksByName[input] == null) - continue; - - int inputRank = m_RanksByName[input].Value; - - if (inputRank < 1 || inputRank == maxRank) - continue; - - if (broadcastSkippableLayers.ContainsKey(input) && broadcastSkippableLayers[input]) - continue; - - int[] permutations = GetPermutationForBroadcast(maxRank, inputRank, (m_isModelExportedFromNHWC && (m_layersChannelOrder[layer.name] == LayoutTransposeRemovalHelper.ChannelsOrder.NHWC))); - - Layer transpose = new Layer("transpose_forbroadcast_" + layer.name + "_" + input, Layer.Type.Transpose); - transpose.inputs = new[] { input }; - transpose.pool = permutations; - - nhwc.layers[l].inputs[i] = transpose.name; - nhwc.layers.Insert(l, transpose); - l += 1; - } - } - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectForBroadcast.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectForBroadcast.cs.meta deleted file mode 100644 index 63434db..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectForBroadcast.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7f52b4cb811d034408787a68666a39ac -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectOutputLayoutToMatchNHWCLayout.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectOutputLayoutToMatchNHWCLayout.cs deleted file mode 100644 index 3a43e8a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectOutputLayoutToMatchNHWCLayout.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using System.Linq; - -namespace Unity.Barracuda.Compiler.Passes -{ - partial class NCHWToNHWCPass - { - void CorrectOutputLayoutToMatchNHWCLayout(ref Model nhwc) - { - var inputShapesNHWC = new Dictionary(); - foreach (var i in nhwc.inputs) - { - inputShapesNHWC.Add(i.name, new TensorShape(i.shape)); - } - - IDictionary shapesByNameNHWC; - ModelAnalyzer.ListTemporaryTensorShapes(nhwc, inputShapesNHWC, out shapesByNameNHWC); - - foreach (var o in nhwc.outputs) - { - if (!(shapesByNameNHWC.ContainsKey(o) && shapesByNameNHWC[o] != null)) - continue; - if (!(m_ShapesByName.ContainsKey(o) && m_ShapesByName[o] != null)) - continue; - - var outputShapeNHWC = shapesByNameNHWC[o].Value; - var outputShapeNHWCList = new List { outputShapeNHWC.sequenceLength, outputShapeNHWC.numberOfDirections, outputShapeNHWC.batch, outputShapeNHWC.extraDimension, outputShapeNHWC.depth, outputShapeNHWC.height, outputShapeNHWC.width, outputShapeNHWC.channels }; - // check that outputShapeNHWC matches the NCHW shape - var outputShape = m_ShapesByName[o].Value; - var outputShapeONNX = IRShapeInferenceHelper.ShapeInference.ShapeToOnnxLayout(outputShape, m_RanksByName[o].Value).ToArray(); - var outputShapeList = IRShapeInferenceHelper.ShapeInference.BarracudaLayoutToTensorShapeLayout(outputShapeONNX).ToList(); - - if (outputShapeNHWCList.SequenceEqual(outputShapeList)) - continue; - - var permutations = new List(); - for (int i = 0; i < 8; i++) - { - for (int j = 0; j < 8; j++) - if (outputShapeList[j] == outputShapeNHWCList[i] && !permutations.Contains(j)) - permutations.Add(j); - } - - // insert transpose to match layout - string transposedName = $"transpose_{o}_ToMatchNHWCLayout"; - - for (int l = 0; l < nhwc.layers.Count; l++) - { - Layer layer = nhwc.layers[l]; - int index = Array.IndexOf(layer.inputs, o); - if (index != -1) - nhwc.layers[l].inputs[index] = transposedName; - - if (layer.name == o) - nhwc.layers[l].name = transposedName; - } - - Layer transposedOutput = new Layer(o, Layer.Type.Transpose); - transposedOutput.inputs = new[] { transposedName }; - transposedOutput.pool = permutations.ToArray(); - - nhwc.layers.Add(transposedOutput); - } - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectOutputLayoutToMatchNHWCLayout.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectOutputLayoutToMatchNHWCLayout.cs.meta deleted file mode 100644 index 38ddc79..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/CorrectOutputLayoutToMatchNHWCLayout.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 82ea5cd7916102c4084a0617414d8c5d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNCHWToNHWC.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNCHWToNHWC.cs deleted file mode 100644 index 99b4a4b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNCHWToNHWC.cs +++ /dev/null @@ -1,939 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Unity.Barracuda.Compiler.Passes -{ - partial class NCHWToNHWCPass - { - Dictionary> InstantiateRewriterNCHWToNHWC() - { - var rewriters = new Dictionary>(); - - // return true if layer should be included in rewritten model, false if it was replaced - rewriters.Add(Layer.Type.Load, ConvertDatasets); - rewriters.Add(Layer.Type.Reshape, (layer, net) => - { - // TODO reshape with pool as constant - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert Reshape to NHWC"); - - int outputRank = 4; - Layer nchwTranspose; - // TODO cleanup? - if (input0Rank.Value == 1) - nchwTranspose = net.Identity($"Transpose_{input0}_For_{layer.name}", input0); - else if (input0Rank.Value == 2) - nchwTranspose = net.Transpose($"Transpose_{input0}_For_{layer.name}", input0, k_FromNHWCtoNCHW); - else if (input0Rank.Value == 3) - nchwTranspose = net.Transpose($"Transpose_{input0}_For_{layer.name}", input0, k_FromN1WCtoNCH); - else if (input0Rank.Value == 4) - nchwTranspose = net.Transpose($"Transpose_{input0}_For_{layer.name}", input0, k_FromNHWCtoNCHW); - else if (input0Rank.Value == 5) - nchwTranspose = net.Transpose($"Transpose_{input0}_For_{layer.name}", input0, new[] { 0, 1, 2, 3, 7, 4, 5, 6 }); - else - // TODO 8D? - nchwTranspose = net.Transpose($"Transpose_{input0}_For_{layer.name}", input0, new[] { 0, 1, 2, 7, 3, 4, 5, 6 }); - - Layer reshape = null; - if (layer.inputs.Length > 1) - { - string input1 = layer.inputs[1]; - if (!m_RanksByName.TryGetValue(input1, out int? input1Rank) || !input1Rank.HasValue) - throw new Exception($"Must have input rank for {input1} in order to convert Reshape to NHWC"); - - if (input1Rank.Value == 1) // shape is in the tensor - { - if (!m_ShapesByName.TryGetValue(input1, out TensorShape? input1Shape) || !input1Shape.HasValue) - throw new Exception($"Must have input shape for {input1} in order to convert Reshape to NHWC"); - - outputRank = input1Shape.Value[TensorShape.DataBatch]; - } - - reshape = net.Reshape($"{layer.name}_NCHW", nchwTranspose, input1); - } - else if (layer.pool.Length > 0) - { - outputRank = layer.pool.Length; - - var shape = IRShapeInferenceHelper.ShapeInference.OnnxLayoutToTensorShapeLayout(layer.pool); - - reshape = net.Reshape($"{layer.name}_NCHW", nchwTranspose, shape); - } - - // TODO cleanup? - if (outputRank == 1) - nchwTranspose = net.Identity(layer.name, reshape); - else if (outputRank == 2) - nchwTranspose = net.Transpose(layer.name, reshape, k_FromNCHWtoNHWC); - else if (outputRank == 3) - net.Transpose(layer.name, reshape, k_FromNCHtoN1WC); - else if (outputRank == 4) - net.Transpose(layer.name, reshape, k_FromNCHWtoNHWC); - else if (outputRank == 5) - net.Transpose(layer.name, reshape, new[] { 0, 1, 2, 3, 5, 6, 7, 4 }); - else - // TODO 8D? - net.Transpose(layer.name, reshape, new[] { 0, 1, 2, 4, 5, 6, 7, 3 }); - - return false; - }); - rewriters.Add(Layer.Type.Expand, (layer, net) => - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert Reshape to NHWC"); - - int rank0 = input0Rank.Value; - var size = layer.pool.ToList(); - - if (rank0 >= size.Count) - { - for (int i = 0; i < rank0 - size.Count; i++) - size.Insert(0, 1); - layer.pool = size.ToArray(); - return ConvertShape(layer, net); - } - - // inputShape needs to be unsqueezed - var transpose = RankChangePermutationBarracuda(rank0, size.Count); - net.Transpose(layer.name, input0, transpose); - - ConvertShape(layer, net); - - return false; - }); - rewriters.Add(Layer.Type.Shape, (layer, net) => - { - if (layer.axis >= 0) - ConvertAxis(layer, net); - - return true; - }); - rewriters.Add(Layer.Type.Transpose, (layer, net) => - { - int rank = layer.pool.Length; - int[] onnxTranspose = layer.pool; - - // TODO cleanup? - switch (rank) - { - case 2: - { - // onnx : 5,7 => 5,7 / 7,5 - // barracuda : 5,_,_,7 => 5,_,_,7 / 7,_,_,5 - layer.pool = new[] { 0, 1, 2, 3 }; - layer.pool[0] = onnxTranspose[0] == 1 ? 3 : onnxTranspose[0]; - layer.pool[3] = onnxTranspose[1] == 1 ? 3 : onnxTranspose[1]; - return true; - } - case 3: - { - // onnx : 5,7,3 => 5,7,3 / 7,5,3 / 7,3,5 ... - // barracuda : 5,_,7,3 => 7,_,3,5 / 7,_,5,3 ... - layer.pool = new[] { 0, 1, 2, 3 }; - layer.pool[0] = onnxTranspose[0] == 1 ? 3 : onnxTranspose[0] == 2 ? 2 : onnxTranspose[0]; - layer.pool[3] = onnxTranspose[1] == 1 ? 3 : onnxTranspose[1] == 2 ? 2 : onnxTranspose[1]; - layer.pool[2] = onnxTranspose[2] == 1 ? 3 : onnxTranspose[2] == 2 ? 2 : onnxTranspose[2]; - return true; - } - case 4: - { - layer.pool = new[] { 0, 1, 2, 3 }; - layer.pool[0] = onnxTranspose[0] == 1 ? 3 : onnxTranspose[0] == 2 ? 1 : onnxTranspose[0] == 3 ? 2 : onnxTranspose[0]; - layer.pool[3] = onnxTranspose[1] == 1 ? 3 : onnxTranspose[1] == 2 ? 1 : onnxTranspose[1] == 3 ? 2 : onnxTranspose[1]; - layer.pool[1] = onnxTranspose[2] == 1 ? 3 : onnxTranspose[2] == 2 ? 1 : onnxTranspose[2] == 3 ? 2 : onnxTranspose[2]; - layer.pool[2] = onnxTranspose[3] == 1 ? 3 : onnxTranspose[3] == 2 ? 1 : onnxTranspose[3] == 3 ? 2 : onnxTranspose[3]; - return true; - } - case 5: - { - // onnx : 5,7,3,4,9 => 5,9,4,7,3 / 3,9,4,7,5 ... - layer.pool = new[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - // [1,1,N,1,D,H,W,C] - - layer.pool[2] = onnxTranspose[0] == 0 ? 2 : onnxTranspose[0] == 1 ? 7 : onnxTranspose[0] + 2; - layer.pool[7] = onnxTranspose[1] == 0 ? 2 : onnxTranspose[1] == 1 ? 7 : onnxTranspose[1] + 2; - layer.pool[4] = onnxTranspose[2] == 0 ? 2 : onnxTranspose[2] == 1 ? 7 : onnxTranspose[2] + 2; - layer.pool[5] = onnxTranspose[3] == 0 ? 2 : onnxTranspose[3] == 1 ? 7 : onnxTranspose[3] + 2; - layer.pool[6] = onnxTranspose[4] == 0 ? 2 : onnxTranspose[4] == 1 ? 7 : onnxTranspose[4] + 2; - - return true; - } - default: - { - // TODO 8D? - layer.pool = new[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - // NCTDHW - - layer.pool[2] = onnxTranspose[0] == 0 ? 2 : onnxTranspose[0] == 1 ? 7 : onnxTranspose[0] + 1; - layer.pool[7] = onnxTranspose[1] == 0 ? 2 : onnxTranspose[1] == 1 ? 7 : onnxTranspose[1] + 1; - layer.pool[3] = onnxTranspose[2] == 0 ? 2 : onnxTranspose[2] == 1 ? 7 : onnxTranspose[2] + 1; - layer.pool[4] = onnxTranspose[3] == 0 ? 2 : onnxTranspose[3] == 1 ? 7 : onnxTranspose[3] + 1; - layer.pool[5] = onnxTranspose[4] == 0 ? 2 : onnxTranspose[4] == 1 ? 7 : onnxTranspose[4] + 1; - layer.pool[6] = onnxTranspose[5] == 0 ? 2 : onnxTranspose[5] == 1 ? 7 : onnxTranspose[5] + 1; - - return true; - } - } - }); - rewriters.Add(Layer.Type.Unsqueeze, (layer, net) => - { - // Replace w/ a Transpose since Barracuda tensors are full rank (i.e. grab an unused dimension) - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for Unsqueeze"); - - int rank = input0Rank.Value; - var combinePermutations = new[] { 0, 1, 2, 3 }; - for (int i = 0; i < layer.pool.Length; i++) - { - int axis = layer.pool[i]; - if (axis < 0) - axis = rank + 1 - axis; - - var transpose = UnSqueezeAxisPermutationForMappingNCHWLayoutToBarracuda(rank, axis); - - // there could be a 4 / 8D shape mismatch - if (transpose.Length == 8 && combinePermutations.Length == 4) - combinePermutations = Permutation4DTo8D(combinePermutations); - - combinePermutations = TensorExtensions.Permute(transpose, combinePermutations); - - rank++; - } - net.Transpose(layer.name, input0, combinePermutations); - - return false; - }); - rewriters.Add(Layer.Type.Squeeze, (layer, net) => - { - // Replace w/ a Transpose since Barracuda tensors are full rank - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for Squeeze"); - - int rank = input0Rank.Value; - var combinePermutations = new[] { 0, 1, 2, 3 }; - for (int i = 0; i < layer.pool.Length; i++) - { - int axis = layer.pool[i]; - if (axis < 0) - axis = rank + 1 - axis; - - var transpose = SqueezeAxisPermutationForMappingNCHWLayoutToBarracuda(rank, axis); - - // there could be a 4 / 8D shape mismatch - if (transpose.Length == 8 && combinePermutations.Length == 4) - combinePermutations = Permutation4DTo8D(combinePermutations); - - combinePermutations = TensorExtensions.Permute(transpose, combinePermutations); - - rank--; - } - net.Transpose(layer.name, input0, combinePermutations); - - return false; - }); - rewriters.Add(Layer.Type.Flatten, (layer, net) => - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert Flatten to NHWC"); - - Layer nchwTranspose = net.Transpose($"Transpose_{input0}_For_{layer.name}", input0, input0Rank.Value == 3 ? k_FromN1WCtoNCH : k_FromNHWCtoNCHW); - net.Flatten(layer.name, nchwTranspose); - // No need to transpose back b/c final shape is always NC (rank 2) - - return false; - }); - rewriters.Add(Layer.Type.Concat, ConvertAxis); - rewriters.Add(Layer.Type.StridedSlice, (layer, net) => - { - int rank = 4; - if (m_RanksByName.ContainsKey(layer.name) && m_RanksByName[layer.name] != null) - rank = m_RanksByName[layer.name].Value; - - var name = layer.name; - - var starts = layer.pad; - var ends = layer.pool; - var steps = layer.stride; - var axes = layer.axes; - - var onnxStarts = Enumerable.Repeat(0, rank).ToArray(); - var onnxEnds = Enumerable.Repeat(int.MaxValue, rank).ToArray(); // by default copy the whole axis till the end - var onnxSteps = Enumerable.Repeat(1, rank).ToArray(); - - // NOTE: begin=0, end=0, stride=1 <= full range from existing axis - // begin=0, end=inf,stride=1 <= full range from existing axis - // begin=0, end=X, stride=1 <= full range from existing axis, if X==last element on this axis - // begin=0, end=0, stride=0 <= new axis OR shrink axis to single 1st element - // begin=N, end=N, stride=0 <= shrink axis to single Nth element - // These notes are copied from TensorExtensions.ApplyStridedSlice(...) - - for (int i = 0; i < axes.Length; ++i) - { - var axis = axes[i]; - if (axis < 0) - axis += rank; - axis = Math.Min(Math.Max(axis, 0), rank); - - onnxStarts[axis] = starts[i]; - onnxEnds[axis] = ends[i]; - onnxSteps[axis] = steps[i]; - } - - layer.pad = PermuteToBarracuda(onnxStarts, rank, 0); - layer.pool = PermuteToBarracuda(onnxEnds, rank, int.MaxValue); - layer.stride = PermuteToBarracuda(onnxSteps, rank, 1); - - return true; - }); - rewriters.Add(Layer.Type.Tile, (layer, net) => - { - if (layer.inputs.Length == 1) - { - int rank = 4; - if (m_RanksByName.ContainsKey(layer.name) && m_RanksByName[layer.name] != null) - rank = m_RanksByName[layer.name].Value; - layer.pool = PermuteToBarracuda(layer.pool, rank, 1);// TensorExtensions.Permute(layer.pool, k_FromNCHWtoNHWC); - } - - return true; - }); - rewriters.Add(Layer.Type.Activation, ConvertActivation); - rewriters.Add(Layer.Type.Gather, ConvertGather); - rewriters.Add(Layer.Type.TopKIndices, ConvertAxis); - rewriters.Add(Layer.Type.TopKValues, ConvertAxis); - - rewriters.Add(Layer.Type.RandomNormal, ConvertNormal); - rewriters.Add(Layer.Type.RandomUniform, ConvertNormal); - - rewriters.Add(Layer.Type.ReduceMax, Reduce); - rewriters.Add(Layer.Type.ReduceMean, Reduce); - rewriters.Add(Layer.Type.ReduceMin, Reduce); - rewriters.Add(Layer.Type.ReduceProd, Reduce); - rewriters.Add(Layer.Type.ReduceSum, Reduce); - - rewriters.Add(Layer.Type.ArgMax, Reduce); - rewriters.Add(Layer.Type.ArgMin, Reduce); - - rewriters.Add(Layer.Type.Upsample2D, Upsample); - rewriters.Add(Layer.Type.Resample2D, Upsample); - rewriters.Add(Layer.Type.Upsample3D, Upsample); - - rewriters.Add(Layer.Type.MatMul, (layer, net) => - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - string input1 = layer.inputs[1]; - if (!m_RanksByName.TryGetValue(input1, out int? input1Rank) || !input1Rank.HasValue) - throw new Exception($"Must have input rank for {input1} in order to convert axis for NHWC op"); - - layer.pool = new[] { input0Rank.Value, input1Rank.Value }; - - return true; - }); - - rewriters.Add(Layer.Type.OneHot, (layer, net) => - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - layer.axis = input0Rank.Value; - - return true; - }); - - rewriters.Add(Layer.Type.Pad, Pad); - - - return rewriters; - } - - int[] GetChannelsLastPermutationsFromRank(int rank) - { - int[] fromNtoC = { 3, 1, 2, 0 }; - int[] k_FromNCtoN11C = { 0, 2, 3, 1 }; - int[] k_FromNCDHWtoNDHWC = { 0, 1, 2, 3, 5, 6, 7, 4 }; - - int[] permutations = k_FromNCHWtoNHWC; - if (rank == 5) - permutations = k_FromNCDHWtoNDHWC; - else if (rank == 3) - permutations = k_FromNCHtoN1WC; - else if (rank == 2) - permutations = k_FromNCtoN11C; - // else if (rank == 1) // AE: are we keeping rank 1 in N now? - // permutations = fromNtoC; - - return permutations; - } - - int GetApproximateRankFromTensorShape(TensorShape shape) - { - // dimensions misreports rank if a dimension is 1 - int rank = shape.dimensions; - // NOTE: NCHW shape reinterpretation of barracuda layout: N == batch, C == height, H == width, W == height - if (shape.batch == 1) - rank++; - if (shape.height == 1 && (shape.width > 1 || shape.height > 1)) - rank++; - - return rank; - } - - bool ConvertDatasets(Layer layer, ModelBuilder net) - { - for (var i = 0; i < layer.datasets.Length; i++) - { - var X = layer.DataSetToTensor(i); - - // NCH is treated as NC1W in Barracuda - TensorShape shape = X.shape; - - int rank = layer.axis; // rank that may have been shoved into the layer on import (e.g. Const) - if (rank < 0) - rank = GetApproximateRankFromTensorShape(shape); - - int[] permutations = GetChannelsLastPermutationsFromRank(rank); - var O = m_Ops.Transpose(X, permutations); - layer.ApplyTensorToDataSet(O, i); - - O.Dispose(); - X.Dispose(); - } - - return true; - } - - bool ConvertActivation(Layer layer, ModelBuilder net) - { - if (layer.activation != Layer.Activation.Softmax && layer.activation != Layer.Activation.LogSoftmax) - return true; - - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - int axis = layer.axis; - if (axis < 0) - axis += input0Rank.Value; - - int[] permutations = AxisPermutationsForMappingNCHWLayoutToBarracuda(input0Rank.Value); - layer.axis = Array.IndexOf(permutations, axis); - - return true; - } - - bool ConvertNormal(Layer layer, ModelBuilder net) - { - if (layer.inputs.Length == 1) - return true; - - var shape = new TensorShape(layer.pool); - var permutations = shape.Get8DPermutationsForNCHWPermutationsAndShape(k_FromNCHWtoNHWC); - - // Preserve symbolic shape by operating on int array instead of TensorShape, which would resolve unknown dimensions - layer.pool = TensorExtensions.Permute(layer.pool, permutations); - - return true; - } - - bool ConvertShape(Layer layer, ModelBuilder net) - { - layer.pool = IRShapeInferenceHelper.ShapeInference.OnnxLayoutToBarracudaTensorShape(layer.pool).ToArray(); - return true; - } - - bool ConvertAxis(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - int axis = layer.axis; - if (axis < 0) - axis += input0Rank.Value; - - int[] permutations = AxisPermutationsForMappingNCHWLayoutToBarracuda(input0Rank.Value); - layer.axis = Array.IndexOf(permutations, axis); - - return true; - } - - bool ConvertGather(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - string input1 = layer.inputs[1]; - if (!m_RanksByName.TryGetValue(input1, out int? input1Rank) || !input1Rank.HasValue) - throw new Exception($"Must have input rank for {input1} in order to convert axis for NHWC op"); - - layer.pool = new[] { input0Rank.Value, input1Rank.Value }; - - return ConvertAxis(layer, net); - } - - - bool Upsample(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - if (layer.inputs.Length > 1) // dynamic case - return true; - - int[] scales = layer.pool; - scales = scales.Skip(2).ToArray(); - switch (scales.Length) - { - case 0: - layer.pool = new[] { 1, 1 }; - break; - case 1: - layer.pool = new[] { scales[0], 1 }; // 1D W => W_ - break; - case 2: - layer.pool = new[] { scales[1], scales[0] }; // 2D HW => WH - break; - case 3: - layer.pool = new[] { scales[2], scales[1], scales[0] }; // 3D DHW => WHD - break; - default: - throw new Exception($"Attribute pads of unsupported length {scales.Length} in {layer.name} ot type {layer.type}."); - } - - return true; - } - - bool Pad(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert pad for NHWC op"); - - var autopadOption = (Layer.AutoPad)(layer.pool[0]); - - if (input0Rank <= 4) - { - if (autopadOption == Layer.AutoPad.NotSet) - { - if (input0Rank == 4) // CHW => WHC - layer.pad = new[] { layer.pad[3], layer.pad[2], layer.pad[1], layer.pad[7], layer.pad[6], layer.pad[5] }; - else if (input0Rank == 3) // CW => W_C - layer.pad = new[] { layer.pad[2], 0, layer.pad[1], layer.pad[5], layer.pad[4] }; - } - else - { - int autopad = -(int)(autopadOption); - layer.pad = new[] { autopad, autopad, autopad, autopad }; - } - switch (layer.axis) - { - case 0: - layer.type = Layer.Type.Border2D; - break; - case 1: - layer.type = Layer.Type.Pad2DReflect; - break; - case 2: - layer.type = Layer.Type.Pad2DEdge; - break; - case 3: - layer.type = Layer.Type.Pad2DSymmetric; - break; - } - layer.axis = -1; - return true; - } - else if (input0Rank == 5) - { - // CDHW => WHDC - layer.pad = new[] { layer.pad[4], layer.pad[3], layer.pad[2], layer.pad[1], layer.pad[9], layer.pad[8], layer.pad[7], layer.pad[6] }; - layer.type = Layer.Type.Border3D; - return true; - } - - throw new Exception($"Unsuported Pad layer, {layer.name}"); - } - - bool Reduce(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - int axis = layer.axis; - if (axis < 0) - axis += input0Rank.Value; - - int[] permutations = AxisPermutationsForMappingNCHWLayoutToBarracuda(input0Rank.Value); - layer.axis = Array.IndexOf(permutations, axis); - - - int keepdims = (int)layer.alpha; - - if (keepdims != 1 && input0Rank.Value > 1) // keepdims removes dimensions in the context of onnx thus we need to repack/transpose to match behavior. - { - string name = layer.name; - layer.name = $"{layer.name}__reduce"; - - net.Reduce(layer.type, layer.name, input0, layer.axis, true, -1); - - - var nameT = $"{layer.name}__transpose"; - var transpose = GetPermutationToMatchReduceWithDroppedDimensionsFromONNX(new[] { axis }, input0Rank.Value); - var transposeLayer = net.Transpose(nameT, layer, transpose); - - net.Identity(name, transposeLayer); - } - else - { - net.Reduce(layer.type, layer.name, input0, layer.axis, true, -1); - } - - return false; - } - - static int[] AxisPermutationsForMappingNCHWLayoutToBarracuda(int rank) - { - const int _ = -1; - - switch (rank) - { - case 6: - return new[] { _, _, 0, 2, 3, 4, 5, 1 }; - case 5: - return new[] { _, _, 0, _, 2, 3, 4, 1 }; - case 4: - return new[] { _, _, 0, _, _, 2, 3, 1 }; - case 3: - return new[] { _, _, 0, _, _, _, 2, 1 }; - case 2: - return new[] { _, _, 0, _, _, _, _, 1 }; - case 1: - case 0: - return new[] { _, _, 0, _, _, _, _, _ }; - } - - throw new ArgumentException($"Unsupported tensor rank {rank}"); - } - - public static int[] PermuteToBarracuda(int[] shape, int rank = 4, int defaultValue = 1) - { - var permutations = AxisPermutationsForMappingNCHWLayoutToBarracuda(rank); // Originally was NCHW - UnityEngine.Debug.Assert(shape.Length <= permutations.Length); - UnityEngine.Debug.Assert(shape.Length >= permutations.Count(v => v >= 0)); - var output = new int[permutations.Length]; - for (var i = 0; i < permutations.Length; ++i) - { - output[i] = permutations[i] >= 0 ? shape[permutations[i]] : defaultValue; - } - - return output; - } - - static int[] UnSqueezeAxisPermutationForMappingNCHWLayoutToBarracuda(int onnxRank, int onnxAxis) - { - var identity = new[] { 0, 1, 2, 3 }; - - - if (onnxRank == 4) - { - // axis: 0 1 2 3 4 - // ONNX: NCHW 1NCHW N1CHW NC1HW NCH1W NCHW1 - // Barracuda: NHWC 1__CHWN N__CHW1 N__1HWC N__H1WC N__HW1C - if (onnxAxis == 0) - return new[] { 0, 1, 3, 4, 7, 5, 6, 2 }; - else if (onnxAxis == 1) - return new[] { 0, 1, 2, 3, 7, 5, 6, 4 }; - else if (onnxAxis == 2) - return new[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - else if (onnxAxis == 3) - return new[] { 0, 1, 2, 3, 5, 4, 6, 7 }; - else - return new[] { 0, 1, 2, 3, 5, 6, 4, 7 }; - } - else if (onnxRank == 3) - { - // axis: 0 1 2 3 - // ONNX: NCH 1NCH N1CH NC1H NCH1 - // Barracuda: N_HC 1CHN NCH1 N1HC NH1C - if (onnxAxis == 0) - return new[] { 1, 3, 2, 0 }; - else if (onnxAxis == 1) - return new[] { 0, 3, 2, 1 }; - else if (onnxAxis == 2) - return identity; - else - return new[] { 0, 2, 1, 3 }; - } - else if (onnxRank == 2) - { - // axis: 0 1 2 - // ONNX: NC 1NC N1C NC1 - // Barracuda: N__C 1_CN N_C1 N_1C - if (onnxAxis == 0) - return new[] { 1, 2, 3, 0 }; - else if (onnxAxis == 1) - return new[] { 0, 1, 3, 2 }; - else - return identity; - } - else if (onnxRank == 1) - { - // axis: 0 1 - // ONNX: N 1N N1 - // Barracuda: N___ 1__N N__1 - if (onnxAxis == 0) - return new[] { 1, 2, 3, 0 }; - else - return identity; - } - else if (onnxRank == 0) - return identity; - else - throw new InvalidOperationException($"Not supported UnSqueeze operation with rank {onnxRank}"); - } - - static int[] SqueezeAxisPermutationForMappingNCHWLayoutToBarracuda(int onnxRank, int onnxAxis) - { - var identity = new[] { 0, 1, 2, 3 }; - - if (onnxRank == 5) - { - // axis: 0 1 2 3 4 - // ONNX: NCDHW CDHW NDHW NCHW NCDW NCDH - // Barracuda: N_DHWC C__HWD N__HWD N__HWC N__DWC N__DHC - // { 0,1,2,3,4,5,6,7} - // _,_,N,_,D,H,W,C - if (onnxAxis == 0) - return new[] { 0, 1, 7, 3, 2, 5, 6, 4 }; - else if (onnxAxis == 1) - return new[] { 0, 1, 2, 3, 7, 5, 6, 4 }; - else if (onnxAxis == 2) - return new[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - else if (onnxAxis == 3) - return new[] { 0, 1, 2, 3, 5, 4, 6, 7 }; - else - return new[] { 0, 1, 2, 3, 6, 4, 5, 7 }; - } - else if (onnxRank == 4) - { - // axis: 0 1 2 3 - // ONNX: NCHW CHW NHW NCW NCH - // Barracuda: NHWC C_WH N_WH N_WC N_HC - if (onnxAxis == 0) - return new[] { 3, 0, 2, 1 }; - else if (onnxAxis == 1) - return new[] { 0, 3, 2, 1 }; - else if (onnxAxis == 2) - return identity; - else - return new[] { 0, 2, 1, 3 }; - } - else if (onnxRank == 3) - { - // axis: 0 1 2 - // ONNX: NCH CH NH NC - // Barracuda: N_HC C__H N__H N__C - if (onnxAxis == 0) - return new[] { 3, 0, 1, 2 }; - else if (onnxAxis == 1) - return new[] { 0, 1, 3, 2 }; - else - return identity; - } - else if (onnxRank == 2) - { - // axis: 0 1 - // ONNX: NC C N - // Barracuda: N__C C___ N___ - if (onnxAxis == 0) - return new[] { 3, 0, 1, 2 }; - else - return identity; - } - else if (onnxRank == 1) - return identity; - else - throw new InvalidOperationException($"Not supported Squeeze operation with rank {onnxRank}"); - } - - private static int[] GetPermutationToMatchReduceWithDroppedDimensionsFromONNX(int[] droppedONNXAxis, int rank) - { - //Assert.IsTrue(droppedONNXAxis.Length > 0); - - //Barracuda always have all dimensions, however in ONNX it is not the case one can drop dimensions, - //Here we handle the case of ReduceXXX ops when they do so. - //An example: - //ONNX -> NCHW - //Reduce on C with keepDims=False. - //ONNX -> NHW - //However ONNX tensor semantic are deducted by position to be mapped to Barracuda in the following way: - //ONNX 1D -> N -> Barracuda N,1,1,1 - //ONNX 2D -> NC -> Barracuda N,1,1,C - //ONNX 3D -> NCW -> Barracuda N,1,W,C - //ONNX 4D -> NCHW -> Barracuda N,H,W,C - //Thus the output tensor above (NHW) will be mapped to N,1,W,C in Barracuda - //while Reduce in Barracuda would rather output N,H,W,1 if keepDim would be true. - //Here we find the transpose needed in Barracuda to match the ONNX behavior as seen by Barracuda. - //ie the transpose from N,H,W,1 to N,1,W,C in this case aka 0,3,2,1. - - //ONNX input Layout from rank - string onnxLayout; - switch (rank) - { - case 1: - onnxLayout = "N"; - break; - case 2: - onnxLayout = "NC"; - break; - case 3: - onnxLayout = "NCW"; - break; - case 4: - onnxLayout = "NCHW"; - break; - default: - //TODO support 8D - throw new Exception($"Reduce ops support up to 4D at the moment, however received an input of rank {rank}."); - } - - //ONNX Layout once dimensions are dropped (example: NHW if C was dropped) - string onnxLayoutDimensionsDropped = onnxLayout; - foreach (var axis in droppedONNXAxis) - { - var onnxAxis = axis; - if (onnxAxis < 0) - onnxAxis = rank + axis; - string semanticToRemove = onnxLayout[onnxAxis].ToString(); - onnxLayoutDimensionsDropped = onnxLayoutDimensionsDropped.Replace(semanticToRemove, string.Empty); - } - // Assert.IsTrue(onnxLayoutDimensionsDropped.Length > 0); - - //Find all missing dimensions that will be unitary in Barracuda - var missingDimensions = new List(); - foreach (var dim in "NHWC") - { - if (!onnxLayoutDimensionsDropped.Contains(dim)) - missingDimensions.Add(dim); - } - - //Find semantic of onnx layout with dropped dimension in Barracuda - var barracudaSemanticLayoutFromONNXReduce = new char[4]; - switch (onnxLayoutDimensionsDropped.Length) - { - case 1: - //ONNX 1D -> N -> Barracuda N,1,1,1 - barracudaSemanticLayoutFromONNXReduce[0] = onnxLayoutDimensionsDropped[0]; - barracudaSemanticLayoutFromONNXReduce[1] = missingDimensions[0]; - barracudaSemanticLayoutFromONNXReduce[2] = missingDimensions[1]; - barracudaSemanticLayoutFromONNXReduce[3] = missingDimensions[2]; - break; - case 2: - //ONNX 2D -> NC -> Barracuda N,1,1,C - barracudaSemanticLayoutFromONNXReduce[0] = onnxLayoutDimensionsDropped[0]; - barracudaSemanticLayoutFromONNXReduce[1] = missingDimensions[0]; - barracudaSemanticLayoutFromONNXReduce[2] = missingDimensions[1]; - barracudaSemanticLayoutFromONNXReduce[3] = onnxLayoutDimensionsDropped[1]; - break; - case 3: - //3D -> NCW -> Barracuda N,1,W,C - barracudaSemanticLayoutFromONNXReduce[0] = onnxLayoutDimensionsDropped[0]; - barracudaSemanticLayoutFromONNXReduce[1] = missingDimensions[0]; - barracudaSemanticLayoutFromONNXReduce[2] = onnxLayoutDimensionsDropped[2]; - barracudaSemanticLayoutFromONNXReduce[3] = onnxLayoutDimensionsDropped[1]; - break; - } - - //Find permutation from NHWC Barracuda layout when mapped from ONNX with dropped dimensions. - var permutation = new int[4]; - for (int idTarget = 0; idTarget < permutation.Length; ++idTarget) - { - char semantic = barracudaSemanticLayoutFromONNXReduce[idTarget]; - permutation[idTarget] = "NHWC".IndexOf(semantic); ; - } - return permutation; - } - - private static int[] RankChangePermutationBarracuda(int rank0, int rank1) - { - var identity = new[] { 0, 1, 2, 3 }; - if (rank0 == 0) - return identity; - else if (rank0 == 1) - { - // ONNX: - // 8 -> 1,8 - // 8 -> 1,1,8 - // 8 -> 1,1,1,8 - // barracuda - // 8,_,_,_ => 1,_,_,8 - // 8,_,_,_ => 1,_8,1 - // 8,_,_,_ => 1,1,8,1 - if (rank1 == 0 || rank1 == 1) - return identity; - else if (rank1 == 2) - return new[] { 1, 2, 3, 0 }; - else if (rank1 == 3) - return new[] { 1, 2, 0, 3 }; - else if (rank1 == 4) - return new[] { 1, 2, 0, 3 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else if (rank0 == 2) - { - // ONNX: - // 28 -> 1,2,8 - // 28 -> 1,1,2,8 - // barracuda - // 2__8 => 1,_8,2 - // 2__8 => 1,2,8,1 - if (rank1 == 3) - return new[] { 1, 2, 3, 0 }; - else if (rank1 == 4) - return new[] { 1, 0, 3, 2 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else if (rank0 == 3) - { - // ONNX: - // 5,2,8 -> 1,5,2,8 - // barracuda - // 5,_,8,2 => 1,2,8,5 - if (rank1 == 4) - return new[] { 1, 3, 2, 0 }; - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - else - throw new ArgumentException($"Unsupported rank permutation change {rank0} to {rank1}"); - } - - static public int[] Permutation4DTo8D(int[] permutations) - { - if (permutations.Length == TensorShape.MaxRank) - return permutations; - - int batchOldAxis = TensorExtensions.Convert4DTo8DAxis(permutations[0]); - int heighOldAxis = TensorExtensions.Convert4DTo8DAxis(permutations[1]); - int widthOldIndex = TensorExtensions.Convert4DTo8DAxis(permutations[2]); - int channeOldIndex = TensorExtensions.Convert4DTo8DAxis(permutations[3]); - return new int[] { 0, 1, batchOldAxis, 3, 4, heighOldAxis, widthOldIndex, channeOldIndex }; - } - - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNCHWToNHWC.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNCHWToNHWC.cs.meta deleted file mode 100644 index 1e01c39..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNCHWToNHWC.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6a7c86eba103ea745a107925131cd73a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNHWCToNHWC.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNHWCToNHWC.cs deleted file mode 100644 index 2e588ed..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNHWCToNHWC.cs +++ /dev/null @@ -1,485 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Unity.Barracuda.Compiler.Passes -{ - partial class NCHWToNHWCPass - { - Dictionary> InstantiateRewriterNHWCToNHWC() - { - var rewritersNHWC = new Dictionary>(); - - // TODO, upsample is sometimes in NHWC mode - rewritersNHWC.Add(Layer.Type.Reshape, (layer, net) => - { - if (layer.inputs.Length == 1) - { - var size = layer.pool; - - // Don't use Tensorshape as this can remove a wild card - const int _ = 1; - if (size.Length == 1) - layer.pool = new[] { _, _, size[0], _, _, 1, 1, 1 }; // [1,1,N,1,1,1,1,1] - else if (size.Length == 2) - layer.pool = new[] { _, _, size[0], _, _, 1, 1, size[1] }; // [1, 1, N, 1, 1, 1, 1, C] - else if (size.Length == 3) - layer.pool = new[] { _, _, size[0], _, _, _, size[1], size[2] }; // [1,1,N,1,1,1,W,C] - else if (size.Length == 4) - layer.pool = new[] { _, _, size[0], _, _, size[1], size[2], size[3] }; // [1,1,N,1,1,H,W,C] - else if (size.Length == 5) - layer.pool = new[] { _, _, size[0], _, size[1], size[2], size[3], size[4] }; // [1,1,N,1,D,H,W,C] - else if (size.Length == 6) - layer.pool = new[] { _, _, size[0], size[1], size[2], size[3], size[4], size[5] }; // [1,1,N,T,D,H,W,C] - else - layer.pool = new[] { size[0], size[1], size[2], size[3], size[4], size[5], size[6], size[7] }; // [S,R,N,T,D,H,W,C] - } - return true; - }); - rewritersNHWC.Add(Layer.Type.Transpose, (layer, net) => - { - var size = layer.pool; - if (size.Length == 1) - { - layer.pool = new[] { 0, 1, 2, 3 }; // [N,_,_,_] - layer.pool[0] = size[0]; - } - else if (size.Length == 2) - { - layer.pool = new[] { 0, 1, 2, 3 }; // [N, _, _, C] - layer.pool[0] = size[0] == 0 ? 0 : size[0] + 2; - layer.pool[3] = size[1] == 0 ? 0 : size[1] + 2; - } - else if (size.Length == 3) - { - layer.pool = new[] { 0, 1, 2, 3 }; // [N, _, W, C] - layer.pool[0] = size[0] == 0 ? 0 : size[0] + 1; - layer.pool[2] = size[1] == 0 ? 0 : size[1] + 1; - layer.pool[3] = size[2] == 0 ? 0 : size[2] + 1; - } - else if (size.Length == 4) - layer.pool = size; // [N,H,W,C] - else if (size.Length == 5) - { - layer.pool = new[] { 0, 1, 2, 3, 4, 5, 6, 7 }; // [_,_,N,_,D,H,W,C] - layer.pool[2] = size[0] == 0 ? 2 : size[0] + 3; - layer.pool[4] = size[1] == 0 ? 2 : size[1] + 3; - layer.pool[5] = size[2] == 0 ? 2 : size[2] + 3; - layer.pool[6] = size[3] == 0 ? 2 : size[3] + 3; - layer.pool[7] = size[4] == 0 ? 2 : size[4] + 3; - } - else if (size.Length == 6) - { - layer.pool = new[] { 0, 1, 2, 3, 4, 5, 6, 7 }; // [1,1,N,T,D,H,W,C] - layer.pool[2] = size[0] + 2; - layer.pool[3] = size[1] + 2; - layer.pool[4] = size[2] + 2; - layer.pool[5] = size[3] + 2; - layer.pool[6] = size[4] + 2; - layer.pool[7] = size[5] + 2; - } - else - layer.pool = new[] { size[0], size[1], size[2], size[3], size[4], size[5], size[6], size[7] }; // [S,R,N,T,D,H,W,C] - return true; - }); - rewritersNHWC.Add(Layer.Type.Gather, ConvertGatherNHWC); - rewritersNHWC.Add(Layer.Type.Concat, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.ReduceMax, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.ReduceMean, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.ReduceMin, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.ReduceProd, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.ReduceSum, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.ArgMax, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.ArgMin, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.Activation, ConvertAxisNHWC); - rewritersNHWC.Add(Layer.Type.StridedSlice, (layer, net) => - { - int rank = 4; - if (m_RanksByName.ContainsKey(layer.name) && m_RanksByName[layer.name] != null) - rank = m_RanksByName[layer.name].Value; - - var name = layer.name; - - var starts = layer.pad; - var ends = layer.pool; - var steps = layer.stride; - var axes = layer.axes; - - var onnxStarts = Enumerable.Repeat(0, rank).ToArray(); - var onnxEnds = Enumerable.Repeat(int.MaxValue, rank).ToArray(); // by default copy the whole axis till the end - var onnxSteps = Enumerable.Repeat(1, rank).ToArray(); - - // NOTE: begin=0, end=0, stride=1 <= full range from existing axis - // begin=0, end=inf,stride=1 <= full range from existing axis - // begin=0, end=X, stride=1 <= full range from existing axis, if X==last element on this axis - // begin=0, end=0, stride=0 <= new axis OR shrink axis to single 1st element - // begin=N, end=N, stride=0 <= shrink axis to single Nth element - // These notes are copied from TensorExtensions.ApplyStridedSlice(...) - - for (int i = 0; i < axes.Length; ++i) - { - var axis = axes[i]; - if (axis < 0) - axis += rank; - axis = Math.Min(Math.Max(axis, 0), rank); - - onnxStarts[axis] = starts[i]; - onnxEnds[axis] = ends[i]; - onnxSteps[axis] = steps[i]; - } - - switch (rank) - { - case 1: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, 0, 0, 0 }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, 1, 1, 1 }; - break; - case 2: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, 0, 0, onnxStarts[1] }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, onnxEnds[1] }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, 1, 1, onnxSteps[1] }; - break; - case 3: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, 0, onnxStarts[1], onnxStarts[2] }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, int.MaxValue, onnxEnds[1], onnxEnds[2] }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, 1, onnxSteps[1], onnxSteps[2] }; - break; - case 4: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, onnxStarts[1], onnxStarts[2], onnxStarts[3] }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, onnxEnds[1], onnxEnds[2], onnxEnds[3] }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, onnxSteps[1], onnxSteps[2], onnxSteps[3] }; - break; - case 5: - layer.pad = new[] { 0, 0, onnxStarts[0], 0, onnxStarts[1], onnxStarts[2], onnxStarts[3], onnxStarts[4] }; - layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, onnxEnds[1], onnxEnds[2], onnxEnds[3], onnxEnds[4] }; - layer.stride = new[] { 1, 1, onnxSteps[0], 1, onnxSteps[1], onnxSteps[2], onnxSteps[3], onnxSteps[4] }; - break; - default: - throw new ArgumentException($"Unsupported tensor rank {rank} for StridedSlice"); - } - return true; - }); - rewritersNHWC.Add(Layer.Type.Flatten, (layer, net) => - { - layer.type = Layer.Type.Nop; - return true; - }); - rewritersNHWC.Add(Layer.Type.Squeeze, (layer, net) => - { - int input0Rank = 4; - if (m_RanksByName.ContainsKey(layer.inputs[0]) && m_RanksByName[layer.inputs[0]] != null) - input0Rank = m_RanksByName[layer.inputs[0]].Value; - - int rank = input0Rank; - var combinePermutations = new[] { 0, 1, 2, 3 }; - for (int i = 0; i < layer.pool.Length; i++) - { - int axis = layer.pool[i]; - if (axis < 0) - axis = rank + 1 - axis; - - var transpose = SqueezeAxisPermutationForMappingNHWCLayoutToBarracuda(rank, axis); - - // there could be a 4 / 8D shape mismatch - if (transpose.Length == 8 && combinePermutations.Length == 4) - combinePermutations = Permutation4DTo8D(combinePermutations); - - combinePermutations = TensorExtensions.Permute(transpose, combinePermutations); - - rank--; - } - - layer.type = Layer.Type.Transpose; - layer.pool = combinePermutations; - - return true; - }); - rewritersNHWC.Add(Layer.Type.Unsqueeze, (layer, net) => - { - int input0Rank = 4; - if (m_RanksByName.ContainsKey(layer.inputs[0]) && m_RanksByName[layer.inputs[0]] != null) - input0Rank = m_RanksByName[layer.inputs[0]].Value; - - int rank = input0Rank; - var combinePermutations = new[] { 0, 1, 2, 3 }; - for (int i = 0; i < layer.pool.Length; i++) - { - int axis = layer.pool[i]; - if (axis < 0) - axis = rank + 1 - axis; - - var transpose = UnSqueezeAxisPermutationForMappingNHWCLayoutToBarracuda(rank, axis); - - // there could be a 4 / 8D shape mismatch - if (transpose.Length == 8 && combinePermutations.Length == 4) - combinePermutations = Permutation4DTo8D(combinePermutations); - - combinePermutations = TensorExtensions.Permute(transpose, combinePermutations); - - rank++; - } - - layer.type = Layer.Type.Transpose; - layer.pool = combinePermutations; - - return true; - }); - rewritersNHWC.Add(Layer.Type.Load, (layer, net) => - { - int rank = layer.axis; - if (rank != 2 && rank != 3) - return true; - - var constX = layer.DataSetToTensor(0); - - var shape = constX.shape; - switch (rank) - { - case 2: - // _,_,N,_,_,C,_,_ => _,_,N,_,_,_,_,C - shape = new TensorShape(shape.batch, shape.height); - break; - case 3: - // _,_,N,_,_,W,C,_ => _,_,N,_,_,_,W,C - shape = new TensorShape(shape.batch, shape.height, shape.width); - break; - } - - var reshapedX = m_Ops.Reshape(constX, shape); - layer.ApplyTensorToDataSet(reshapedX, 0); - reshapedX.Dispose(); - constX.Dispose(); - return true; - }); - rewritersNHWC.Add(Layer.Type.OneHot, (layer, net) => - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - layer.axis = input0Rank.Value; - - return true; - }); - rewritersNHWC.Add(Layer.Type.MatMul, (layer, net) => - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - string input1 = layer.inputs[1]; - if (!m_RanksByName.TryGetValue(input1, out int? input1Rank) || !input1Rank.HasValue) - throw new Exception($"Must have input rank for {input1} in order to convert axis for NHWC op"); - - layer.pool = new[] { input0Rank.Value, input1Rank.Value }; - - int outputRank = Math.Max(input0Rank.Value, input1Rank.Value); - - if (outputRank <= 2) - { - return true; - } - - Layer input0Transposed = net.Transpose($"Transpose_For_{input0}", input0, input0Rank.Value == 3 ? k_FromNCHtoN1WC : k_ToNHWC); - Layer input1Transposed = net.Transpose($"Transpose_For_{input1}", input1, input1Rank.Value == 3 ? k_FromNCHtoN1WC : k_ToNHWC); - - string originalLayerName = layer.name; - layer.name = $"{layer.name}_NHWC"; - layer.inputs[0] = input0Transposed.name; - layer.inputs[1] = input1Transposed.name; - net.model.layers.Add(layer); - - net.Transpose(originalLayerName, layer.name, outputRank == 3 ? k_FromN1WCtoNCH : k_ToNCHW); - - return false; - }); - rewritersNHWC.Add(Layer.Type.Pad, PadNHWC); - - return rewritersNHWC; - } - - bool ConvertAxisNHWC(Layer layer, ModelBuilder net) - { - if (layer.type == Layer.Type.Activation && layer.activation != Layer.Activation.Softmax && layer.activation != Layer.Activation.LogSoftmax) - return true; - - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - var axis = layer.axis; - if (input0Rank == 1 || input0Rank == 0) - // N => _,_N,_,_,_,_,_ - // 0 2 - layer.axis = 2; - else if (input0Rank == 2) - // N,C => _,_,N,_,_,_,_,C - // 0,1 2 7 - layer.axis = axis == 0 ? 2 : 7; - else if (input0Rank == 3) - // N,W,C => _,_N,_,_,_,W,C - // 0,1,2 2 6,7 - layer.axis = axis == 0 ? 2 : axis + 5; - else if (input0Rank == 4) - // N,H,W,C => _,_N,_,_,H,W,C - // 0,1,2,3 2 5,6,7 - layer.axis = axis == 0 ? 2 : axis + 4; - else if (input0Rank == 5) - // N,D,H,W,C => N,_,D,H,W,C - // 0,1,2,3,4 2, 4,5,6,7 - layer.axis = axis == 0 ? 2 : axis + 3; - else if (input0Rank == 6) - // N,T,D,H,W,C => N,T,D,H,W,C - // 0,1,2,3,4,5 2,3,4,5,6,7 - layer.axis = axis + 2; - else - throw new ArgumentException($"Unsupported tensor rank {input0Rank} for StridedSlice"); - return true; - } - - bool ConvertGatherNHWC(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert axis for NHWC op"); - - string input1 = layer.inputs[1]; - if (!m_RanksByName.TryGetValue(input1, out int? input1Rank) || !input1Rank.HasValue) - throw new Exception($"Must have input rank for {input1} in order to convert axis for NHWC op"); - - layer.pool = new[] { input0Rank.Value, input1Rank.Value }; - - return ConvertAxisNHWC(layer, net); - } - - bool PadNHWC(Layer layer, ModelBuilder net) - { - string input0 = layer.inputs[0]; - if (!m_RanksByName.TryGetValue(input0, out int? input0Rank) || !input0Rank.HasValue) - throw new Exception($"Must have input rank for {input0} in order to convert pad for NHWC op"); - - var autopadOption = (Layer.AutoPad)(layer.pool[0]); - - if (input0Rank <= 4) - { - if (autopadOption == Layer.AutoPad.NotSet) - { - if (input0Rank == 4) // HWC => WHC - layer.pad = new[] { layer.pad[2], layer.pad[1], layer.pad[3], layer.pad[6], layer.pad[5], layer.pad[7]}; - else if (input0Rank == 3) // WC => W_C - layer.pad = new[] { layer.pad[1], 0, layer.pad[2], 0, layer.pad[3], layer.pad[5] }; - } - else - { - int autopad = -(int)(autopadOption); - layer.pad = new[] { autopad, autopad, autopad, autopad }; - } - switch (layer.axis) - { - case 0: - layer.type = Layer.Type.Border2D; - break; - case 1: - layer.type = Layer.Type.Pad2DReflect; - break; - case 2: - layer.type = Layer.Type.Pad2DEdge; - break; - case 3: - layer.type = Layer.Type.Pad2DSymmetric; - break; - } - layer.axis = -1; - return true; - } - else if (input0Rank == 5) - { - // DHWC => WHDC - layer.pad = new[] { layer.pad[3], layer.pad[2], layer.pad[1], layer.pad[4], layer.pad[8], layer.pad[7], layer.pad[6], layer.pad[9] }; - layer.type = Layer.Type.Border3D; - return true; - } - - throw new Exception($"Unsuported Pad layer, {layer.name}"); - } - - static int[] SqueezeAxisPermutationForMappingNHWCLayoutToBarracuda(int onnxRank, int onnxAxis) - { - var identity = new[] { 0, 1, 2, 3 }; - - if (onnxRank == 4) - { - // N,H,W,C -> _,H,W,C => H,_,W,C - // -> N,_,W,C ok - // -> N,H,_,C => N,_,H,C - // -> N,H,W,_ => N,_,H,W - if (onnxAxis == 0) - identity = new[] { 1, 0, 2, 3 }; - else if (onnxAxis == 2) - identity = new[] { 0, 2, 1, 3 }; - else if (onnxAxis == 3) - identity = new[] { 0, 3, 1, 2 }; - } - else if (onnxRank == 3) - { - - // N,_,W,C -> _,_,W,C => W,_,_,C - // -> N,_,_,C ok - // -> N,_,W,_ => N,_,_,W - if (onnxAxis == 0) - identity = new[] { 2, 0, 1, 3 }; - else if (onnxAxis == 2) - identity = new[] { 0, 1, 3, 2 }; - } - else if (onnxRank == 2) - { - // N,_,_,C -> N,_,_,_ ok - // -> _,_,_,C => N,_,_,_ - if (onnxAxis == 1) - identity = new[] { 3, 0, 1, 2 }; - } - - return identity; - } - - static int[] UnSqueezeAxisPermutationForMappingNHWCLayoutToBarracuda(int onnxRank, int onnxAxis) - { - var identity = new[] { 0, 1, 2, 3 }; - - if (onnxRank == 3) - { - // N,_,W,C -> 1,N,W,C - // -> N,1,W,C => ok - // -> N,W,1,C - // -> N,W,C,1 - if (onnxAxis == 0) - identity = new[] { 1, 0, 2, 3 }; - else if (onnxAxis == 2) - identity = new[] { 0, 2, 1, 3 }; - else if (onnxAxis == 3) - identity = new[] { 0, 2, 3, 1 }; - } - else if (onnxRank == 2) - { - // N,_,_,C -> 1,_,N,C - // -> N,_,1,C => ok - // -> N,_,C,1 - if (onnxAxis == 0) - identity = new[] { 1, 2, 0, 3 }; - else if (onnxAxis == 2) - identity = new[] { 0, 1, 3, 2 }; - } - else if (onnxRank == 1) - { - // N,_,_,_ -> 1,_,_,N - // -> N,_,_,1 => ok - if (onnxAxis == 0) - identity = new[] { 1, 2, 3, 0 }; - } - - return identity; - } - - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNHWCToNHWC.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNHWCToNHWC.cs.meta deleted file mode 100644 index ec3287e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWC/RewriterNHWCToNHWC.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 69c649a63d4f5964fa34e962dd287cf8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWCPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWCPass.cs deleted file mode 100644 index be8c254..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWCPass.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Unity.Barracuda.Compiler.Passes -{ - partial class NCHWToNHWCPass : IModelPass - { - IDictionary m_RanksByName; - IDictionary m_ShapesByName; - - // NHWC models, layout re-ordering - bool m_isModelExportedFromNHWC; - Dictionary m_layersChannelOrder; - - readonly BurstCPUOps m_Ops = new BurstCPUOps(); - - static readonly int[] k_FromNHWCtoNCHW = { 0, 3, 1, 2 }; - static readonly int[] k_FromNCHWtoNHWC = { 0, 2, 3, 1 }; - static readonly int[] k_FromNCHtoN1WC = { 0, 3, 2, 1 }; - static readonly int[] k_FromN1WCtoNCH = { 0, 3, 2, 1 }; - readonly int[] k_ToNCHW = { 0, 3, 1, 2 }; - readonly int[] k_ToNHWC = { 0, 2, 3, 1 }; - - public void Run(ref Model model) - { - if (!model.layout.Contains("NCHW")) - return; - - // This is a necessary pass for NCHW models that have the layout built into the model itself (e.g. SSD) - // It's necessary to contract this into a single layer, so that the Gather pass doesn't get converted - var shapeContractionPass = new ShapeContractionPass(); - shapeContractionPass.Run(ref model); - - // Remove shape-gather-reshape pattern when they map a transpose to NHWC operation - var shapeGatherReshapeToNHWCRemovePass = new ShapeGatherReshapeToNHWCRemovePass(); - shapeGatherReshapeToNHWCRemovePass.Run(ref model); - - Rewrite(ref model); - - // Preserve any new layers that must be preserved (e.g. new LSTM outputs) - // TODO: outputs are preserved, adjust optimization passes to properly merge outputs by renaming layers - var preserveLayersPass = new PreserveLayersPass(); - preserveLayersPass.Run(ref model); - - // cleanup - var removeUnusedPass = new Cleanup.RemoveUnusedLayersPass(); - removeUnusedPass.Run(ref model); - var removeNoOpPass = new Cleanup.RemoveNoOpsPass(); - removeNoOpPass.Run(ref model); - } - - void Rewrite(ref Model model) - { - IRShapeInferenceHelper.RankInference.ListTemporaryTensorRanks(model, out m_RanksByName); - var inputShapes = new Dictionary(); - foreach (var i in model.inputs) - { - if (!ModelAnalyzer.IsInputShapeAcceptablyKnowForShapeInference(i)) - continue; - inputShapes.Add(i.name, new TensorShape(i.shape)); - } - - IRShapeInferenceHelper.ShapeInference.ListTemporaryTensorShapesNCHW(model, inputShapes, ref m_RanksByName, out m_ShapesByName); - - var nhwc = model.ShallowCopy(); - nhwc.layers.Clear(); - nhwc.layout = "NHWC"; - - // TF2ONNX transpose pattern -> part of the model are in NHWC and not NCHW - // * identify those - // * transpose inputs to NCHW - // * remove layout transposes - // * convert axis/constants accordingly - LayoutTransposeRemovalHelper transposeRemoval = new LayoutTransposeRemovalHelper(); - m_isModelExportedFromNHWC = transposeRemoval.InferAllLayersChannelOrder(model, out m_layersChannelOrder); - - if (m_isModelExportedFromNHWC && !transposeRemoval.IsImporterLikelyNHWCLayout(model.ProducerName)) - nhwc.Warnings.Add(new Model.ImporterWarning("model", "model detected as NCHW, but not natively in this layout, behavior might be erroneous")); - - // remove layout change transposes - if (m_isModelExportedFromNHWC) - transposeRemoval.RemoveAllChannelLayoutTransposes(ref model, m_layersChannelOrder); - - var modelBuilder = new ModelBuilder(nhwc); - - for (int i = 0; i < nhwc.inputs.Count; i++) - { - Model.Input input = nhwc.inputs[i]; - - int[] shape = input.shape; - var tensorShape = new TensorShape(shape); - int[] rankPermutations = GetChannelsLastPermutationsFromRank(input.rank); - int[] permutations = tensorShape.Get8DPermutationsForNCHWPermutationsAndShape(rankPermutations); - - // Preserve symbolic shape by operating on int array instead of TensorShape, which would resolve unknown dimensions - if (m_isModelExportedFromNHWC) // transpose input shape if importer preserved NHWC layout - { - if (m_layersChannelOrder[input.name] == LayoutTransposeRemovalHelper.ChannelsOrder.NCHW) - input.shape = TensorExtensions.Permute(shape, permutations); - else - { - var onnxShape = new List { shape[2], shape[5], shape[6], shape[7] }; - onnxShape.RemoveRange(input.rank, 4 - input.rank); - input.shape = IRShapeInferenceHelper.ShapeInference.BarracudaLayoutToTensorShapeLayout(onnxShape.ToArray()); - } - } - else - { - input.shape = TensorExtensions.Permute(shape, permutations); - } - nhwc.inputs[i] = input; - } - - // NCHW -> Barracuda NHWC rewriter (some layer need to insert aditional layers to be Barracuda compatible) - var rewriters = InstantiateRewriterNCHWToNHWC(); - // NHWC -> Barracuda NHWC rewriter (axis and constant padding padding) - var rewritersNHWC = InstantiateRewriterNHWCToNHWC(); - - - foreach (var l in model.layers) - { - // Some nodes output multiple layers (e.g. LSTM), so don't process or include those layers - if (nhwc.layers.Exists(alreadyOutputLayer => alreadyOutputLayer.name == l.name)) - continue; - - if (m_layersChannelOrder.TryGetValue(l.name, out LayoutTransposeRemovalHelper.ChannelsOrder layerChannelOrder)) - { - if (m_isModelExportedFromNHWC && (layerChannelOrder == LayoutTransposeRemovalHelper.ChannelsOrder.NHWC)) - { - if (!rewritersNHWC.TryGetValue(l.type, out Func rwNCHW) || rwNCHW(l, modelBuilder)) - { - nhwc.layers.Add(l); - } - continue; - } - } - - if (!rewriters.TryGetValue(l.type, out Func rw) || rw(l, modelBuilder)) - { - // Either no re-write was needed or the layer was not replaced - nhwc.layers.Add(l); - } - } - - // We need to correct constants to have broadcast work correctly - // ONNX: 1,64,32 + c:32 - // Barracuda: 1,_32,64 + c:_,_,32,64 and not c:32,_,_,_ - // X:5,7 + c: 6,9,5,7 = 6,9,5,7 - // X: 5,_,_,7 + c: 6,5,7,9 = ??? - CorrectConstantsForBroadCast(ref nhwc); - CorrectDynamicInputsForBroadCast(ref nhwc); - - // for NHWC importers, perform slightly more aggressive output shape check - // => add transposes to match onnx layout - if (transposeRemoval.IsImporterLikelyNHWCLayout(model.ProducerName)) - CorrectOutputLayoutToMatchNHWCLayout(ref nhwc); - - model = nhwc; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWCPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWCPass.cs.meta deleted file mode 100644 index 783c650..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/NCHWToNHWCPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 22c42c4d140db864c84e0f9efee4d01d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/PreserveLayersPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/PreserveLayersPass.cs deleted file mode 100644 index f735776..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/PreserveLayersPass.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace Unity.Barracuda.Compiler.Passes -{ - class PreserveLayersPass : IModelPass - { - public void Run(ref Model model) - { - // outputs and memories can be queried by the user, make sure they are not removed - IEnumerable preserve = model.memories.Select(mem => mem.input).Concat( - model.memories.Select(mem => mem.output)).Concat( - model.outputs); - - foreach (Layer l in model.layers) - { - if (preserve.Contains(l.name)) - l.flags |= Layer.Flags.Preserve; - } - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/PreserveLayersPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/PreserveLayersPass.cs.meta deleted file mode 100644 index 2ae444b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/PreserveLayersPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: edfae13b2fedf854ab642fe6b76c7e9c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveNoOpsPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveNoOpsPass.cs deleted file mode 100644 index 9785d67..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveNoOpsPass.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes.Cleanup -{ - // TODO remove useless patterns: - // Reduce keepdim 0 -> * -> Reshape - class RemoveNoOpsPass : IModelPass - { - public void Run(ref Model model) - { - var noopLayers = new List(); - var remap = new Dictionary(); - - // algorithm: - // - if input is pointing to a noop, we need to remap it to upstream layer - // - if layer is a noop, store its link to upstream layer - // layers are in order of appearance, so if layer_N has layer_M as input, we'd have treated layer_M before - for (int l = 0; l < model.layers.Count; ++l) - { - var layer = model.layers[l]; - - // replace removed layers with their upstream inputs - for (int i = 0; i < layer.inputs.Length; ++i) - { - var input = layer.inputs[i]; - if (remap.ContainsKey(input)) - { - Assert.IsTrue(noopLayers.Any(x => input == x.name)); - model.layers[l].inputs[i] = remap[input]; - } - else - { - Assert.IsFalse(noopLayers.Any(x => input == x.name)); - } - } - - if (layer.flags.HasFlag(Layer.Flags.Preserve)) - continue; - - if (layer.inputs.Length == 0) // const - continue; - - // if layer is noop = nop, identity or flatten - if (IsLayerNoop(layer)) - { - Assert.IsTrue(layer.inputs.Length == 1); // noop layers have only 1 input - remap[layer.name] = layer.inputs[0]; - noopLayers.Add(layer); - } - } - - foreach (var l in noopLayers) - { - model.layers.Remove(l); - } - } - - public static bool IsPermutationNoop(int[] permutations) - { - for (int i = 0; i < permutations.Length; ++i) - if (permutations[i] != i) - return false; - return true; - } - - public static bool IsLayerNoop(Layer layer) - { - // LSTM outputs, TODO remove? - // TODO: move this in IsLayerLSTMRelated - if (layer.activation == Layer.Activation.None && layer.pad.Length > 0 - && layer.name.IndexOf("lstm", StringComparison.OrdinalIgnoreCase) >= 0) - { - return false; - } - - return layer.type == Layer.Type.Nop || - (layer.type == Layer.Type.Activation && layer.activation == Layer.Activation.None) || - (layer.type == Layer.Type.Transpose && IsPermutationNoop(layer.pool) || - (layer.type == Layer.Type.StridedSlice - // Nothing is actually being done in this case since it is the full range with single stepping, so skip it - && layer.pad.All(s => s == 0) - && layer.pool.All(e => e == int.MaxValue) - && layer.stride.All(s => s == 1))) || - (layer.type == Layer.Type.Transpose && Enumerable.SequenceEqual(layer.pool, new [] { 0, 1, 2, 3 })) || - (layer.type == Layer.Type.Expand && layer.inputs.Length == 1 && layer.pool.Length >= 1 && layer.pool.All(x => x == 1)); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveNoOpsPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveNoOpsPass.cs.meta deleted file mode 100644 index ff6cb7a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveNoOpsPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: da0d3719f9b7a194a8df593fce83d6f5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveUnusedLayersPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveUnusedLayersPass.cs deleted file mode 100644 index 3ab5c48..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveUnusedLayersPass.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Unity.Barracuda.Compiler.Passes.Cleanup -{ - class RemoveUnusedLayersPass : IModelPass - { - public void Run(ref Model model) - { - // TODO: strip layers not useful to compute output - // Strip unused layers - var unusedLayers = new HashSet(ModelAnalyzer.FindUnusedLayers(model)); - model.layers = model.layers.Where(l => !unusedLayers.Contains(l.name) || l.flags.HasFlag(Layer.Flags.Preserve)).ToList(); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveUnusedLayersPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveUnusedLayersPass.cs.meta deleted file mode 100644 index 9fc47bc..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/RemoveUnusedLayersPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6864735d494102c4fada3c3fe22d3fb7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeContractionPass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeContractionPass.cs deleted file mode 100644 index bfdd05f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeContractionPass.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes -{ - class ShapeContractionPass : IModelPass - { - public void Run(ref Model model) - { - if (!model.layout.Contains("NCHW")) - return; - - var remap = new Dictionary(); - - for (int l = 1; l < model.layers.Count; ++l) - { - var previousLayer = model.layers[l - 1]; - var layer = model.layers[l]; - - if (layer.flags.HasFlag(Layer.Flags.Preserve)) - continue; - - string[] layerInputs = layer.inputs; - for (int i = 0; i < layerInputs.Length; i++) - { - if (remap.TryGetValue(layerInputs[i], out string replacement)) - layerInputs[i] = replacement; - } - - if (previousLayer.type == Layer.Type.Shape - && layer.type == Layer.Type.Gather) - { - string indicesInput = layer.inputs[1]; - var indicesConstant = model.layers.FirstOrDefault(c => c.type == Layer.Type.Load && c.name == indicesInput); - if (indicesConstant != null) - { - Tensor indices = indicesConstant.DataSetToTensor(0); - if (indices.length == 1) // Shape only supports selecting one axis in place of the full shape - { - // Update the axis on the shape layer - previousLayer.axis = (int)indices[0]; - remap[layer.name] = previousLayer.name; - } - } - } - else if (previousLayer.type == Layer.Type.Shape - && layer.type == Layer.Type.ConstantOfShape) - { - layer.axis = 1; - layer.type = Layer.Type.ConstantOfShape; - layer.inputs[0] = previousLayer.inputs[0]; - remap[previousLayer.name] = layer.name; - } - } - - var removeLayers = remap.Keys; - model.layers.RemoveAll(l => removeLayers.Contains(l.name)); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeContractionPass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeContractionPass.cs.meta deleted file mode 100644 index fbadd1c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeContractionPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a33f6918081491c45bea5a64ca000f10 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeGatherReshapeToNHWCRemovePass.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeGatherReshapeToNHWCRemovePass.cs deleted file mode 100644 index 0bc8754..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeGatherReshapeToNHWCRemovePass.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda.Compiler.Passes -{ - class ShapeGatherReshapeToNHWCRemovePass : IModelPass - { - public void Run(ref Model model) - { - if (!model.layout.Contains("NCHW")) - return; - - var layersToRemove = new List(); - - for (int l = 2; l < model.layers.Count; ++l) - { - if (model.layers[l - 2].type != Layer.Type.Shape || - model.layers[l - 1].type != Layer.Type.Gather || - model.layers[l - 0].type != Layer.Type.Reshape) - continue; - - var shapeLayer = model.layers[l - 2]; - var gatherLayer = model.layers[l - 1]; - var reshapeLayer = model.layers[l - 0]; - - if (shapeLayer.flags.HasFlag(Layer.Flags.Preserve) || - gatherLayer.flags.HasFlag(Layer.Flags.Preserve)) - continue; - - //Is reshape using gather as input? - if (reshapeLayer.inputs[1] != gatherLayer.name) - continue; - - //Is gather using shape as input? - if (gatherLayer.inputs[0] != shapeLayer.name) - continue; - - //Are those layer used by other node of the model? - if (!CanLayerBeRemoved(shapeLayer, gatherLayer, model) || - !CanLayerBeRemoved(gatherLayer, reshapeLayer, model)) - continue; - - //Is gather converting that shape to channel last? - if (!IsGather1DAndConvertingToChannelLast(gatherLayer, model)) - continue; - - //Then those three layer are equivalent to a transpose to channel last. - //this transpose is itself not needed as we are converting to channel last. - //so we can just replace those three layers by a single identity. - reshapeLayer.type = Layer.Type.Activation; - reshapeLayer.activation = Layer.Activation.None; - reshapeLayer.pool = new int[0]; - reshapeLayer.axis = -1; - reshapeLayer.inputs = shapeLayer.inputs; - - layersToRemove.Add(shapeLayer.name); - layersToRemove.Add(gatherLayer.name); - } - - model.layers.RemoveAll(l => layersToRemove.Contains(l.name)); - } - - bool IsGather1DAndConvertingToChannelLast(Layer gatherLayer, Model model) - { - Assert.AreEqual(Layer.Type.Gather,gatherLayer.type); - if (gatherLayer.axis > 0) - return false; - - var indicesAsConstants = model.layers.FirstOrDefault(c => c.type == Layer.Type.Load && c.name == gatherLayer.inputs[1]); - if (indicesAsConstants == null) - return false; - - var indices = indicesAsConstants.DataSetToTensor(0).ToReadOnlyArray(); - if (Enumerable.SequenceEqual(indices, new float[] { 0, 2, 3, 1 }) || - Enumerable.SequenceEqual(indices, new float[] { 0, 1, 2, 4, 5, 6, 7, 3 })) - return true; - - return false; - } - - bool CanLayerBeRemoved(Layer layerToRemove, Layer acceptedChildLayer, Model model) - { - if (model.outputs.Contains(layerToRemove.name)) - return false; - - if (model.memories.Exists(m => m.output == layerToRemove.name)) - return false; - - //Need to check that no other layers use layerToRemove but the one accepted child that we will process. - if (model.layers.Exists(l => l != acceptedChildLayer && l.inputs.Contains(layerToRemove.name))) - return false; - - return true; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeGatherReshapeToNHWCRemovePass.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeGatherReshapeToNHWCRemovePass.cs.meta deleted file mode 100644 index 4334828..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ShapeGatherReshapeToNHWCRemovePass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d603705facc410c4b92cfceef364ec25 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ValidatePasses.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ValidatePasses.cs deleted file mode 100644 index 598a8b4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ValidatePasses.cs +++ /dev/null @@ -1,248 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; -using UnityEditor; - -namespace Unity.Barracuda.Compiler.Passes -{ - internal enum MessageType - { - None = 0, - Info = 1, - Warning = 2, - Error = 3 - } - - class ValidationHelper - { - public static void AppendWarning(bool condition, string layer, string message, ref List warnings, MessageType level = MessageType.Info) - { - if (!condition) - warnings?.Add(new Model.ImporterWarning(layer, $"MessageType.{(int)level}" + message)); - } - } - - class ValidateNCHWShapesPass : IValidateModelPass - { - public void Run(Model model, ref List warnings) - { - var modelTemp = model.ShallowCopy(); - IDictionary inputShapes = new Dictionary(); - // force batch to 1 - for (int i = 0; i < modelTemp.inputs.Count; i++) - { - var input = modelTemp.inputs[i]; - var shape = input.shape.ToArray(); - if (shape[TensorShape.DataBatch] <= 0) - shape[TensorShape.DataBatch] = 1; - input.shape = shape; - modelTemp.inputs[i] = input; - - if (!ModelAnalyzer.IsInputShapeAcceptablyKnowForShapeInference(input)) - continue; - - inputShapes[input.name] = new TensorShape(input.shape); - } - - ValidationHelper.AppendWarning(inputShapes.Count == modelTemp.inputs.Count, "model", "Input Shape: unkown non batch dimension", ref warnings); - - IRShapeInferenceAndConstantFusing shapeInferencePass = new IRShapeInferenceAndConstantFusing(); - shapeInferencePass.Run(ref modelTemp); - - IDictionary ranksByName; - IRShapeInferenceHelper.RankInference.ListTemporaryTensorRanks(modelTemp, out ranksByName); - IDictionary shapesByName; - IRShapeInferenceHelper.ShapeInference.ListTemporaryTensorShapesNCHW(modelTemp, inputShapes, ref ranksByName, out shapesByName); - - int negativeRanks = ranksByName.Values.Count(x => x < 0); - ValidationHelper.AppendWarning(negativeRanks == 0, "model", $"StaticRankInference: {negativeRanks} negative rank(s) found!", ref warnings, MessageType.Warning); - - int knowRanks = ranksByName.Count(x => x.Value != null); - int knowShapes = shapesByName.Count(x => x.Value != null); - - ValidationHelper.AppendWarning(knowRanks == knowShapes, "model", "StaticShape/RankInference: known ranks # != known shape #", ref warnings); - - foreach (var i in modelTemp.inputs) - { - var name = i.name; - ValidationHelper.AppendWarning(ranksByName.ContainsKey(name), name, "StaticRankInference: did not find input", ref warnings); - if (ranksByName.ContainsKey(name)) - ValidationHelper.AppendWarning(ranksByName[name] != null, name, "StaticRankInference: unknown input rank at compile time", ref warnings); - - ValidationHelper.AppendWarning(shapesByName.ContainsKey(name), name, "StaticShapeInference: did not find input", ref warnings); - if (shapesByName.ContainsKey(name)) - ValidationHelper.AppendWarning(shapesByName[name] != null, name, "StaticShapeInference: unknown input shape for at compile time", ref warnings); - } - foreach (var l in modelTemp.layers) - { - var name = l.name; - ValidationHelper.AppendWarning(ranksByName.ContainsKey(name), name, "StaticRankInference: did not find layer", ref warnings); - if (ranksByName.ContainsKey(name)) - ValidationHelper.AppendWarning(ranksByName[name] != null, name, "StaticRankInference: unknown layer rank at compile time", ref warnings); - - ValidationHelper.AppendWarning(shapesByName.ContainsKey(name), name, "StaticShapeInference: did not find layer", ref warnings); - if (shapesByName.ContainsKey(name)) - ValidationHelper.AppendWarning(shapesByName[name] != null, name, "StaticShapeInference: unknown layer shape at compile time", ref warnings); - } - } - } - - class ValidateIntermediateNCHWModelLayers : IValidateModelPass - { - public void Run(Model model, ref List warnings) - { - foreach (var l in model.layers) - { - var name = l.name; - var type = l.type; - if(type == Layer.Type.Upsample2D) - { - if (l.inputs.Length == 2) - continue; // dynamic Upsample - - var sizes = l.pool; - if (sizes != null) - ValidationHelper.AppendWarning((sizes[0] == 1) && (sizes[1] == 1), name, "ValidateIntermediateNCHWModelLayers:Upsample2D Only spatial(H and W) resizing is currently supported." + - " Non spatial sizes (N and C) will be ignored and default to identity.", ref warnings); - } - else if (type == Layer.Type.Upsample3D) - { - if (l.inputs.Length == 2) - continue; // dynamic Upsample - - var sizes = l.pool; - if (sizes != null) - ValidationHelper.AppendWarning((sizes[0] == 1) && (sizes[1] == 1), name, "ValidateIntermediateNCHWModelLayers:Upsample3D Only spatial(H and W) resizing is currently supported." + - " Non spatial sizes (N and C) will be ignored and default to identity.", ref warnings); - } - else if (type == Layer.Type.Range) - { - ValidationHelper.AppendWarning(true, name, "ValidateIntermediateNCHWModelLayers::Range only const inputs supported", ref warnings, MessageType.Error); - } - else if (type == Layer.Type.StridedSlice) - { - int[] starts = l.pad; int[] ends = l.pool; int[] strides = l.stride; - for (int i = 0; i < starts.Length; i++) - { - if (strides[i] == 0) - ValidationHelper.AppendWarning(true, name, "ValidateIntermediateNCHWModelLayers::StridedSlice strides=0 will result in slicing the whole tensor", ref warnings, MessageType.Warning); - if(starts[i] == 0 && ends[i] == 0) - ValidationHelper.AppendWarning(true, name, "ValidateIntermediateNCHWModelLayers::StridedSlice starts=0 && ends=0 will result in slicing whole tensor and not empty tensor", ref warnings, MessageType.Warning); - } - } - else if (type == Layer.Type.Unsqueeze) - { - ValidationHelper.AppendWarning(l.inputs.Length == 1, name, "ValidateIntermediateNCHWModelLayers::Unsqueeze unsupported dynamic Unsqueeze, axes must be constant", ref warnings, MessageType.Warning); - } - else if (type == Layer.Type.Squeeze) - { - ValidationHelper.AppendWarning(l.inputs.Length == 1, name, "ValidateIntermediateNCHWModelLayers::Unsqueeze unsupported dynamic Squeeze, axes must be constant", ref warnings, MessageType.Warning); - } - } - } - } - - class ValidateBrokenLinksPass : IValidateModelPass - { - private static string[] FindBrokenLinks(Model model, HashSet links) - { - var allVariables = new HashSet(model.layers.Select(i => i.name)); - var globalInputs = new HashSet(model.inputs.Select(i => i.name)); - var memoryInputs = new HashSet(model.memories.Select(i => i.input)); - allVariables.UnionWith(globalInputs); - allVariables.UnionWith(memoryInputs); - - var brokenLinks = links; - brokenLinks.ExceptWith(allVariables); - return brokenLinks.ToArray(); - } - - private static string[] FindBrokenLinks(Model model, string[] links) - { - return FindBrokenLinks(model, new HashSet(links)); - } - - public static string[] FindBrokenLinks(Model model) - { - // check global outputs - var linksToInspect = new HashSet(model.outputs); - - // and all layers - foreach (var layer in model.layers) - foreach (var i in layer.inputs) - linksToInspect.Add(i); - - return FindBrokenLinks(model, linksToInspect); - } - - public void Run(Model model, ref List warnings) - { - // Model should not contain any broken links in the end - var unconnectedInputs = FindBrokenLinks(model); - if (unconnectedInputs.Length > 0) - { - foreach (var x in unconnectedInputs) - ValidationHelper.AppendWarning(false, x, "ValidateBrokenLinks: broken Links : ", ref warnings, MessageType.Warning); - } - } - } - - class ValidateUniqueOutputsPass : IValidateModelPass - { - public void Run(Model model, ref List warnings) - { - // validate, all model outputs are unique - // https://stackoverflow.com/questions/18547354/c-sharp-linq-find-duplicates-in-list - var duplicateOutputs = model.outputs.GroupBy(x => x) - .Where(g => g.Count() > 1) - .Select(y => y.Key); - foreach (var o in duplicateOutputs) - ValidationHelper.AppendWarning(false, o, "ValidateUniqueOutputs: Output is specified more than once in the model", ref warnings, MessageType.Warning); - } - } - - class ValidateUnconectedLayersPass : IValidateModelPass - { - public void Run(Model model, ref List warnings) - { - // validate, model contains no unconnected layers - var unconnectedOutputs = ModelAnalyzer.FindUnconnectedOutputs(model); - foreach (var o in unconnectedOutputs) - ValidationHelper.AppendWarning(false, o, "ValidateUnconnectedLayers: Layer is specified as output, but is missing in the model", ref warnings, MessageType.Warning); - } - } - - class ValidateNCHWPass : IValidateModelPass - { - public void Run(Model model, ref List warnings) - { - var validatePasses = new List - { - new ValidateNCHWShapesPass(), - new ValidateIntermediateNCHWModelLayers(), - new ValidateUniqueOutputsPass(), - new ValidateUnconectedLayersPass() - }; - - foreach (var validate in validatePasses) - validate.Run(model, ref warnings); - } - } - - class ValidateNHWCPass : IValidateModelPass - { - public void Run(Model model, ref List warnings) - { - var validatePasses = new List - { - new ValidateUniqueOutputsPass(), - new ValidateUnconectedLayersPass() - }; - - foreach (var validate in validatePasses) - validate.Run(model, ref warnings); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ValidatePasses.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ValidatePasses.cs.meta deleted file mode 100644 index 897a443..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/Passes/ValidatePasses.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c603a83833a737b4fa1d41b43f3048d6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference.meta deleted file mode 100644 index 13fbee8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 57c0ae307895bb741887efd1c8b77371 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRRankInferenceHelper.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRRankInferenceHelper.cs deleted file mode 100644 index 7a9d97f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRRankInferenceHelper.cs +++ /dev/null @@ -1,361 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; - -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; - -namespace Unity.Barracuda.Compiler.IRShapeInferenceHelper -{ - internal class RankInference - { - static public int? InferOutputRank(Layer layer, int?[] inputRanks, TensorShape?[] inputShapes) - { - switch (layer.type) - { - case Layer.Type.Dense: - { - Assert.AreEqual(inputRanks.Length, 1, "InferOutputRank.Dense inputRanks.Length"); - return 2; - } - case Layer.Type.MatMul: - { - if (inputRanks.Length != 2) - return null; - if (inputRanks.Any(x => x == null)) - return null; - return inputRanks.Max(); - } - case Layer.Type.Conv3D: - { - if (inputRanks[0] == null) - return null; - - Assert.AreEqual(inputRanks.Length, 1, "InferOutputRank.*Conv3D* inputRanks.Length"); Assert.IsTrue(inputRanks[0].Value >= 2 && inputRanks[0].Value <= 5, "InferOutputRank.*Conv3D* inputRanks"); - return inputRanks[0]; - } - case Layer.Type.Conv2D: - case Layer.Type.DepthwiseConv2D: - case Layer.Type.Conv2DTrans: - { - if (inputRanks[0] == null) - return null; - - Assert.AreEqual(inputRanks.Length, 1, "InferOutputRank.*Conv2D* inputRanks.Length"); Assert.IsTrue(inputRanks[0].Value >= 2 && inputRanks[0].Value <= 4, "InferOutputRank.*Conv2D* inputRanks"); // conv1D/2D are done via conv2D - return inputRanks[0]; - } - case Layer.Type.DepthToSpace: - case Layer.Type.SpaceToDepth: - { - if (inputRanks[0] == null) - return null; - - Assert.AreEqual(inputRanks.Length, 1, "InferOutputRank.ToDepth/Space inputRanks.Length"); Assert.AreEqual(inputRanks[0].Value, 4, "InferOutputRank.ToDepth/Space inputRanks"); - return 4; - } - case Layer.Type.Upsample3D: - { - if (inputRanks[0] == null) - return null; - - Assert.AreEqual(inputRanks[0].Value, 5, "InferOutputRank.*Upsample3D inputRanks"); - return 5; - } - case Layer.Type.Upsample2D: - case Layer.Type.Resample2D: - { - if (inputRanks[0] == null) - return null; - - Assert.AreEqual(inputRanks[0].Value, 4, "InferOutputRank.*Upsample2D inputRanks"); - return 4; - } - case Layer.Type.MaxPool2D: - case Layer.Type.AvgPool2D: - { - if (inputRanks[0] == null) - return null; - - Assert.IsTrue(inputRanks[0].Value == 4 || inputRanks[0].Value == 3, "InferOutputRank.*Pool2D inputRanks"); - return inputRanks[0]; - } - case Layer.Type.GlobalMaxPool2D: - case Layer.Type.GlobalAvgPool2D: - { - if (inputRanks[0] == null) - return null; - - Assert.AreEqual(inputRanks.Length, 1, "InferOutputRank.Global*Pool2D inputRanks.Length"); Assert.IsTrue(inputRanks[0].Value == 4 || inputRanks[0].Value == 3, "InferOutputRank.Global*Pool2D inputRanks"); - return inputRanks[0]; - } - case Layer.Type.Pad: - return inputRanks[0]; - case Layer.Type.RandomNormal: - case Layer.Type.RandomUniform: - { - if (layer.pool.Length > 0) - return layer.pool.Length; - else - { - Assert.AreEqual(inputRanks.Length, 1, "InferOutputRank.*Random inputRanks.Length"); - return inputRanks[0]; - } - } - case Layer.Type.Multinomial: - return 2; - case Layer.Type.OneHot: - { - if (inputRanks[0] == null) - return null; - - Assert.AreEqual(inputRanks.Length, 1, "InferOutputRank.OneHot inputRanks.Length"); - return inputRanks[0] + 1; - } - case Layer.Type.RoiAlign: - return 4; - case Layer.Type.LSTM: - return 4; - case Layer.Type.Add: - case Layer.Type.Sub: - case Layer.Type.Mul: - case Layer.Type.Div: - case Layer.Type.Pow: - case Layer.Type.Min: - case Layer.Type.Max: - case Layer.Type.Mean: - case Layer.Type.Greater: - case Layer.Type.GreaterEqual: - case Layer.Type.Less: - case Layer.Type.LessEqual: - case Layer.Type.Equal: - case Layer.Type.LogicalOr: - case Layer.Type.LogicalAnd: - case Layer.Type.LogicalXor: - { - if (inputRanks.Any(x => x == null)) - return null; - return inputRanks.Max(); - } - case Layer.Type.Range: - { - return 1; - } - case Layer.Type.ReduceL1: - case Layer.Type.ReduceL2: - case Layer.Type.ReduceLogSum: - case Layer.Type.ReduceLogSumExp: - case Layer.Type.ReduceMax: - case Layer.Type.ReduceMean: - case Layer.Type.ReduceMin: - case Layer.Type.ReduceProd: - case Layer.Type.ReduceSum: - case Layer.Type.ReduceSumSquare: - case Layer.Type.ArgMax: - case Layer.Type.ArgMin: - { - if (inputRanks[0] == null) - return null; - if (layer.alpha != 1.0f) - return inputRanks[0] - 1; - else - return inputRanks[0]; - } - case Layer.Type.Flatten: - return 2; - case Layer.Type.ConstantOfShape: - { - if(layer.axis == 1) - return inputRanks[0]; - - if (inputRanks.Length == 1) - { - if (inputShapes[0] != null) - return (inputShapes[0].Value)[TensorShape.DataBatch]; - else - return null; - } - else - return layer.pool.Length; - } - case Layer.Type.Reshape: - { - if (inputShapes.Length == 2 && inputShapes[1] != null) - return (inputShapes[1].Value)[TensorShape.DataBatch]; - - if (inputRanks.Length > 1) - // shape is in the tensor and calculated at runtime, so we can't know it - return null; - - if (layer.pad.Length > 0) - return layer.pad[0]; // original rank stored here - - return layer.pool.Length; - } - case Layer.Type.Expand: - { - if (inputRanks.Length > 1) - return null; - - if(inputRanks[0] == null) - return null; - - return Mathf.Max(inputRanks[0].Value, layer.pool.Length); - } - case Layer.Type.Transpose: - return inputRanks[0]; - case Layer.Type.Gather: - { - if (inputRanks.Length != 2) - return null; - - if (inputRanks[0] == null) - return null; - - if (inputRanks[1] == null) - return null; - - // Gather can implicitly do a squeeze in inputs are single int - // we don't but instead append a squeeze op after Gather if that is the case - return inputRanks[0] + Mathf.Max(inputRanks[1].Value, 1) - 1; - } - case Layer.Type.ScatterND: - return inputRanks[0]; - case Layer.Type.TopKIndices: - case Layer.Type.TopKValues: - return inputRanks[0]; - case Layer.Type.NonMaxSuppression: - return 2; - case Layer.Type.NonZero: - return 2; - case Layer.Type.Squeeze: - { - if (inputRanks.Length > 1) - return null; - - if(inputRanks[0] == null) - return null; - - return inputRanks[0].Value - layer.pool.Length; - } - case Layer.Type.Unsqueeze: - { - if (inputRanks.Length > 1) - return null; - - if(inputRanks[0] == null) - return null; - - return inputRanks[0].Value + layer.pool.Length; - } - case Layer.Type.Concat: - { - if (inputRanks.Any(x => x == null)) - return null; - - int rank = 0; - - for (int i = 0; i < inputRanks.Length; i++) - { - if (inputRanks[i] != null) - rank = Math.Max(rank, inputRanks[i].Value); - } - - return rank; - } - case Layer.Type.StridedSlice: - // TODO : figure out if slice can produce lower rank output - return inputRanks[0]; - case Layer.Type.Tile: - return inputRanks[0]; - case Layer.Type.Load: - { - if (layer.datasets[0].length == 1 && layer.axis == 1) - return 0; // TODO const float vs [float] maybe override rank in ONNXTensor - return layer.axis; - } - case Layer.Type.Nop: - case Layer.Type.ScaleBias: - case Layer.Type.Normalization: - case Layer.Type.LRN: - case Layer.Type.Dropout: - case Layer.Type.LogicalNot: - case Layer.Type.Sign: - case Layer.Type.Where: - { - return inputRanks[0]; - } - case Layer.Type.Activation: - { - // For convenience we sometimes use layer.pad to store rank for inference purposes (e.g. LSTMs) - if (layer.activation == Layer.Activation.None && layer.pad.Length > 0) - return layer.pad[0]; - - return inputRanks[0]; - } - case Layer.Type.Shape: - return 1; - default: - return null; - } - } - - // TODO merge List&Update*** - public static void UpdateKnownTensorRanks(Model model, IDictionary ranksByName) - { - foreach (var l in model.layers) - { - TensorShape?[] layerInputShapes = new TensorShape?[l.inputs.Length]; - int?[] layerInputShapeRanks = new int?[l.inputs.Length]; - for (int i = 0; i < l.inputs.Length; i++) - { - ranksByName.TryGetValue(l.inputs[i], out int? irank); - layerInputShapeRanks[i] = irank; - } - - int? outputRank = InferOutputRank(l, layerInputShapeRanks, layerInputShapes); - - if (ranksByName.ContainsKey(l.name) && ranksByName[l.name] != null && outputRank != null) - ranksByName[l.name] = Mathf.Max(ranksByName[l.name].Value, outputRank.Value); - else - ranksByName[l.name] = outputRank; - } - } - - public static int?[] ListTemporaryTensorRanks(Model model, - out IDictionary ranksByName) - { - Profiler.BeginSample("Barracuda.ListTemporaryTensorRanks"); - var ranks = new List(); - ranksByName = new Dictionary(); - foreach (var i in model.inputs) - ranksByName[i.name] = i.rank; - - foreach (var m in model.memories) - ranksByName.Add(m.input, 3); // [num_directions, batch_size, hidden_size] - - foreach (var l in model.layers) - { - TensorShape?[] layerInputShapes = new TensorShape?[l.inputs.Length]; - int?[] layerInputShapeRanks = new int?[l.inputs.Length]; - - for (int i = 0; i < l.inputs.Length; i++) - { - ranksByName.TryGetValue(l.inputs[i], out int? irank); - - layerInputShapeRanks[i] = irank; - } - - int? outputRank = InferOutputRank(l, layerInputShapeRanks, layerInputShapes); - - ranks.Add(outputRank); - ranksByName.Add(l.name, outputRank); - } - - Profiler.EndSample(); - return ranks.ToArray(); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRRankInferenceHelper.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRRankInferenceHelper.cs.meta deleted file mode 100644 index 1d37e6b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRRankInferenceHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7a76aaebdeefbb340909663f40f90984 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRShapeInferenceHelper.cs b/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRShapeInferenceHelper.cs deleted file mode 100644 index 29dce0a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRShapeInferenceHelper.cs +++ /dev/null @@ -1,952 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; - -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; - -namespace Unity.Barracuda.Compiler.IRShapeInferenceHelper -{ - internal class ShapeInference - { - static public int[] BarracudaLayoutToTensorShapeLayout(int[] size) - { - const int _ = 1; - if (size.Length == 0) - return new[] { _, _, 1, _, _, 1, 1, 1 }; - else if (size.Length == 1) - return new[] { _, _, size[0], _, _, 1, 1, 1 }; - else if (size.Length == 2) - return new[] { _, _, size[0], _, _, 1, 1, size[1] }; - else if (size.Length == 3) - return new[] { _, _, size[0], _, _, 1, size[1], size[2] }; - else if (size.Length == 4) - return new[] { _, _, size[0], _, _, size[1], size[2], size[3] }; - else if (size.Length == 5) - return new[] { _, _, size[0], _, size[1], size[2], size[3], size[4] }; - else if (size.Length == 6) - return new[] { _, _, size[0], size[1], size[2], size[3], size[4], size[5] }; - else - return new[] { size[0], size[1], size[2], size[3], size[4], size[5], size[6], size[7] }; - } - static public List BarracudaShapeToOnnxLayout(TensorShape X, int rank) - { - if (rank == 0) - return new List { 1 }; - else if (rank == 1) - return new List { X.batch }; - else if (rank == 2) - return new List { X.batch, X.channels }; - else if (rank == 3) - return new List { X.batch, X.channels, X.width }; - else if (rank == 4) - return new List { X.batch, X.channels, X.height, X.width }; - else if (rank == 5) - return new List { X.batch, X.channels, X.depth, X.height, X.width }; - else if (rank == 6) - return new List { X.batch, X.channels, X.depth, X.extraDimension, X.height, X.width }; - else - return new List { X.sequenceLength, X.numberOfDirections, X.batch, X.extraDimension, X.channels, X.depth, X.height, X.width }; // TODO not sure - } - static public List ShapeToOnnxLayout(TensorShape X, int rank) - { - if (rank == 0) - return new List { 1 }; - else if (rank == 1) - return new List { X.batch }; - else if (rank == 2) - return new List { X.batch, X.height }; - else if (rank == 3) - return new List { X.batch, X.height, X.width }; - else if (rank == 4) - return new List { X.batch, X.height, X.width, X.channels }; - else if (rank == 5) - return new List { X.batch, X.depth, X.height, X.width, X.channels }; - else if (rank == 6) - return new List { X.batch, X.depth, X.extraDimension, X.height, X.width, X.channels }; - else - return new List { X.sequenceLength, X.numberOfDirections, X.batch, X.extraDimension, X.depth, X.height, X.width, X.channels }; - } - - static public int[] OnnxLayoutToTensorShapeLayout(int[] size) // needed to keep -1 and 0 in shape - { - const int _ = 1; - if (size.Length == 0) - return new[] { _, _, 1, _, _, 1, 1, 1 }; - else if (size.Length == 1) - return new[] { _, _, size[0], _, _, 1, 1, 1 }; - else if (size.Length == 2) - return new[] { _, _, size[0], _, _, size[1], 1, 1 }; - else if (size.Length == 3) - return new[] { _, _, size[0], _, _, size[1], size[2], 1 }; - else if (size.Length == 4) - return new[] { _, _, size[0], _, _, size[1], size[2], size[3] }; - else if (size.Length == 5) - return new[] { _, _, size[0], _, size[1], size[2], size[3], size[4] }; - else if (size.Length == 6) - return new[] { _, _, size[0], size[1], size[2], size[3], size[4], size[5] }; - else - return new[] { size[0], size[1], size[2], size[3], size[4], size[5], size[6], size[7] }; - } - - static public TensorShape OnnxLayoutToTensorShape(int[] size) - { - if (size.Length == 0) - return new TensorShape(1, 1, 1, 1); - else if (size.Length == 1) - return new TensorShape(size[0], 1, 1, 1); - else if (size.Length == 2) - return new TensorShape(size[0], size[1], 1, 1); - else if (size.Length == 3) - return new TensorShape(size[0], size[1], size[2], 1); - else if (size.Length == 4) - return new TensorShape(size[0], size[1], size[2], size[3]); - else if (size.Length == 5) - return new TensorShape(size[0], size[1], size[2], size[3], size[4]); - else if (size.Length == 6) - return new TensorShape(1, 1, size[0], size[1], size[2], size[3], size[4], size[5]); - else - return new TensorShape(size[0], size[1], size[2], size[3], size[4], size[5], size[6], size[7]); - } - static public TensorShape OnnxLayoutToBarracudaTensorShape(int[] size) - { - if (size.Length == 0) - return new TensorShape(1, 1, 1, 1); - else if (size.Length == 1) - return new TensorShape(size[0], 1, 1, 1); - else if (size.Length == 2) - return new TensorShape(size[0], 1, 1, size[1]); - else if (size.Length == 3) - return new TensorShape(size[0], 1, size[2], size[1]); - else if (size.Length == 4) - return new TensorShape(size[0], size[2], size[3], size[1]); - else if (size.Length == 5) - return new TensorShape(size[0], size[2], size[3], size[4], size[1]); - else if (size.Length == 6) - return new TensorShape(1, 1, size[0], size[2], size[3], size[4], size[5], size[1]); - else - return new TensorShape(size[0], size[1], size[2], size[4], size[5], size[6], size[7], size[3]); - } - - static public List BarracudaShapeToList(TensorShape X, int rank) - { - if (rank == 0) - return new List { 1 }; - else if (rank == 1) - return new List { X.batch }; - else if (rank == 2) - return new List { X.batch, X.channels }; - else if (rank == 3) - return new List { X.batch, X.width, X.channels }; - else if (rank == 4) - return new List { X.batch, X.height, X.width, X.channels }; - else if (rank == 5) - return new List { X.batch, X.depth, X.height, X.width, X.channels }; - else if (rank == 6) - return new List { X.batch, X.depth, X.extraDimension, X.height, X.width, X.channels }; - else - return new List { X.sequenceLength, X.numberOfDirections, X.batch, X.extraDimension, X.depth, X.height, X.width, X.channels }; - } - - static public int BarracudaAxisToTensor(int axis, int rank) - { - if (rank == 0) - return 0; - else if (rank == 1) - return 0; - else if (rank == 2) - return axis == TensorShape.DataBatch ? 0 : 1; - else if (rank == 3) - return axis == TensorShape.DataBatch ? 0 : axis - TensorShape.W + 1; - else if (rank == 4) - return axis == TensorShape.DataBatch ? 0 : axis - TensorShape.H + 1; - else if (rank == 5) - return axis == TensorShape.DataBatch ? 0 : axis - TensorShape.D + 1; - else if (rank == 6) - return axis == TensorShape.DataBatch ? 0 : axis - TensorShape.DataFeature3 + 1; - else - return axis; - } - - static public TensorShape? InferOutputShapeNCHW(Layer layer, int?[] inputRanks, TensorShape?[] inputShapes) - { - switch (layer.type) - { - case Layer.Type.Conv3D: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - // N C D H W, constructor is N D H W C - // => N = N C = D, D = H, H = W, W = C - // TODO helper function for that - X = new TensorShape(X.batch, X.height, X.width, X.channels, X.depth); - var K = layer.datasets[0].shape; - - Assert.IsNotNull(layer.stride); - Assert.IsNotNull(layer.pad); - var pad = X.AdjustPadToKernel(K, layer.stride, layer.pad); - - var O = X.ApplyKernel(K, layer.stride, pad); - return new TensorShape(O.batch, O.channels, O.depth, O.height, O.width); - } - case Layer.Type.Conv2D: - case Layer.Type.DepthwiseConv2D: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - // N C H W, constructor is N H W C - // => N = N C = H, H = W, H = C - // TODO helper function for that - X = new TensorShape(X.batch, X.width, X.channels, X.height); - var K = layer.datasets[0].shape; - - Assert.IsNotNull(layer.stride); - Assert.IsNotNull(layer.pad); - var pad = X.AdjustPadToKernel(K, layer.stride, layer.pad); - - var O = X.ApplyKernel(K, layer.stride, pad); - return new TensorShape(O.batch, O.channels, O.height, O.width); - } - case Layer.Type.Conv2DTrans: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - // N C H W, constructor is N H W C - // => N = N C = H, H = W, H = C - // TODO helper function for that - X = new TensorShape(X.batch, X.width, X.channels, X.height); - var K = layer.datasets[0].shape; - - Assert.IsNotNull(layer.stride); - Assert.IsNotNull(layer.pad); - // pool size is treated as output_adjustment aka output_padding here - var outputAdjustment = layer.pool; - var pad = X.AdjustPadToKernel(K, layer.stride, layer.pad); - var O = X.ApplyKernelInverse(K, layer.stride, pad, outputAdjustment); - return new TensorShape(O.batch, O.channels, O.height, O.width); - } - case Layer.Type.GlobalMaxPool2D: - case Layer.Type.GlobalAvgPool2D: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - int rankX = inputRanks[0].Value; - List xShape = ShapeToOnnxLayout(X, rankX); - - for (int i = 2; i < xShape.Count; i++) - xShape[i] = 1; - return OnnxLayoutToTensorShape(xShape.ToArray()); - } - case Layer.Type.Dense: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - X = new TensorShape(X.batch, X.width, X.channels, X.height); - Assert.IsNotNull(layer.datasets); - var W = layer.datasets[0].shape; - var O = new TensorShape(X.flatHeight, W.flatWidth); - return new TensorShape(O.batch, O.channels, O.height, O.width); - } - case Layer.Type.MatMul: - { - if(inputShapes[0] == null || inputShapes[1] == null) - return null; - - TensorShape X = inputShapes[0].Value; - int rankX = inputRanks[0].Value; - List xShape = ShapeToOnnxLayout(X, rankX); - - TensorShape Y = inputShapes[1].Value; - int rankY = inputRanks[1].Value; - List yShape = ShapeToOnnxLayout(Y, rankY); - - int rankO = Mathf.Max(rankX, rankY); - for (int i = 0; i < rankO - rankX; i++) - xShape.Insert(0, 1); - for (int i = 0; i < rankO - rankY; i++) - yShape.Insert(0, 1); - - List oShape = new List(); - - for (int i = 0; i < rankO - 2; i++) - oShape.Add(Mathf.Max(xShape[i], yShape[i])); - - oShape.Add(xShape[rankO - 2]); - oShape.Add(yShape[rankO - 1]); - - return OnnxLayoutToTensorShape(oShape.ToArray()); - } - case Layer.Type.Pad: - { - if (inputShapes.Length > 1) - return null; - - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - int rankX = inputRanks[0].Value; - List xShape = ShapeToOnnxLayout(X, rankX); - - - for (int i = 0; i < xShape.Count; i++) - { - xShape[i] += layer.pad[i] + layer.pad[rankX + i]; - } - - return OnnxLayoutToTensorShape(xShape.ToArray()); - } - case Layer.Type.Upsample2D: - { - if (inputShapes.Length > 1) - return null; - - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - - // pool size is treated as upsample coefficient here - Assert.IsNotNull(layer.pool); - Assert.AreEqual(layer.pool.Length, 4); - return new TensorShape(X.batch * layer.pool[0], X.height * layer.pool[1], X.width * layer.pool[2], X.channels * layer.pool[3]); - } - case Layer.Type.Upsample3D: - { - if (inputShapes.Length > 1) - return null; - - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - - // pool size is treated as upsample coefficient here - Assert.IsNotNull(layer.pool); - Assert.AreEqual(layer.pool.Length, 5); - return new TensorShape(X.batch * layer.pool[0], X.depth * layer.pool[1], X.height * layer.pool[2], X.width * layer.pool[3], X.channels * layer.pool[4]); - } - case Layer.Type.Resample2D: - { - if (inputShapes.Length > 1) - return null; - - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - - // pool is treated as resample size here - var size = layer.pool; - Assert.IsNotNull(size); - Assert.AreEqual(size.Length, 4); - return new TensorShape(size[0], size[1], size[2], size[3]); - } - case Layer.Type.TopKIndices: - case Layer.Type.TopKValues: - { - // Calculated at runtime: same shape as input 0 with k elements in the dimension specified by axis - return null; - } - case Layer.Type.NonMaxSuppression: - { - int maxOutputBoxesPerClass = 0; - - if (layer.pool.Length > 0) - maxOutputBoxesPerClass = layer.pool[0]; - - if (maxOutputBoxesPerClass <= 0) - return null; - - return new TensorShape(maxOutputBoxesPerClass, 3); - } - case Layer.Type.NonZero: - { - // Calculated at runtime - return null; - } - case Layer.Type.Add: - case Layer.Type.Sub: - case Layer.Type.Mul: - case Layer.Type.Div: - case Layer.Type.Pow: - case Layer.Type.Min: - case Layer.Type.Max: - case Layer.Type.Mean: - case Layer.Type.Greater: - case Layer.Type.GreaterEqual: - case Layer.Type.Less: - case Layer.Type.LessEqual: - case Layer.Type.Equal: - case Layer.Type.LogicalOr: - case Layer.Type.LogicalAnd: - case Layer.Type.LogicalXor: - { - if(inputShapes.Any(x => x == null)) - return null; - - - int rankO = inputRanks.Max().Value; - - var O = new List(); - for (int i = 0; i < rankO; i++) - O.Add(1); - for (int i = 0; i < inputShapes.Length; i++) - { - TensorShape X = inputShapes[i].Value; - int rankX = inputRanks[i].Value; - List xShape = ShapeToOnnxLayout(X, rankX); - - for (int k = 0; k < rankO - rankX; k++) - xShape.Insert(0, 1); - - for (int k = 0; k < rankO; k++) - O[k] = Math.Max(O[k], xShape[k]); - } - - return OnnxLayoutToTensorShape(O.ToArray()); - } - case Layer.Type.Range: - { - return null; // only const support - } - case Layer.Type.ReduceL1: - case Layer.Type.ReduceL2: - case Layer.Type.ReduceLogSum: - case Layer.Type.ReduceLogSumExp: - case Layer.Type.ReduceMax: - case Layer.Type.ReduceMean: - case Layer.Type.ReduceMin: - case Layer.Type.ReduceProd: - case Layer.Type.ReduceSum: - case Layer.Type.ReduceSumSquare: - case Layer.Type.ArgMax: - case Layer.Type.ArgMin: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - - int rank = inputRanks[0].Value; - var xShape = ShapeToOnnxLayout(X, rank); - - var axis = layer.axis; - if (axis < 0) - axis = rank + axis; - - xShape[axis] = 1; - if (layer.alpha != 1.0f) // keepdim == 0 - xShape.RemoveAt(axis); - - return OnnxLayoutToTensorShape(xShape.ToArray()); - } - case Layer.Type.Transpose: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - var permutations = layer.pool; - if (permutations == null) - return new TensorShape(X.batch, X.width); - else - { - int rank = inputRanks[0].Value; - List xShape = ShapeToOnnxLayout(X, rank); - - // Permutations may already be in padded form for op purposes, so strip down to match rank - permutations = permutations.Take(rank).ToArray(); - - var oShape = TensorExtensions.Permute(xShape.ToArray(), permutations); - return OnnxLayoutToTensorShape(oShape); - } - } - case Layer.Type.MaxPool2D: - case Layer.Type.AvgPool2D: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - X = new TensorShape(X.batch, X.width, X.channels, X.height); - Assert.IsNotNull(layer.pool); - Assert.IsNotNull(layer.stride); - Assert.IsNotNull(layer.pad); - var pad = X.AdjustPadToPool(layer.pool, layer.stride, layer.pad); - var O = X.ApplyPool(layer.pool, layer.stride, pad); - return new TensorShape(O.batch, O.channels, O.height, O.width); - } - case Layer.Type.Load: - { - return layer.datasets[0].shape; - } - case Layer.Type.DepthToSpace: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - X = new TensorShape(X.batch, X.width, X.channels, X.height); - // pool size is treated as blocksize here - Assert.IsNotNull(layer.pool); - Assert.AreEqual(layer.pool.Length, 2); - Assert.AreEqual(X.channels % (layer.pool[0] * layer.pool[1]), 0); - var O = new TensorShape(X.batch, X.height * layer.pool[1], X.width * layer.pool[0], X.channels / (layer.pool[0] * layer.pool[1])); - return new TensorShape(O.batch, O.channels, O.height, O.width); - } - case Layer.Type.SpaceToDepth: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - X = new TensorShape(X.batch, X.width, X.channels, X.height); - // pool size is treated as blocksize here - Assert.IsNotNull(layer.pool); - Assert.AreEqual(layer.pool.Length, 2); - var O = new TensorShape(X.batch, X.height / layer.pool[1], X.width / layer.pool[0], X.channels * (layer.pool[0] * layer.pool[1])); - return new TensorShape(O.batch, O.channels, O.height, O.width); - } - case Layer.Type.RandomNormal: - case Layer.Type.RandomUniform: - { - Assert.IsNotNull(layer.pool); - // pool size is treated as shape constant, if not empty - // otherwise shape of the previous tensor is used - if (layer.pool.Length > 0) - return new TensorShape(layer.pool); - else - return inputShapes[0]; - } - case Layer.Type.Multinomial: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - Assert.IsNotNull(layer.pool); - Assert.AreEqual(layer.pool.Length, 1); - return new TensorShape(X.batch, layer.pool[0]); - } - case Layer.Type.OneHot: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - int rank = inputRanks[0].Value; - var nchwShape = ShapeToOnnxLayout(X, rank); - int depth = layer.pool[0]; - nchwShape.Add(depth); - - return OnnxLayoutToTensorShape(nchwShape.ToArray()); - } - case Layer.Type.RoiAlign: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - TensorShape rois = inputShapes[0].Value; - - return new TensorShape(rois.batch, X.height, layer.pool[0], layer.pool[1]); - } - case Layer.Type.LSTM: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - var nchwShape = new List { X.batch, X.height, X.width, X.channels }; - int hiddenSize = layer.pool[0]; - - // The first output, Y, is rank 4; Other outputs are handled as identity layers - return new TensorShape(nchwShape[0], 1, nchwShape[1], hiddenSize); - } - case Layer.Type.Flatten: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - return X.Flatten(); - } - case Layer.Type.Tile: - { - if (inputShapes.Length > 1) - return null; - - if(inputShapes[0] == null) - return null; - - var inputShape = ShapeToOnnxLayout(inputShapes[0].Value, inputRanks[0].Value); - var scale = layer.pool.ToArray(); - Assert.IsNotNull(scale); - Assert.AreEqual(scale.Length, inputShape.Count); - - for (int i = 0; i < scale.Length; i++) - scale[i] *= inputShape[i]; - - return OnnxLayoutToTensorShape(scale); - } - case Layer.Type.ConstantOfShape: - { - if(layer.axis == 1) - return inputShapes[0]; - - if (inputShapes.Length == 1) - return null; - else - return OnnxLayoutToTensorShape(layer.pool); - } - case Layer.Type.Reshape: - { - if (inputShapes.Length > 1) - return null; - - if (inputShapes[0] == null) - return null; - - // TODO shape to onnx shape given rank - TensorShape X = inputShapes[0].Value; - int rank = inputRanks[0].Value; - var nchwShape = ShapeToOnnxLayout(X, rank); - - var unknownIndex = -1; - var multipleOf = 1; - var size = layer.pool.ToArray(); - for (var i = 0; i < size.Length; ++i) - { - if (size[i] == 0) - size[i] = nchwShape[i]; - - if (size[i] < 0) - unknownIndex = i; - else - multipleOf *= size[i]; - } - - if (unknownIndex != -1) - size[unknownIndex] = X.length / multipleOf; - - return OnnxLayoutToTensorShape(size); - } - case Layer.Type.Expand: - { - if (inputShapes.Length > 1) - return null; - - if(inputShapes[0] == null) - return null; - - var size = layer.pool.ToList(); - var inputShape = ShapeToOnnxLayout(inputShapes[0].Value, inputRanks[0].Value); - - int rankO = Math.Max(size.Count, inputShape.Count); - for (int i = 0; i < rankO - size.Count; i++) - size.Insert(0, 1); - for (int i = 0; i < rankO - inputShape.Count; i++) - inputShape.Insert(0, 1); - - var tiledShape = new int[rankO]; - for (int i = 0; i < rankO; i++) - tiledShape[i] = Mathf.Max(size[i], inputShape[i]); - - return OnnxLayoutToTensorShape(tiledShape); - } - case Layer.Type.Concat: - { - if(inputShapes.Any(x => x == null)) - return null; - - int maxRank = inputRanks.Max().Value; - - var shape = ShapeToOnnxLayout(inputShapes[0].Value, maxRank); - var axis = layer.axis; - if (axis < 0) - axis += maxRank; - - for (int i = 1; i < inputShapes.Length; i++) - { - var shapei = ShapeToOnnxLayout(inputShapes[i].Value, maxRank); - shape[axis] += shapei[axis]; - } - - return OnnxLayoutToTensorShape(shape.ToArray()); - } - case Layer.Type.Gather: - { - if(inputShapes[0] == null || inputShapes[1] == null) - return null; - - var input0Shape = inputShapes[0].Value; - var input1Shape = inputShapes[1].Value; - - - int rank0 = inputRanks[0].Value; - int rank1 = inputRanks[1].Value; - var shape = ShapeToOnnxLayout(input0Shape, rank0); - var indicies = ShapeToOnnxLayout(input1Shape, rank1); - - var axis = layer.axis; - if (axis < 0) - axis += rank0; - - shape.InsertRange(axis, indicies); - shape.RemoveAt(axis + indicies.Count); - - return OnnxLayoutToTensorShape(shape.ToArray()); - } - case Layer.Type.ScatterND: - return inputShapes[0]; - // elementwise operations - case Layer.Type.Nop: - case Layer.Type.ScaleBias: - case Layer.Type.Normalization: - case Layer.Type.LRN: - case Layer.Type.Dropout: - case Layer.Type.LogicalNot: - case Layer.Type.Sign: - case Layer.Type.Where: - { - // works in place, keeps the same shape size - return inputShapes[0]; - } - case Layer.Type.Activation: - { - // LSTMs have multiple outputs, so deal with those separately - if (layer.activation == Layer.Activation.None && layer.pad.Length > 0 - && layer.name.IndexOf("lstm", StringComparison.OrdinalIgnoreCase) >= 0) - { - int rank = layer.pad[0]; - switch (rank) - { - case 4: - // Y - return inputShapes[0]; - - case 3: - { - if (inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - // Y_h, Y_c: seq_length is stripped off - return new TensorShape(X[1], X[2], X[3]); - } - } - } - - // works in place, keeps the same shape size - return inputShapes[0]; - } - case Layer.Type.Shape: - { - if(inputRanks[0] == null) - return null; - - int rank = inputRanks[0].Value; - return new TensorShape(rank); - } - case Layer.Type.Squeeze: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - int rank = inputRanks[0].Value; - - if (inputShapes.Length > 1) - return null; - - var nchwShape = ShapeToOnnxLayout(X, rank); - - var squeezedShape = new List(); - for (int i = 0; i < nchwShape.Count; i++) - { - if (!layer.pool.Contains(i)) - squeezedShape.Add(nchwShape[i]); - } - - return OnnxLayoutToTensorShape(squeezedShape.ToArray()); - } - case Layer.Type.Unsqueeze: - { - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - int rank = inputRanks[0].Value; - - if (inputShapes.Length > 1) - return null; - - if (rank < 0) - return null; - - var nchwShape = ShapeToOnnxLayout(X, rank); - - if (rank == 0) - return new TensorShape(new int[] { 1, 1, 1, 1 }); - - for (int a = 0; a < layer.pool.Length; a++) - { - var axis = layer.pool[a]; - if (axis < 0) - axis += rank; - - nchwShape.Insert(axis, 1); - rank++; - } - - return OnnxLayoutToTensorShape(nchwShape.ToArray()); - } - case Layer.Type.StridedSlice: - { - if (inputShapes.Length > 1) - return null; - - if(inputShapes[0] == null) - return null; - - TensorShape X = inputShapes[0].Value; - int rank = inputRanks[0].Value; - var nchwShape = ShapeToOnnxLayout(X, rank); - - var starts = layer.pad.ToArray(); - var ends = layer.pool.ToArray(); - var steps = layer.stride.ToArray(); - var axes = layer.axes.ToArray(); - - var onnxStarts = Enumerable.Repeat(0, rank).ToArray(); - var onnxEnds = Enumerable.Repeat(int.MaxValue, rank).ToArray(); // by default copy the whole axis till the end - var onnxSteps = Enumerable.Repeat(1, rank).ToArray(); - - // NOTE: begin=0, end=0, stride=1 <= full range from existing axis - // begin=0, end=inf,stride=1 <= full range from existing axis - // begin=0, end=X, stride=1 <= full range from existing axis, if X==last element on this axis - // begin=0, end=0, stride=0 <= new axis OR shrink axis to single 1st element - // begin=N, end=N, stride=0 <= shrink axis to single Nth element - // These notes are copied from TensorExtensions.ApplyStridedSlice(...) - - for (int i = 0; i < axes.Length; ++i) - { - var axis = axes[i]; - if (axis < 0) - axis += rank; - axis = Math.Min(Math.Max(axis, 0), rank); - - onnxStarts[axis] = starts[i]; - onnxEnds[axis] = ends[i]; - onnxSteps[axis] = steps[i]; - } - - var sliced = new int[rank]; - for (int i = 0; i < rank; ++i) - { - // NOTE: begin=0, end=0, stride=1 <= full range from the existing axis - // begin=0, end=X, stride=1 <= full range from the existing axis, if X==last element on this axis - // begin=0, end=0, stride=0 <= new axis OR shrink axis to a single 1st element - // begin=N, end=N, stride=0 <= shrink axis to a single Nth element - int ei = TensorExtensions.WrapIndex(onnxEnds[i], nchwShape[i]); - int si = TensorExtensions.WrapIndex(onnxStarts[i], nchwShape[i]); - - if (onnxSteps[i] > 0) - sliced[i] = (int)Mathf.Round((float)(Math.Min(ei, nchwShape[i]) - Math.Min(si, nchwShape[i] - 1)) / (float)(Mathf.Abs(onnxSteps[i]))); - else - { - bool inclusive = onnxEnds[i] < -nchwShape[i]; // edge case when ends is negative and bigger than nchwShape - sliced[i] = (int)Mathf.Round((float)(Math.Min(si, nchwShape[i] - 1) - Math.Min(ei, nchwShape[i]) + (inclusive ? 1 : 0)) / (float)(Mathf.Abs(onnxSteps[i]))); - } - } - - return OnnxLayoutToTensorShape(sliced.ToArray()); - } - default: - throw new NotImplementedException("InferOutputShapeNCHW: Unhandled layer: " + layer.ToString()); - } - } - - // TODO merge that with NHWC : flank by transpose shape and call InferOutputShapeNHWC - public static void UpdateKnownTensorShapesNCHW(Model model, ref IDictionary ranksByName, ref IDictionary shapesByName) - { - foreach (var l in model.layers) - { - TensorShape?[] layerInputShapes = new TensorShape?[l.inputs.Length]; - int?[] layerInputShapeRanks = new int?[l.inputs.Length]; - - for (int i = 0; i < l.inputs.Length; i++) - { - shapesByName.TryGetValue(l.inputs[i], out TensorShape? ishape); - ranksByName.TryGetValue(l.inputs[i], out int? irank); - - layerInputShapes[i] = ishape; - layerInputShapeRanks[i] = irank; - } - - // knowing rank might imply knowing shape: - // + compute rank first - // + compute shape - // knowing shape might imply knowing rank: - // + compute rank - int? outputRank = RankInference.InferOutputRank(l, layerInputShapeRanks, layerInputShapes); - ranksByName[l.name] = outputRank; - TensorShape? outputShape = InferOutputShapeNCHW(l, layerInputShapeRanks, layerInputShapes); - outputRank = RankInference.InferOutputRank(l, layerInputShapeRanks, layerInputShapes); - ranksByName[l.name] = outputRank; - shapesByName[l.name] = outputShape; - } - } - public static TensorShape?[] ListTemporaryTensorShapesNCHW(Model model, IDictionary inputShapes, ref IDictionary ranksByName, - out IDictionary shapesByName) - { - Profiler.BeginSample("Barracuda.ListTemporaryTensorShapesNCHW"); - var shapes = new List(); - shapesByName = new Dictionary(); - foreach (var i in inputShapes) - shapesByName.Add(i.Key, i.Value); - - foreach (var l in model.layers) - { - TensorShape?[] layerInputShapes = new TensorShape?[l.inputs.Length]; - int?[] layerInputShapeRanks = new int?[l.inputs.Length]; - - for (int i = 0; i < l.inputs.Length; i++) - { - shapesByName.TryGetValue(l.inputs[i], out TensorShape? ishape); - ranksByName.TryGetValue(l.inputs[i], out int? irank); - - layerInputShapes[i] = ishape; - layerInputShapeRanks[i] = irank; - } - - - int? outputRank = RankInference.InferOutputRank(l, layerInputShapeRanks, layerInputShapes); - ranksByName[l.name] = outputRank; - TensorShape? outputShape = InferOutputShapeNCHW(l, layerInputShapeRanks, layerInputShapes); - outputRank = RankInference.InferOutputRank(l, layerInputShapeRanks, layerInputShapes); - ranksByName[l.name] = outputRank; - - shapes.Add(outputShape); - shapesByName.Add(l.name, outputShape); - } - - Profiler.EndSample(); - return shapes.ToArray(); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRShapeInferenceHelper.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRShapeInferenceHelper.cs.meta deleted file mode 100644 index b9f58e4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Compiler/ShapeInference/IRShapeInferenceHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bded274bae6deea43a748679b69fbb9f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals.meta b/Packages/com.unity.barracuda/Runtime/Core/Internals.meta deleted file mode 100644 index 2cb7e5b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2e66409e73f60504cb31cf0068d44e20 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/Debug.cs b/Packages/com.unity.barracuda/Runtime/Core/Internals/Debug.cs deleted file mode 100644 index b2b2888..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/Debug.cs +++ /dev/null @@ -1,260 +0,0 @@ -#define BARRACUDA_LOG_ENABLED - -using System; -using UnityEngine; -using Object = UnityEngine.Object; - -namespace Unity.Barracuda -{ - /// - /// Barracuda debug logging utility - /// - public class D - { - /// - /// Warning stack trace collection enabling flag - /// - public static bool warningStackTraceEnabled = Application.isEditor; - - /// - /// Error stack trace collection enabling flag - /// - public static bool errorStackTraceEnabled = true; - - /// - /// Debug log stack trace collection enabling flag - /// - public static bool logStackTraceEnabled = false; - - /// - /// Warning logging enabled flag - /// - public static bool warningEnabled = true; - - /// - /// Error logging enabled flag - /// - public static bool errorEnabled = true; - - /// - /// Debug logging enabled flag - /// - public static bool logEnabled = true; - -#if BARRACUDA_LOG_ENABLED - - /// - /// Log warning - /// - /// message - public static void LogWarning(object message) - { - if (!warningEnabled) - return; - - if (!warningStackTraceEnabled) - { - try - { - var oldConfig = Application.GetStackTraceLogType(LogType.Warning); - Application.SetStackTraceLogType(LogType.Warning, StackTraceLogType.None); - UnityEngine.Debug.LogWarning(message); - Application.SetStackTraceLogType(LogType.Warning, oldConfig); - } - catch (Exception) - { - UnityEngine.Debug.LogWarning(message); - } - - } - else - { - UnityEngine.Debug.LogWarning(message); - } - } - - /// - /// Log warning - /// - /// message - /// context - public static void LogWarning(object message, Object context) - { - if (!warningEnabled) - return; - - if (!warningStackTraceEnabled) - { - try - { - var oldConfig = Application.GetStackTraceLogType(LogType.Warning); - Application.SetStackTraceLogType(LogType.Warning, StackTraceLogType.None); - UnityEngine.Debug.LogWarning(message, context); - Application.SetStackTraceLogType(LogType.Warning, oldConfig); - } - catch (Exception) - { - UnityEngine.Debug.LogWarning(message, context); - } - } - else - { - UnityEngine.Debug.LogWarning(message, context); - } - } - - /// - /// Log error - /// - /// message - public static void LogError(object message) - { - if (!errorEnabled) - return; - - if (!errorStackTraceEnabled) - { - try - { - var oldConfig = Application.GetStackTraceLogType(LogType.Warning); - Application.SetStackTraceLogType(LogType.Error, StackTraceLogType.None); - UnityEngine.Debug.LogError(message); - Application.SetStackTraceLogType(LogType.Error, oldConfig); - } - catch (Exception) - { - UnityEngine.Debug.LogError(message); - } - } - else - { - UnityEngine.Debug.LogError(message); - } - } - - /// - /// Log error - /// - /// message - /// context - public static void LogError(object message, Object context) - { - if (!errorEnabled) - return; - - if (!errorStackTraceEnabled) - { - try - { - var oldConfig = Application.GetStackTraceLogType(LogType.Warning); - Application.SetStackTraceLogType(LogType.Error, StackTraceLogType.None); - UnityEngine.Debug.LogError(message, context); - Application.SetStackTraceLogType(LogType.Error, oldConfig); - } - catch (Exception) - { - UnityEngine.Debug.LogError(message, context); - } - } - else - { - UnityEngine.Debug.LogError(message, context); - } - } - - /// - /// Log debug info - /// - /// message - public static void Log(object message) - { - if (!logEnabled) - return; - - if (!logStackTraceEnabled) - { - try - { - var oldConfig = Application.GetStackTraceLogType(LogType.Warning); - Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.None); - UnityEngine.Debug.Log(message); - Application.SetStackTraceLogType(LogType.Log, oldConfig); - } - catch (Exception) - { - UnityEngine.Debug.Log(message); - } - } - else - { - UnityEngine.Debug.Log(message); - } - } - - /// - /// Log debug info - /// - /// message - /// context - public static void Log(object message, Object context) - { - if (!logEnabled) - return; - - if (!logStackTraceEnabled) - { - try - { - var oldConfig = Application.GetStackTraceLogType(LogType.Warning); - Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.None); - UnityEngine.Debug.Log(message, context); - Application.SetStackTraceLogType(LogType.Log, oldConfig); - } - catch (Exception) - { - UnityEngine.Debug.Log(message, context); - } - } - else - { - UnityEngine.Debug.Log(message, context); - } - } -#else - public static void LogWarning(object message) - { - - } - - public static void LogWarning(object message, Object context) - { - - } - - public static void LogError(object message) - { - - } - - public static void LogError(object message, Object context) - { - - } - - public static void Log(object message) - { - - } - - public static void Log(object message, Object context) - { - - } -#endif - } - - internal class Debug : D - { - - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/Debug.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Internals/Debug.cs.meta deleted file mode 100644 index 0eaa6a3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/Debug.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: bdcfe88795204e0799076d9c7cd8dd39 -timeCreated: 1534164090 \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModel.cs b/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModel.cs deleted file mode 100644 index e1a1249..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModel.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using UnityEngine; - -namespace Unity.Barracuda -{ - /// - /// Barracuda Model asset - /// - public class NNModel : ScriptableObject - { - /// - /// Model data - /// - [HideInInspector] - public NNModelData modelData; - - [NonSerialized] - Model m_Model; - - [NonSerialized] - float m_LastLoaded; - - internal Model GetDeserializedModel(bool verbose = false, bool skipWeights = true) - { - if (m_Model == null) - { - m_Model = ModelLoader.Load(this, verbose, skipWeights); - m_LastLoaded = Time.realtimeSinceStartup; - } - - return m_Model; - } - - void OnEnable() - { - // Used for detecting re-serialized models (e.g. adjusting import settings in the editor) - // Force a reload on next access - if (Time.realtimeSinceStartup >= m_LastLoaded) - m_Model = null; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModel.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModel.cs.meta deleted file mode 100644 index 9013f48..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModel.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d56b7ac7bee314a29a9d00b13ccdb4f5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModelData.cs b/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModelData.cs deleted file mode 100644 index 40aa74b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModelData.cs +++ /dev/null @@ -1,16 +0,0 @@ -using UnityEngine; - -namespace Unity.Barracuda -{ - /// - /// Barracuda `Model` data storage - /// - public class NNModelData : ScriptableObject - { - /// - /// `Model` byte stream - /// - [HideInInspector] - public byte[] Value; - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModelData.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModelData.cs.meta deleted file mode 100644 index e0cc9d3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/NNModelData.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 918083d8e7e25db4ca0bf105a499975e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/StringCache.cs b/Packages/com.unity.barracuda/Runtime/Core/Internals/StringCache.cs deleted file mode 100644 index cd36f5d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/StringCache.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Unity.Barracuda -{ - -internal struct StringStringPair : IEquatable -{ - public string a; - public string b; - - public bool Equals(StringStringPair other) - { - return string.Equals(a, other.a) && string.Equals(b, other.b); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is StringStringPair && Equals((StringStringPair) obj); - } - - public override int GetHashCode() - { - var hashCode = a.GetHashCode(); - hashCode ^= b.GetHashCode(); - return hashCode; - } -} - -internal struct StringStringLongTriplet : IEquatable -{ - public string a; - public string b; - public long c; - - public override int GetHashCode() - { - var hashCode = a.GetHashCode(); - hashCode ^= b.GetHashCode(); - hashCode ^= c.GetHashCode(); - return hashCode; - } - - public bool Equals(StringStringLongTriplet other) - { - return string.Equals(a, other.a) && string.Equals(b, other.b) && c == other.c; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is StringStringLongTriplet && Equals((StringStringLongTriplet) obj); - } -} - -internal class StringCache -{ - private Dictionary m_CacheStringString = new Dictionary(); - private Dictionary m_CacheStringStringLong = new Dictionary(); - - public string Lookup(string a, string b) - { - var key = new StringStringPair {a = a ?? "", b = b ?? ""}; - - if (!m_CacheStringString.ContainsKey(key)) - m_CacheStringString[key] = a + b; - - return m_CacheStringString[key]; - } - - public string Lookup(string a, string b, long c) - { - var key = new StringStringLongTriplet {a = a ?? "", b = b ?? "", c = c}; - - if (!m_CacheStringStringLong.ContainsKey(key)) - m_CacheStringStringLong[key] = a + b + c; - - return m_CacheStringStringLong[key]; - } - - public void Clear() - { - m_CacheStringString.Clear(); - m_CacheStringStringLong.Clear(); - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/StringCache.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Internals/StringCache.cs.meta deleted file mode 100644 index a55a8c2..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/StringCache.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6728c68ead6e34aee8795c793b4e5070 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/TestSetLoader.cs b/Packages/com.unity.barracuda/Runtime/Core/Internals/TestSetLoader.cs deleted file mode 100644 index f9ef5cb..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/TestSetLoader.cs +++ /dev/null @@ -1,530 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -using UnityEngine; -using UnityEngine.Assertions; -using System.IO.Compression; - - -namespace Unity.Barracuda { - -/// -/// Test set loading utility -/// -public class TestSet -{ - private RawTestSet rawTestSet; - private JSONTestSet jsonTestSet; - - /// - /// Create with raw test set - /// - /// raw test set - public TestSet(RawTestSet rawTestSet) - { - this.rawTestSet = rawTestSet; - } - - /// - /// Create with JSON test set - /// - /// JSON test set - public TestSet(JSONTestSet jsonTestSet) - { - this.jsonTestSet = jsonTestSet; - } - - /// - /// Create `TestSet` - /// - public TestSet() - { - } - - /// - /// Check if test set supports named tensors - /// - /// `true` if named tensors are supported - public bool SupportsNames() - { - if (rawTestSet != null) - return false; - - return true; - } - - /// - /// Get output tensor count - /// - /// - public int GetOutputCount() - { - if (rawTestSet != null) - return 1; - - return jsonTestSet.outputs.Length; - } - - /// - /// Get output tensor data - /// - /// tensor index - /// tensor data - public float[] GetOutputData(int idx = 0) - { - if (rawTestSet != null) - return rawTestSet.labels; - - return jsonTestSet.outputs[idx].data; - } - - /// - /// Get output tensor name - /// - /// tensor index - /// tensor name - public string GetOutputName(int idx = 0) - { - if (rawTestSet != null) - return null; - - string name = jsonTestSet.outputs[idx].name; - return name.EndsWith(":0") ? name.Remove(name.Length - 2) : name; - } - - /// - /// Get input tensor count - /// - /// - public int GetInputCount() - { - if (rawTestSet != null) - return 1; - - return jsonTestSet.inputs.Length; - } - - /// - /// Get input tensor name - /// - /// input tensor index - /// tensor name - public string GetInputName(int idx = 0) - { - if (rawTestSet != null) - return ""; - - string name = jsonTestSet.inputs[idx].name; - return name.EndsWith(":0") ? name.Remove(name.Length - 2) : name; - } - - /// - /// Get input tensor data - /// - /// input tensor index - /// tensor data - public float[] GetInputData(int idx = 0) - { - if (rawTestSet != null) - return rawTestSet.input; - - return jsonTestSet.inputs[idx].data; - } - - /// - /// Get input shape - /// - /// input tensor index - /// input shape - public TensorShape GetInputShape(int idx = 0) - { - if (rawTestSet != null) - return new TensorShape(1,rawTestSet.input.Length); - - return new TensorShape(jsonTestSet.inputs[idx].shape.sequenceLength, - jsonTestSet.inputs[idx].shape.numberOfDirections, - jsonTestSet.inputs[idx].shape.batch, - jsonTestSet.inputs[idx].shape.extraDimension, - jsonTestSet.inputs[idx].shape.depth, - jsonTestSet.inputs[idx].shape.height, - jsonTestSet.inputs[idx].shape.width, - jsonTestSet.inputs[idx].shape.channels); - } - - /// - /// Get output tensor shape - /// - /// output tensor index - /// tensor shape - public TensorShape GetOutputShape(int idx = 0) - { - if (rawTestSet != null) - return new TensorShape(1,rawTestSet.labels.Length); - - return new TensorShape(jsonTestSet.outputs[idx].shape.sequenceLength, - jsonTestSet.outputs[idx].shape.numberOfDirections, - jsonTestSet.outputs[idx].shape.batch, - jsonTestSet.outputs[idx].shape.extraDimension, - jsonTestSet.outputs[idx].shape.depth, - jsonTestSet.outputs[idx].shape.height, - jsonTestSet.outputs[idx].shape.width, - jsonTestSet.outputs[idx].shape.channels); - } - - /// - /// Get inputs as `Tensor` dictionary - /// - /// dictionary to store results - /// max batch count - /// start from batch - /// dictionary with input tensors - /// thrown if called on raw test set (only JSON test set is supported) - public Dictionary GetInputsAsTensorDictionary(Dictionary inputs = null, int batchCount = -1, int fromBatch = 0) - { - if (rawTestSet != null) - throw new Exception("GetInputsAsTensorDictionary is not supported for RAW test suites"); - - if (inputs == null) - inputs = new Dictionary(); - - for (var i = 0; i < GetInputCount(); i++) - inputs[GetInputName(i)] = GetInputAsTensor(i, batchCount, fromBatch); - - return inputs; - } - - /// - /// Get outputs as `Tensor` dictionary - /// - /// dictionary to store results - /// max batch count - /// start from batch - /// dictionary with input tensors - /// thrown if called on raw test set (only JSON test set is supported) - public Dictionary GetOutputsAsTensorDictionary(Dictionary outputs = null, int batchCount = -1, int fromBatch = 0) - { - if (rawTestSet != null) - throw new Exception("GetOutputsAsTensorDictionary is not supported for RAW test suites"); - - if (outputs == null) - outputs = new Dictionary(); - - for (var i = 0; i < GetOutputCount(); i++) - outputs[GetOutputName(i)] = GetOutputAsTensor(i, batchCount, fromBatch); - - return outputs; - } - - /// - /// Get input as `Tensor` - /// - /// input index - /// max batch count - /// start from batch - /// `Tensor` - /// thrown if called on raw test set (only JSON test set is supported) - public Tensor GetInputAsTensor(int idx = 0, int batchCount = -1, int fromBatch = 0) - { - if (rawTestSet != null) - throw new Exception("GetInputAsTensor is not supported for RAW test suites"); - - TensorShape shape = GetInputShape(idx); - Assert.IsTrue(shape.sequenceLength==1 && shape.numberOfDirections==1); - var array = GetInputData(idx); - var maxBatchCount = array.Length / shape.flatWidth; - - fromBatch = Math.Min(fromBatch, maxBatchCount - 1); - if (batchCount < 0) - batchCount = maxBatchCount - fromBatch; - - // pad data with 0s, if test-set doesn't have enough batches - var shapeArray = shape.ToArray(); - shapeArray[TensorShape.DataBatch] = batchCount; - var tensorShape = new TensorShape(shapeArray); - var managedBufferStartIndex = fromBatch * tensorShape.flatWidth; - var count = Math.Min(batchCount, maxBatchCount - fromBatch) * tensorShape.flatWidth; - float[] dataToUpload = new float[tensorShape.length]; - Array.Copy(array, managedBufferStartIndex, dataToUpload, 0, count); - - var data = new ArrayTensorData(tensorShape.length); - data.Upload(dataToUpload, tensorShape, 0); - - var res = new Tensor(tensorShape, data); - res.name = GetInputName(idx); - res.name = res.name.EndsWith(":0") ? res.name.Remove(res.name.Length - 2) : res.name; - - return res; - } - - /// - /// Get output as `Tensor` - /// - /// output index - /// max batch count - /// start from batch - /// `Tensor` - /// thrown if called on raw test set (only JSON test set is supported) - public Tensor GetOutputAsTensor(int idx = 0, int batchCount = -1, int fromBatch = 0) - { - if (rawTestSet != null) - throw new Exception("GetOutputAsTensor is not supported for RAW test suites"); - - TensorShape shape = GetOutputShape(idx); - Assert.IsTrue(shape.sequenceLength==1 && shape.numberOfDirections==1); - var barracudaArray = new BarracudaArrayFromManagedArray(GetOutputData(idx)); - - var maxBatchCount = barracudaArray.Length / shape.flatWidth; - - fromBatch = Math.Min(fromBatch, maxBatchCount - 1); - if (batchCount < 0) - batchCount = maxBatchCount - fromBatch; - batchCount = Math.Min(batchCount, maxBatchCount - fromBatch); - - var shapeArray = shape.ToArray(); - shapeArray[TensorShape.DataBatch] = batchCount; - var tensorShape = new TensorShape(shapeArray); - - var offset = fromBatch * tensorShape.flatWidth; - var res = new Tensor(tensorShape, new SharedArrayTensorData(barracudaArray, tensorShape, offset)); - res.name = GetOutputName(idx); - res.name = res.name.EndsWith(":0") ? res.name.Remove(res.name.Length - 2) : res.name; - - return res; - } -} - -/// -/// Raw test structure -/// -public class RawTestSet -{ - /// - /// Input data - /// - public float[] input; - - /// - /// Output data - /// - public float[] labels; -} - -/// -/// JSON test structure -/// -[Serializable] -public class JSONTestSet -{ - /// - /// Inputs - /// - public JSONTensor[] inputs; - - /// - /// Outputs - /// - public JSONTensor[] outputs; -} - -/// -/// JSON tensor shape -/// -[Serializable] -public class JSONTensorShape -{ - /// - /// Sequence length - /// - public int sequenceLength; - - /// - /// Number of directions - /// - public int numberOfDirections; - - /// - /// Batch - /// - public int batch; - - /// - /// Extra dimension - /// - public int extraDimension; - - /// - /// Depth - /// - public int depth; - - /// - /// Height - /// - public int height; - - /// - /// Width - /// - public int width; - - /// - /// Channels - /// - public int channels; -} - -/// -/// JSON tensor -/// -[Serializable] -public class JSONTensor -{ - /// - /// Name - /// - public string name; - - /// - /// Shape - /// - public JSONTensorShape shape; - - /// - /// Tensor type - /// - public string type; - - /// - /// Tensor data - /// - public float[] data; -} - -/// -/// Test set loader -/// -public class TestSetLoader -{ - /// - /// Load test set from file - /// - /// file name - /// `TestSet` - public static TestSet Load(string filename) - { - if (filename.ToLower().EndsWith(".raw")) - return LoadRaw(filename); - else if (filename.ToLower().EndsWith(".gz")) - return LoadGZ(filename); - - return LoadJSON(filename); - } - - /// - /// Load GZ - /// - /// file name - /// `TestSet` - public static TestSet LoadGZ(string filename) - { - var jsonFileName = filename.Substring(0, filename.Length - 3); - var sourceArchiveFileName = Path.Combine(Application.streamingAssetsPath, "TestSet", filename); - var destinationDirectoryName = sourceArchiveFileName.Substring(0, sourceArchiveFileName.Length - 3); - - FileInfo fileToDecompress = new FileInfo(sourceArchiveFileName); - using (FileStream originalFileStream = fileToDecompress.OpenRead()) - { - using (FileStream decompressedFileStream = File.Create(destinationDirectoryName)) - { - using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress)) - { - decompressionStream.CopyTo(decompressedFileStream); - } - } - } - - return LoadJSON(jsonFileName); - } - - /// - /// Load JSON - /// - /// file name - /// `TestSet` - public static TestSet LoadJSON(string filename) - { - string json = ""; - - if (filename.EndsWith(".json")) - json = File.ReadAllText(Path.Combine(Application.streamingAssetsPath, "TestSet", filename)); - else - json = Resources.Load($"TestSet/{filename}").text; - - TestSet result = new TestSet(JsonUtility.FromJson(json)); - return result; - } - - /// - /// Load raw test set - /// - /// file name - /// `TestSet` - public static TestSet LoadRaw(string filename) - { - string fullpath = Path.Combine(Application.streamingAssetsPath, "TestSet", filename); - - using(BinaryReader file = Open(fullpath)) - { - - var rawTestSet = new RawTestSet(); - rawTestSet.input = LoadFloatArray(file); - rawTestSet.labels = LoadFloatArray(file); - return new TestSet(rawTestSet); - } - } - - /// - /// Load image - /// - /// file name - /// `Texture` - public static Texture LoadImage(string filename) - { - string fullpath = Path.Combine(Application.streamingAssetsPath, "TestSet", filename); - - var bytes = File.ReadAllBytes(fullpath); - var tex = new Texture2D(2, 2); - ImageConversion.LoadImage(tex, bytes, false); // LoadImage will auto-resize the texture dimensions - tex.wrapMode = TextureWrapMode.Clamp; - return tex; - } - - /// - /// Load float array - /// - /// binary file reader - /// float array - public static float[] LoadFloatArray(BinaryReader file) - { - Int64 dataLength = file.ReadInt64(); - float[] array = new float[dataLength]; - byte[] bytes = file.ReadBytes(Convert.ToInt32(dataLength * sizeof(float))); // @TODO: support larger than MaxInt32 data blocks - Buffer.BlockCopy(bytes, 0, array, 0, bytes.Length); - - return array; - } - - /// - /// Open file with binary reader - /// - /// file name - /// `BinaryReader` - static BinaryReader Open(string filename) - { - return new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)); - } -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Internals/TestSetLoader.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Internals/TestSetLoader.cs.meta deleted file mode 100644 index ee47724..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Internals/TestSetLoader.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: b60ed189056434a469534a5cfdd124ab -timeCreated: 1495576373 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Model.cs b/Packages/com.unity.barracuda/Runtime/Core/Model.cs deleted file mode 100644 index 814e8e0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Model.cs +++ /dev/null @@ -1,1334 +0,0 @@ -using System; -using System.Linq; // Select -using System.Collections.Generic; -using Unity.Barracuda.Compiler.Passes; -using UnityEngine.Assertions; -using UnityEditor; - -namespace Unity.Barracuda { - -/// -/// Barracuda Model Layer -/// -public class Layer -{ - /// - /// Layer Type - /// - public enum Type - { - /// - /// No operation / identity layer - /// - Nop = 0, - - /// - /// Dense layer - /// - Dense = 1, - - /// - /// Matrix multiplication layer - /// - MatMul = 2, - - /// - /// Rank-3 Dense Layer - /// - Dense3 = 3, - - /// - /// 2D Convolution layer - /// - Conv2D = 20, - - /// - /// Depthwise Convolution layer - /// - DepthwiseConv2D = 21, - - /// - /// Transpose 2D Convolution layer - /// - Conv2DTrans = 22, - - /// - /// Upsampling layer - /// - Upsample2D = 23, - - /// - /// Max Pool layer - /// - MaxPool2D = 25, - - /// - /// Average Pool layer - /// - AvgPool2D = 26, - - /// - /// Global Max Pool layer - /// - GlobalMaxPool2D = 27, - - /// - /// Global Average Pool layer - /// - GlobalAvgPool2D = 28, - - /// - /// Border / Padding layer - /// - Border2D = 29, - - /// - /// 3D Convolution layer - /// - Conv3D = 30, - - /// - /// Transpose 3D Convolution layer (not yet implemented) - /// - Conv3DTrans = 32, // TODO: NOT IMPLEMENTED - - /// - /// 3D Upsampling layer - /// - Upsample3D = 33, - - /// - /// 3D Max Pool layer (not yet implemented) - /// - MaxPool3D = 35, // TODO: NOT IMPLEMENTED - - /// - /// 3D Average Pool layer (not yet implemented) - /// - AvgPool3D = 36, // TODO: NOT IMPLEMENTED - - /// - /// 3D Global Max Pool layer (not yet implemented) - /// - GlobalMaxPool3D = 37, // TODO: NOT IMPLEMENTED - - /// - /// 3D Global Average Pool layer (not yet implemented) - /// - GlobalAvgPool3D = 38, // TODO: NOT IMPLEMENTED - - /// - /// 3D Border / Padding layer - /// - Border3D = 39, - - /// - /// Activation layer, see `Activation` enum for activation types - /// - Activation = 50, - - /// - /// Scale + Bias layer - /// - ScaleBias = 51, - - /// - /// Normalization layer - /// - Normalization = 52, - - /// - /// LRN (Local Response Normalization) layer - /// - LRN = 53, - - /// - /// Dropout layer (does nothing in inference) - /// - Dropout = 60, - - /// - /// Random sampling from normal distribution layer - /// - RandomNormal = 64, - - /// - /// Random sampling from uniform distribution layer - /// - RandomUniform = 65, - - /// - /// Random sampling from multinomial distribution layer - /// - Multinomial = 66, - - /// - /// OneHot layer - /// - OneHot = 67, - - /// - /// TopK indices layer - /// - TopKIndices = 68, - - /// - /// TopK values layer - /// - TopKValues = 69, - - /// - /// NonZero layer - /// - NonZero = 70, - - /// - /// Range layer - /// - Range = 71, - - /// - /// RoiAlign layer - /// - RoiAlign = 72, - - /// - /// Addition layer - /// - Add = 100, - - /// - /// Subtraction layer - /// - Sub = 101, - - /// - /// Multiplication layer - /// - Mul = 102, - - /// - /// Division layer - /// - Div = 103, - - /// - /// Power layer - /// - Pow = 104, - - /// - /// Min layer - /// - Min = 110, - - /// - /// Max layer - /// - Max = 111, - - /// - /// Mean layer - /// - Mean = 112, - - /// - /// Reduce L1 layer (not yet implemented) - /// - ReduceL1 = 120, // TODO: NOT IMPLEMENTED - - /// - /// Reduce L2 layer (not yet implemented) - /// - ReduceL2 = 121, // TODO: NOT IMPLEMENTED - - /// - /// Reduce LogSum layer (not yet implemented) - /// - ReduceLogSum = 122, // TODO: NOT IMPLEMENTED - - /// - /// Reduce LogSumExp layer (not yet implemented) - /// - ReduceLogSumExp = 123, // TODO: NOT IMPLEMENTED - - /// - /// Reduce with Max layer - /// - ReduceMax = 124, - - /// - /// Reduce with Mean layer - /// - ReduceMean = 125, - - /// - /// Reduce with Min layer - /// - ReduceMin = 126, - - /// - /// Reduce with Prod layer - /// - ReduceProd = 127, - - /// - /// Reduce with Sum layer - /// - ReduceSum = 128, - - /// - /// Reduce with SumSquare layer (not yet implemented) - /// - ReduceSumSquare = 129, // TODO: NOT IMPLEMENTED - - /// - /// Logic operation: Greater layer - /// - Greater = 140, - - /// - /// Logic operation: GreaterEqual layer - /// - GreaterEqual = 141, - - /// - /// Logic operation: Less layer - /// - Less = 142, - - /// - /// Logic operation: LessEqual layer - /// - LessEqual = 143, - - /// - /// Logic operation: Equal layer - /// - Equal = 144, - - /// - /// Logic operation: LogicalOr layer - /// - LogicalOr = 145, - - /// - /// Logic operation: LogicalAnd layer - /// - LogicalAnd = 146, - - /// - /// Logic operation: LogicalNot layer - /// - LogicalNot = 147, - - /// - /// Logic operation: LogicalXor layer - /// - LogicalXor = 148, - - /// - /// Logic operation: Where layer - /// - Where = 149, - - /// - /// Logic operation: Sign layer - /// - Sign = 150, - - /// - /// Generic Pad layer (not fully supported) - /// - Pad = 159, // TODO: NOT IMPLEMENTED - - /// - /// Reflection padding layer - /// - Pad2DReflect = 160, - - /// - /// Symmetric padding layer - /// - Pad2DSymmetric = 161, - - /// - /// Edge padding layer - /// - Pad2DEdge = 162, - - /// - /// ArgMax layer - /// - ArgMax = 163, - - /// - /// ArgMin layer - /// - ArgMin = 164, - - /// - /// ConstantOfShape layer - /// - ConstantOfShape = 199, - - /// - /// Flatten layer - /// - Flatten = 200, - - /// - /// Reshape layer - /// - Reshape = 201, - - /// - /// Transpose layer - /// - Transpose = 202, - - /// - /// Squeeze layer (not fully supported) - /// - Squeeze = 203, // TODO: NOT IMPLEMENTED - - /// - /// Unsqueeze layer (not fully supported) - /// - Unsqueeze = 204, // TODO: NOT IMPLEMENTED - - /// - /// Gather layer - /// - Gather = 205, - - /// - /// Depth to space layer - /// - DepthToSpace = 206, - - /// - /// Space to depth layer - /// - SpaceToDepth = 207, - - /// - /// Expand layer - /// - Expand = 208, - - /// - /// 2D Resample layer - /// - Resample2D = 209, - - /// - /// Concat layer - /// - Concat = 210, - - /// - /// Strided slice layer - /// - StridedSlice = 211, - - /// - /// Tile layer - /// - Tile = 212, - - /// - /// Shape layer - /// - Shape = 213, - - /// - /// Non max suppression layer - /// - NonMaxSuppression = 214, - - /// - /// LSTM - /// - LSTM = 215, - - /// - /// ScatterND - /// - ScatterND = 216, - - /// - /// Constant load layer (for internal use) - /// - Load = 255 - } - - //Keep in sync with Tensor.cginc ACTIVATION defines and IsActivationFusable() methods in ModelBuilder.cs and FuseActivationsPass.cs - /// - /// Fused activations enum - /// - public enum FusedActivation - { - /// - /// None - /// - None = Activation.None, - - /// - /// Relu - /// - Relu = Activation.Relu, - - /// - /// Tanh - /// - Tanh = Activation.Tanh, - - /// - /// Softplus - /// - Softplus = Activation.Softplus, - - /// - /// Sigmoid - /// - Sigmoid = Activation.Sigmoid, - - /// - /// Relu6 - /// - Relu6 = Activation.Relu6, - - /// - /// Swish - /// - Swish = Activation.Swish, - - /// - /// Neg - /// - Neg = Activation.Neg, - - /// - /// Sqrt - /// - Sqrt = Activation.Sqrt, - - /// - /// Exp - /// - Exp = Activation.Exp, - - /// - /// Log - /// - Log = Activation.Log, - - /// - /// Acos - /// - Acos = Activation.Acos, - - /// - /// Acosh - /// - Acosh = Activation.Acosh, - - /// - /// Asin - /// - Asin = Activation.Asin, - - /// - /// Asinh - /// - Asinh = Activation.Asinh, - - /// - /// Atan - /// - Atan = Activation.Atan, - - /// - /// Atanh - /// - Atanh = Activation.Atanh, - - /// - /// Cos - /// - Cos = Activation.Cos, - - /// - /// Cosh - /// - Cosh = Activation.Cosh, - - /// - /// Sin - /// - Sin = Activation.Sin, - - /// - /// Sinh - /// - Sinh = Activation.Sinh, - - /// - /// Tan - /// - Tan = Activation.Tan, - - /// - /// Erf - /// - Erf = Activation.Erf - } - - /// - /// Activation enum - /// - public enum Activation - { - /// - /// None - /// - None = 0, - - /// - /// Relu - /// - Relu = 1, - - /// - /// Softmax - /// - Softmax = 2, - - /// - /// Tanh - /// - Tanh = 3, - - /// - /// Sigmoid - /// - Sigmoid = 4, - - /// - /// Elu - /// - Elu = 5, - - /// - /// Relu6 - /// - Relu6 = 6, - - /// - /// LeakyRelu - /// - LeakyRelu = 7, - - /// - /// Selu - /// - Selu = 8, - - /// - /// Swish - /// - Swish = 9, - - /// - /// LogSoftmax - /// - LogSoftmax = 10, - - /// - /// Softplus - /// - Softplus = 11, - - /// - /// Softsign (not yet implemented) - /// - Softsign = 12, // TODO: NOT IMPLEMENTED - - /// - /// PRelu - /// - PRelu = 13, - - /// - /// Hardmax (not yet implemented) - /// - Hardmax = 20, // TODO: NOT IMPLEMENTED - - /// - /// HardSigmoid - /// - HardSigmoid = 21, - - /// - /// Abs - /// - Abs = 100, - - /// - /// Neg - /// - Neg = 101, - - /// - /// Ceil - /// - Ceil = 102, - - /// - /// Clip - /// - Clip = 103, - - /// - /// Floor - /// - Floor = 104, - - /// - /// Round - /// - Round = 105, - - /// - /// Reciprocal - /// - Reciprocal = 110, - - /// - /// Sqrt - /// - Sqrt = 111, - - /// - /// Pow - /// - Pow = 112, - - /// - /// Exp - /// - Exp = 113, - - /// - /// Log - /// - Log = 114, - - /// - /// Acos - /// - Acos = 200, - - /// - /// Acosh - /// - Acosh = 201, - - /// - /// Asin - /// - Asin = 202, - - /// - /// Asinh - /// - Asinh = 203, - - /// - /// Atan - /// - Atan = 204, - - /// - /// Atanh - /// - Atanh = 205, - - /// - /// Cos - /// - Cos = 206, - - /// - /// Cosh - /// - Cosh = 207, - - /// - /// Sin - /// - Sin = 208, - - /// - /// Sinh - /// - Sinh = 209, - - /// - /// Tan - /// - Tan = 210, - - /// - /// Erf - /// - Erf = 211 - } - - /// - /// Auto padding enum - /// - public enum AutoPad - { - /// - /// NotSet - /// - NotSet = 1, - - /// - /// Valid - /// - Valid = 0, - - /// - /// Same upper - /// - SameUpper = -1, - - /// - /// Same lower - /// - SameLower = -2, - } - - public enum PadMode - { - Constant = 0, - Reflect = 1, - Edge = 2, - Symetric = 3, - } - - /// - /// Depth to space mode enum - /// - public enum DepthToSpaceMode - { - /// - /// DCR (Depth Column Row) - /// - DCR, - - /// - /// CRD (Column Row Depth) - /// - CRD - } - - /// - /// ScatterND reduction mode - /// - public enum ScatterNDReductionMode - { - /// - /// None - /// - None = 0, - - /// - /// Add - /// - Add = 1, - - /// - /// Multiply - /// - Mul = 2, - } - - /// - /// Layer param data structure - /// - public struct DataSet - { - /// - /// Name - /// - public string name; - - /// - /// Shape - /// - public TensorShape shape; - - /// - /// Offset from start - /// - public Int64 offset; - - /// - /// Item size in bytes - /// - public Int32 itemSizeInBytes; - - /// - /// Dataset length - /// - public Int32 length; - } - - /// - /// Layer preservation flags - /// - [Flags] - public enum Flags - { - /// - /// No flags defined - /// - None = 0, - - /// - /// Preserve the layer (e.g. don't remove it in a model pass) - /// - Preserve = 1 << 1, - } - - /// - /// Layer name - /// - public string name; - - /// - /// Layer type - /// - public Type type; - - /// - /// Layer flags (not serialized) - used for conversion - /// - [NonSerialized] - public Flags flags; - - /// - /// Layer activation type - /// - public Activation activation; - - /// - /// Padding shape - /// - public Int32[] pad; - - /// - /// Stride - /// - public Int32[] stride; - - /// - /// Pooling - /// - public Int32[] pool; - - /// - /// Axis - /// - public Int32 axis; - - /// - /// Alpha - /// - public float alpha; - - /// - /// Beta - /// - public float beta; - - /// - /// Input (layer) names - /// - public string[] inputs; - - /// - /// Output (layer) names (not serialized) - used for conversion - /// - [NonSerialized] - public string[] outputs; - - /// - /// Axes (not serialized) - used for conversion - /// - [NonSerialized] - public Int32[] axes; - - /// - /// Datasets bound to layer - /// - public DataSet[] datasets; - - /// - /// Flat weights array (for actual shape see `datasets`) - /// - public BarracudaArray weights; - - private Layer(string layerName) - { - name = layerName; - type = Type.Nop; - activation = Activation.None; - pad = new int[0]; - stride = new int[0]; - pool = new int[0]; - axis = -1; - alpha = 1.0f; - beta = 0.0f; - inputs = new string[0]; - datasets = new DataSet[0]; - weights = new BarracudaArray(0);//TODO fp16? - } - - /// - /// Constructs Layer - /// - /// layer name - /// layer type - /// layer activation type - public Layer(string layerName, Type layerType, Activation activationType = Activation.None) : this(layerName) - { - type = layerType; - activation = activationType; - } - - /// - /// Constructs Activation Layer - /// - /// layer name - /// layer activation type - public Layer(string layerName, Activation activationType) : this(layerName) - { - type = Type.Activation; - activation = activationType; - } - - /// - /// Layer summary string - /// - /// layer summary string - public override string ToString() - { - return ($"name:{name}, activation:{activation}, inputs:[{string.Join(",", inputs)}], " + - $"pad:[{string.Join(",", pad)}], stride:[{string.Join(",", stride)}], pool:[{string.Join(",", pool)}], " + - $"alpha:{alpha}, beta:{beta}, axis:{axis}, " + - $"weights:[{string.Join(", ", datasets.Select(x => $"{x.name} {x.shape}"))}]".Replace(name+"/","").Replace(name+" ","")). - Replace("activation:None, ", "").Replace("inputs:[], ", "").Replace("pad:[], ", ""). - Replace("stride:[], ", "").Replace("stride:[1,1], ", "").Replace("pool:[], ", ""). - Replace("alpha:1, ", "").Replace("beta:0, ", "").Replace("axis:-1, ", ""). - Replace("weights:[]", ""); - } - - /// - /// Converts DataSet to Tensor - /// - /// dataset index - /// Tensor - public Tensor DataSetToTensor(int index) - { - Assert.IsTrue(index < datasets.Length); - var ds = datasets[index]; - return new Tensor(ds.shape, new SharedArrayTensorData(weights, ds.shape, (int)ds.offset), ds.name); - } - - /// - /// Converts Tensor to DataSet - /// - /// input `Tensor` - /// dataset index - public void ApplyTensorToDataSet(Tensor X, int index) - { - Assert.IsTrue(index < datasets.Length); - var ds = datasets[index]; - ds.shape = X.shape; - BarracudaArray.Copy(X.ToReadOnlyArray(), 0, weights, ds.offset, ds.shape.length); - datasets[index] = ds; - } -} - -/// -/// Neural Net Model data structure -/// -public class Model -{ - /// - /// Model version, incremented with each data structure change - /// - public const int Version = 20; - internal const int LastVersionWithout8DSupport = 16; - public const int LastVersionWithoutWeightsAlignmentSupport = 18; - internal const int WeightsAlignment = 16; - - /// - /// Input data structure - /// - public struct Input - { - /// - /// Name - /// - public string name; - - /// - /// Shape as `int` array - /// - public Int32[] shape; // input shape can contain -1 for unspecified dimensions - - /// - /// Input rank - /// - public int rank; - - /// - /// Creates input structure with specified name - /// - /// name - /// Input structure - public Input WithName(string name) - { - return new Input {name = name, shape = shape}; - } - } - - /// - /// Memory data structure. Used by recurrent models to store information about recurrent inputs/outputs - /// - public struct Memory - { - /// - /// Shape - /// - public TensorShape shape; - - /// - /// Input name - /// - public string input; - - /// - /// Output name - /// - public string output; - } - - /// - /// Model layout - /// - public string layout = String.Empty; - - /// - /// All model inputs - /// - public List inputs = new List(); - - /// - /// All model outputs - /// - public List outputs = new List(); - - /// - /// All model memories - /// - public List memories = new List(); - - /// - /// All model layers - /// - public List layers = new List(); - - #region Importer info - /// - /// Model source metadata string - /// - public string IrSource = "Script"; - - /// - /// Model ONNX version metadata string - /// - public string IrVersion = "NA"; - - /// - /// Model producer metadata string - /// - public string ProducerName = "Script"; - - /// - /// Model import warnings - /// - public List Warnings { get; } = new List(); - - /// - /// Importer warning data structure - /// - public class ImporterWarning - { - /// - /// Message - /// - public string Message { get; } - - /// - /// Layer name - /// - public string LayerName { get; } - - /// - /// Constructs ImporterWarning - /// - /// layer name - /// message - public ImporterWarning(string layer, string msg) - { - Message = msg; - LayerName = layer; - } - } - - /// - /// Metadata properties associated with the model - /// - public Dictionary Metadata { get; private set; } = new Dictionary(); - #endregion - - /// - /// Build shallow copy of the model - /// - /// shallow copy of the model - public Model ShallowCopy() - { - var model = new Model(); - model.inputs.AddRange(inputs); - model.outputs.AddRange(outputs); - model.memories.AddRange(memories); - model.layers.AddRange(layers); - - model.IrSource = IrSource; - model.IrVersion = IrVersion; - model.ProducerName = ProducerName; - model.Warnings.AddRange(Warnings); - model.Metadata = new Dictionary(Metadata); - return model; - } - - /// - /// Model summary string - /// - /// Model summary string - public override string ToString() - { - // weights are not loaded for UI, recompute size - var totalUniqueWeights = 0; - for (var l = 0; l < layers.Count; ++l) - for (var d = 0; d < layers[l].datasets.Length; ++d) - totalUniqueWeights += layers[l].datasets[d].length; - - return $"inputs: [{string.Join(", ", inputs.Select(i => $"{i.name} ({string.Join(",", i.shape)})"))}], " + - $"memories: [{string.Join(", ", memories.Select(m => $"{m.input} {m.shape} {m.output}"))}], " + - $"outputs: [{string.Join(", ", outputs)}] " + - $"\n{layers.Count} layers, {totalUniqueWeights:n0} weights: \n{string.Join("\n", layers.Select(i => $"{i.type} ({i})"))}"; - } - - /// - /// Convert in place all model weights to given data type - /// - /// target type for moodel weights - internal void ConvertWeights(DataType type) - { - foreach (var layer in layers) - { - if (layer.weights != null && layer.weights.Type != type) - { - var sourceWeights = layer.weights; - var targetWeights = new BarracudaArray(layer.weights.Length, type); - BarracudaArray.Copy(sourceWeights, targetWeights); - layer.weights = targetWeights; - } - } - } -} - -/// -/// Model metadata extensions -/// -public static class ModelMetadataExtensions -{ - /// - /// Get model tensor by name - /// - /// Model - /// Tensor name - /// Tensor - static public Tensor GetTensorByName(this Model model, string name) - { - foreach (var l in model.layers) - foreach (var ds in l.datasets) - if (ds.name == name) - return new Tensor(ds.shape, - new SharedArrayTensorData(l.weights, ds.shape, (int)ds.offset), ds.name); - - return null; - } - - /// - /// Get model tensor shape by name - /// - /// Model - /// Tensor name - /// Tensor shape - /// - static public TensorShape? GetShapeByName(this Model model, string name) - { - foreach (var i in model.inputs) - if (i.name == name) - return new TensorShape(i.shape); - - TensorShape shape; - if (ModelAnalyzer.TryGetOutputTensorShape(model, name, out shape)) - return shape; - - foreach (var l in model.layers) - foreach (var ds in l.datasets) - if (ds.name == name) - return ds.shape; - - foreach (var mem in model.memories) - { - if (mem.input == name || mem.output == name) - return mem.shape; - } - - throw new System.Collections.Generic.KeyNotFoundException("Shape " + name + " not found!"); - } - - /// - /// Get count of layers that directly depend on specified input - /// - /// Model - /// input name - /// count of layers that directly depend on specified input - static public int GetDownStreamLayersCount(this Model model, string name) - { - return model.layers.Count(x => x.inputs.Contains(name)); - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Model.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Model.cs.meta deleted file mode 100644 index 564b709..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Model.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: b26b24090eb094bbbad7577bab770b25 -timeCreated: 1506364243 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/ModelBuilder.cs b/Packages/com.unity.barracuda/Runtime/Core/ModelBuilder.cs deleted file mode 100644 index 95c2a48..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/ModelBuilder.cs +++ /dev/null @@ -1,2406 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine.Assertions; - -namespace Unity.Barracuda -{ - /// - /// Class responsible for run-time model building from Neural Net primitives. - /// - public class ModelBuilder - { - readonly Model m_Model; - - /// - /// Model under construction - /// - public Model model => m_Model; - - /// - /// Create a model builder helper to construct the underlying Model. - /// - /// base model to continue building on - public ModelBuilder(Model model = null) - { - if (model == null) - model = new Model(); - m_Model = model; - } - - /// - /// Add an input to the model - /// - /// input name - /// input shape - /// input rank - /// Input instance - public Model.Input Input(string name, Int32[] shape, int rank) - { - m_Model.inputs.Add(new Model.Input {name = name, shape = shape, rank = rank}); - - return m_Model.inputs.Last(); - } - - /// - /// Add an input to the model - /// - /// input name - /// input shape - /// Input instance - public Model.Input Input(string name, TensorShape shape) - { - m_Model.inputs.Add(new Model.Input {name = name, shape = shape.ToArray()}); - - return m_Model.inputs.Last(); - } - - /// - /// Add an input to the model - /// - /// input name - /// input batch size - /// input channel count - /// Input instance - public Model.Input Input(string name, Int32 batch, Int32 channels) - { - m_Model.inputs.Add(new Model.Input {name = name, shape = new []{batch, 1, 1, channels}, rank = 2}); - - return m_Model.inputs.Last(); - } - - /// - /// Add an input to the model - /// - /// input name - /// input batch size - /// input height - /// input width - /// input channel count - /// Input instance - public Model.Input Input(string name, Int32 batch, Int32 height, Int32 width, Int32 channels) - { - m_Model.inputs.Add(new Model.Input {name = name, shape = new []{batch, height, width, channels}, rank = 4}); - - return m_Model.inputs.Last(); - } - - /// - /// Add an output to the model - /// - /// reference object, could be `string`, `Layer` or `Model.Input` - /// Output instance - public string Output(object input) - { - var name = ResolveInput(input); - if (!m_Model.outputs.Contains(name)) - m_Model.outputs.Add(name); - return name; - } - - /// - /// Add memory to the model - /// - /// reference input object, could be `string`, `Layer` or `Model.Input` - /// reference output object, could be `string`, `Layer` or `Model.Input` - /// memory shape - /// Memory instance - public Model.Memory Memory(object input, object output, TensorShape shape) - { - m_Model.memories.Add(new Model.Memory { - shape = shape, - input = ResolveInput(input), - output = ResolveInput(output)}); - - return m_Model.memories.Last(); - } - - private string ResolveInput(object input) - { - if (input == null) - return null; - - if (input is string) - return input as string; - - if (input is Layer) - return (input as Layer).name; - - if (input is Model.Input) - return ((Model.Input)input).name; - - throw new ArgumentException($"Unsupported input type: {input.GetType()}"); - } - - /// - /// Allow to load a tensor from constants. - /// - /// Layer name - /// data Tensor - /// insertion index in Layer list - /// constant rank - /// created Layer instance - public Layer Const(string name, Tensor tensor, int insertionIndex = -1, int rank = -1) - { - Layer layer = new Layer(name, Layer.Type.Load); - if (rank >= 0) - layer.axis = rank; - layer.datasets = new Layer.DataSet[1]; - layer.datasets[0].name = name; - layer.datasets[0].shape = tensor.shape; - layer.datasets[0].itemSizeInBytes = 4;//TODO fp16 - layer.datasets[0].length = tensor.shape.length; - layer.datasets[0].offset = 0; - layer.weights = new BarracudaArray(tensor.shape.length, tensor.dataType); - tensor.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - - if (insertionIndex < 0 || insertionIndex >= m_Model.layers.Count) - m_Model.layers.Add(layer); - else - m_Model.layers.Insert(insertionIndex, layer); - - return layer; - } - - /// - /// Apply per channel scale and bias. - /// Scale and bias should be tensors of shape [1,1,1, input.shape[C]] - /// - /// Output shape is same as input. - /// - /// Layer name - /// input node - /// scale data Tensor - /// bias data Tensor - /// created Layer instance - public Layer ScaleBias(string name, object input, Tensor scale, Tensor bias) - { - Layer layer = new Layer(name,Layer.Type.ScaleBias); - layer.inputs = new [] {ResolveInput(input)}; - layer.datasets = new Layer.DataSet[2]; - layer.datasets[0].name = $"{name}/S"; - layer.datasets[0].shape = scale.shape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = scale.shape.length; - layer.datasets[0].offset = 0; - layer.datasets[1].name = $"{name}/B"; - layer.datasets[1].shape = bias.shape; - layer.datasets[1].itemSizeInBytes = 4; - layer.datasets[1].length = bias.shape.length; - layer.datasets[1].offset = scale.shape.length; - Assert.AreEqual(scale.dataType, bias.dataType); - layer.weights = new BarracudaArray(scale.shape.length + bias.shape.length, scale.dataType); - - scale.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - bias.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, layer.datasets[1].offset); - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Apply Local Response Normalization as described in the AlexNet paper - /// https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf - /// It normalizes over local input regions, local region being defined across channels. - /// - /// For an element X[n, h, w, c] in a tensor of shape (N x H x W x C), its region is X[n, h, w, cRange] - /// with cRange = [max(0, c - floor((size - 1) / 2)), min(C - 1, c + ceil((size - 1) / 2)]. - /// - /// y = x / Pow( bias + alpha * sum( xOverLocalRange ^ 2 ) / size, beta) - /// - /// Output shape is same as input. - /// - /// Layer name - /// input node - /// alpha - /// beta - /// bias - /// size - /// created Layer instance - public Layer LRN(string name, object input, float alpha, float beta, float bias, int size) - { - Layer layer = new Layer(name, Layer.Type.LRN); - layer.inputs = new [] {ResolveInput(input)}; - layer.alpha = alpha; - layer.beta = beta; - layer.datasets = new Layer.DataSet[1]; - layer.datasets[0].name = $"{name}/B"; - layer.datasets[0].shape = new TensorShape(1,1,1,1); - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = 1; - layer.datasets[0].offset = 0; - layer.weights = new BarracudaArray(1); - layer.weights[0] = bias; - layer.pool = new int[1]; - layer.pool[0] = size; - m_Model.layers.Add(layer); - - return layer; - } - - - /// - /// Takes a tensor as input and outputs a tensor containing the shape of the input tensor. - /// Optionally, if an axis is specified, then it will return only that part of the shape. - /// - /// Layer name - /// input node - /// axis - /// created Layer instance - public Layer Shape(string name, object input, int axis = -1) - { - var layer = new Layer(name, Layer.Type.Shape); - layer.inputs = new [] { ResolveInput(input) }; - layer.axis = axis; // If positive, then this will return the specific axis of the shape - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Carries out instance normalization as described in the paper https://arxiv.org/abs/1607.08022 - /// y = scale * (x - mean) / sqrt(variance + epsilon) + bias, where mean and variance are computed per instance per channel. - /// Scale and bias should be tensors of shape [1,1,1, input.shape[C]] - /// - /// Output shape is same as input. - /// - /// Layer name - /// input node - /// scale - /// bias - /// epsilon - /// created Layer instance - public Layer Normalization(string name, object input, Tensor scale, Tensor bias, float epsilon = 1e-5f) - { - Layer layer = new Layer(name, Layer.Type.Normalization); - layer.inputs = new [] {ResolveInput(input)}; - layer.datasets = new Layer.DataSet[2]; - layer.datasets[0].name = $"{name}/S"; - layer.datasets[0].shape = scale.shape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = scale.shape.length; - layer.datasets[0].offset = 0; - layer.datasets[1].name = $"{name}/B"; - layer.datasets[1].shape = bias.shape; - layer.datasets[1].itemSizeInBytes = 4; - layer.datasets[1].length = bias.shape.length; - layer.datasets[1].offset = scale.shape.length; - Assert.AreEqual(scale.dataType, bias.dataType); - layer.weights = new BarracudaArray(scale.shape.length + bias.shape.length, scale.dataType); - layer.beta = epsilon; - - scale.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - bias.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, layer.datasets[1].offset); - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Apply a densely connected layer (aka general matrix multiplication or GEMM) - /// Bias should be a tensor with (batch == input.shape[H] * input.shape[W] * input.shape[C]) and only one other dimensions of size > 1 - /// Weight should be a tensor with (batch == 1) and (height * width * channels == bias.shape[B] * ) - /// - /// Output shape is [input.shape[B], 1, 1, Weight.shape[H]*Weight.shape[W]*Weight.shape[C]] - /// - /// Layer name - /// input node - /// weight data Tensor - /// bias data Tensor - /// created Layer instance - public Layer Dense(string name, object input, Tensor weight, Tensor bias) - { - Layer layer = new Layer(name, Layer.Type.Dense); - layer.inputs = new [] {ResolveInput(input)}; - layer.datasets = new Layer.DataSet[2]; - layer.datasets[0].name = $"{name}/W"; - layer.datasets[0].shape = weight.shape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = weight.shape.length; - layer.datasets[0].offset = 0; - layer.datasets[1].name = $"{name}/B"; - layer.datasets[1].shape = bias.shape; - layer.datasets[1].itemSizeInBytes = 4; - layer.datasets[1].length = bias.shape.length; - layer.datasets[1].offset = weight.shape.length; - Assert.AreEqual(weight.dataType, bias.dataType); - layer.weights = new BarracudaArray(weight.shape.length + bias.shape.length, weight.dataType); - - weight.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - bias.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, layer.datasets[1].offset); - - m_Model.layers.Add(layer); - - return layer; - } - /// - /// Rank 3 `Dense` layer - /// - /// Layer name - /// input node - /// weight data Tensor - /// bias data Tensor - /// created Layer instance - public Layer Dense3(string name, object input, Tensor weight, Tensor bias) - { - Layer layer = new Layer(name, Layer.Type.Dense3); - layer.inputs = new[] { ResolveInput(input) }; - layer.datasets = new Layer.DataSet[2]; - layer.datasets[0].name = $"{name}/W"; - layer.datasets[0].shape = weight.shape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = weight.shape.length; - layer.datasets[0].offset = 0; - layer.datasets[1].name = $"{name}/B"; - layer.datasets[1].shape = bias.shape; - layer.datasets[1].itemSizeInBytes = 4; - layer.datasets[1].length = bias.shape.length; - layer.datasets[1].offset = weight.shape.length; - Assert.AreEqual(weight.dataType, bias.dataType); - layer.weights = new BarracudaArray(weight.shape.length + bias.shape.length, weight.dataType); - - weight.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - bias.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, layer.datasets[1].offset); - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Applies matrix multiplication between A and B - /// - /// Layer name - /// first input node - /// second input node - /// created Layer instance - public Layer MatMul(string name, object input0, object input1) - { - var inputs = new[] { input0, input1 }; - Layer layer = new Layer(name, Layer.Type.MatMul); - layer.inputs = inputs.Select(i => ResolveInput(i)).ToArray(); - - m_Model.layers.Add(layer); - - return layer; - } - - private Layer Conv(string name, Layer.Type convType, object input, Int32[] stride, Int32[] pad, Int32[] outputPad, Tensor kernel, Tensor bias) - { - Layer layer = new Layer(name, convType); - layer.pad = pad; - layer.stride = stride; - layer.pool = outputPad; - layer.inputs = new [] {ResolveInput(input)}; - layer.datasets = new Layer.DataSet[2]; - layer.datasets[0].name = $"{name}/K"; - layer.datasets[0].shape = kernel.shape; - layer.datasets[0].itemSizeInBytes = 4; - layer.datasets[0].length = kernel.shape.length; - layer.datasets[0].offset = 0; - layer.datasets[1].name = $"{name}/B"; - layer.datasets[1].shape = bias.shape; - layer.datasets[1].itemSizeInBytes = 4; - layer.datasets[1].length = bias.shape.length; - layer.datasets[1].offset = kernel.shape.length; - Assert.AreEqual(kernel.dataType, bias.dataType); - layer.weights = new BarracudaArray(kernel.shape.length + bias.shape.length, kernel.dataType); - - kernel.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, 0); - bias.ToReadOnlyArray().CopyToBarracudaArray(layer.weights, layer.datasets[1].offset); - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Apply a spatial 2D convolution on H and W. - /// Stride should be of size 2 and format is [W, H]. - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// Kernel should be a tensor of shape [kernelHeight, kernelWidth, kernelDepth, kernelCount] - /// Bias should be a tensor with (batch == 1) and (height * width * channels == kernelCount) - /// - /// Output batch is same as input. - /// Output channel is kernel.kernelCount. - /// output.shape[H,W] = (input.shape[H,W] + pad[1,0] + pad[3,2] - kernel.shape[1,0]) / stride[1,0] + 1. - /// - /// Layer name - /// input node - /// stride - /// padding - /// kernel weight data Tensor - /// bias data Tensor - /// created Layer instance - public Layer Conv2D(string name, object input, Int32[] stride, Int32[] pad, Tensor kernel, Tensor bias) - { - return Conv(name, Layer.Type.Conv2D, input, stride, pad, new int[0], kernel, bias); - } - - /// - /// Apply a spatial 3D convolution on H, W and D. - /// Stride should be of size 3 and format is [W, H, D]. - /// Pad should be of size 6 and format is [pre W, pre H, pre D, post W, post H, post D]. - /// Kernel should be a tensor of shape [kernelSpatialHeight, kernelSpatialWidth, kernelSpatialDepth, kernelDepth, kernelCount] - /// Bias should be a tensor with (batch == 1) and (height * width * channels == kernelCount) - /// - /// Output batch is same as input. - /// Output channel is kernel.kernelCount. - /// output.shape[D,H,W] = (input.shape[D,H,W] + pad[2,1,0] + pad[5,4,3] - kernel.shape[2,1,0]) / stride[2,1,0] + 1. - /// - /// Layer name - /// input node - /// stride - /// padding - /// kernel weight data Tensor - /// bias data Tensor - /// created Layer instance - public Layer Conv3D(string name, object input, Int32[] stride, Int32[] pad, Tensor kernel, Tensor bias) - { - return Conv(name, Layer.Type.Conv3D, input, stride, pad, new int[0], kernel, bias); - } - - /// - /// Apply a spatial 2D depthwise convolution on H and W. - /// Stride should be of size 2 and format is [W, H]. - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// Kernel should be a tensor of shape [kernelHeight, kernelWidth, kernelDepth, kernelCount] - /// Thus input must have a channel dimension of 1 - /// Bias should be a tensor with (batch == 1) and (height * width * channels == kernelCount) - /// - /// Output batch is same as input. - /// Output channel is kernel.shape[3]. - /// output.shape[H,W] = (input.shape[H,W] + pad[1,0] + pad[3,2] - kernel.shape[1,0]) / stride[1,0] + 1. - /// - /// Layer name - /// input node - /// stride - /// padding - /// kernel weight data Tensor - /// bias data Tensor - /// created Layer instance - public Layer DepthwiseConv2D(string name, object input, Int32[] stride, Int32[] pad, Tensor kernel, Tensor bias) - { - return Conv(name, Layer.Type.DepthwiseConv2D, input, stride, pad, new int[0], kernel, bias); - } - - /// - /// Apply a spatial 2D transposed convolution on H and W. - /// Stride should be of size 2 and format is [W, H]. - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// Kernel should be a tensor of rank 4 of dimensions [kernelHeight, kernelWidth, kernelDepth, kernelCount] - /// Bias should be a tensor with (batch == 1) and (height * width * channels == kernelCount) - /// OutputPad should be of length 0 or 2, format is [W, H]. - /// If OutputPad length is 0 it will be defaulted to: - /// OutputPad[W,H] = (input.shape[W,H] * stride[0,1] + pad[0,1] + pad[2,3] - [kernelWidth, kernelHeight]) % stride[0,1] - /// - /// Output batch is same as input. - /// Output channel is kernel.shape[3]. - /// output.shape[H,W] = (input.shape[H,W]-1) * stride[0,1] - (pad[1,0] + pad[3,2]) + [kernelWidth, kernelHeight] + OutputPad[W,H] - /// - /// Layer name - /// input node - /// stride - /// padding - /// output padding - /// kernel weight data Tensor - /// bias data Tensor - /// created Layer instance - public Layer Conv2DTrans(string name, object input, Int32[] stride, Int32[] pad, Int32[] outputPad, Tensor kernel, Tensor bias) - { - return Conv(name, Layer.Type.Conv2DTrans, input, stride, pad, outputPad, kernel, bias); - } - - private Layer Pool(Layer.Type type, string name, object input, Int32[] pool, Int32[] stride, Int32[] pad) - { - Layer layer = new Layer(name, type); - layer.pad = pad; - layer.stride = stride; - layer.pool = pool; - layer.inputs = new [] {ResolveInput(input)}; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Apply 'average' pooling by downscaling H and W dimension according to `pool`, `stride` and `pad`. - /// Pool and stride should be of size 2 and format is [W, H]. - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// - /// Output batch and channels dimensions the same as input. - /// output.shape[H,W] = (input.shape[H,W] + pad[1,0] + pad[3,2] - pool[1,0]) / stride[1,0] + 1. - /// - /// Layer name - /// input node - /// pooling - /// stride - /// padding - /// created Layer instance - public Layer AvgPool2D(string name, object input, Int32[] pool, Int32[] stride, Int32[] pad) - { - return Pool(Layer.Type.AvgPool2D, name, input, pool, stride, pad); - } - - /// - /// Apply 'max' pooling by downscaling H and W dimension according to `pool`, `stride` and `pad`. - /// Pool and stride should be of size 2 and format is [W, H]. - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// - /// Output batch and channels dimensions the same as input. - /// output.shape[H,W] = (input.shape[H,W] + pad[1,0] + pad[3,2] - pool[1,0]) / stride[1,0] + 1. - /// - /// Layer name - /// input node - /// pooling - /// stride - /// padding - /// created Layer instance - public Layer MaxPool2D(string name, object input, Int32[] pool, Int32[] stride, Int32[] pad) - { - return Pool(Layer.Type.MaxPool2D, name, input, pool, stride, pad); - } - - /// - /// Apply 'average' pooling by downscaling H and W dimension to [1,1] - /// - /// Layer name - /// input node - /// created Layer instance - public Layer GlobalAvgPool2D(string name, object input) - { - return Pool(Layer.Type.GlobalAvgPool2D, name, input, new int[0], new int[0], new int[0]); - } - - /// - /// Apply 'max' pooling by downscaling H and W dimension to [1,1] - /// - /// Layer name - /// input node - /// created Layer instance - public Layer GlobalMaxPool2D(string name, object input) - { - return Pool(Layer.Type.GlobalMaxPool2D, name, input, new int[0], new int[0], new int[0]); - } - - /// - /// Upsample the input tensor by scaling W and H by upsample[0] and upsample[1] respectively. - /// `bilinear` allow to choose between nearest neighbor or bilinear upsampling. - /// - /// Layer name - /// input node - /// upsampling - /// use bilinear - /// created Layer instance - public Layer Upsample2D(string name, object input, Int32[] upsample, bool bilinear) - { - Layer layer = new Layer(name, Layer.Type.Upsample2D); - layer.pool = upsample; - layer.axis = bilinear ? 1: -1; - layer.inputs = new [] {ResolveInput(input)}; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Upsample the input tensor - /// - /// Layer name - /// source input node - /// scale input node - /// use bilinear - /// created Layer instance - public Layer Upsample2D(string name, object source, object scale, bool bilinear) - { - Layer layer = new Layer(name, Layer.Type.Upsample2D); - layer.axis = bilinear ? 1: -1; - layer.inputs = new[] { ResolveInput(source), ResolveInput(scale) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Upsample the input tensor by scaling W,H and D by upsample[0], upsample[1] and upsample[2] respectively. - /// `trilinear` allow to choose between nearest neighbor or trilinear upsampling. - /// - /// Layer name - /// input node - /// scaling factors array [W,H,D] - /// trilinear flag - /// created Layer instance - public Layer Upsample3D(string name, object input, Int32[] upsample, bool trilinear) - { - Layer layer = new Layer(name, Layer.Type.Upsample3D); - layer.pool = upsample; - layer.axis = trilinear ? 1: -1; - layer.inputs = new [] {ResolveInput(input)}; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Upsample the input tensor by scaling W,H and D by scale[0], scale[1] and scale[2] respectively. - /// `trilinear` allow to choose between nearest neighbor or trilinear upsampling. - /// - /// Layer name - /// input node - /// scale Tensor - /// trilinear flag - /// created Layer instance - public Layer Upsample3D(string name, object source, object scale, bool trilinear) - { - Layer layer = new Layer(name, Layer.Type.Upsample3D); - layer.axis = trilinear ? 1: -1; - layer.inputs = new[] { ResolveInput(source), ResolveInput(scale) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Resample2D scales the input tensor to the given resolution (W=size[0], H=size[1]). - /// `bilinear` allows to choose between nearest neighbour or bilinear sampling. - /// - /// Layer name - /// input node - /// size - /// use bilinear - /// created Layer instance - public Layer Resample2D(string name, object input, Int32[] size, bool bilinear) - { - Layer layer = new Layer(name, Layer.Type.Resample2D); - layer.pool = size; - layer.axis = bilinear ? 1 : -1; - layer.inputs = new[] { ResolveInput(input) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Resample2D scales the input tensor to the given resolution (W=size[0], H=size[1]). - /// `bilinear` allows to choose between nearest neighbour or bilinear sampling. - /// - /// Layer name - /// input node - /// size tensor - /// use bilinear - /// created Layer instance - internal Layer Resample2D(string name, object input, object size, bool bilinear) - { - Layer layer = new Layer(name, Layer.Type.Resample2D); - layer.axis = bilinear ? 1 : -1; - layer.inputs = new[] { ResolveInput(input), ResolveInput(size) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// DepthToSpace rearranges (permutes) data from depth into blocks of - /// spatial data. This is the reverse transformation of SpaceToDepth. - /// More specifically, this op outputs a copy of the input tensor where - /// values from the depth dimension are moved in spatial blocks to the - /// height and width dimensions. By default, mode = DCR. In the DCR mode, - /// elements along the depth dimension from the input tensor are rearranged - /// in the following order: depth, column, and then row. - /// In the CRD mode, elements along the depth dimension from the input - /// tensor are rearranged in the following order: column, row, and depth. - /// - /// Layer name - /// input node - /// block size - /// mode, see `Layer.DepthToSpaceMode` - /// created Layer instance - public Layer DepthToSpace(string name, object source, int blocksize, string mode) - { - Layer layer = new Layer(name, Layer.Type.DepthToSpace); - - layer.pool = new int[] { blocksize, blocksize }; - layer.axis = (int)(Layer.DepthToSpaceMode)Enum.Parse(typeof(Layer.DepthToSpaceMode), mode); - layer.inputs = new[] { ResolveInput(source) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// SpaceToDepth rearranges blocks of [blocksize, blocksize] spatial data into depth. - /// - /// Layer name - /// input node - /// block size - /// created Layer instance - public Layer SpaceToDepth(string name, object source, int blocksize) - { - Layer layer = new Layer(name, Layer.Type.SpaceToDepth); - - layer.pool = new int[] { blocksize, blocksize }; - layer.inputs = new[] { ResolveInput(source) }; - - m_Model.layers.Add(layer); - - return layer; - } - - - /// - /// Apply symbolic shape to input tensor. Symbolic shape can have up to one dimension specified as unknown (value -1). - /// - /// Layer name - /// input node - /// shape - /// rank - /// created Layer instance - public Layer Reshape(string name, object input, int[] shape, int rank = -1) - { - Layer layer = new Layer(name, Layer.Type.Reshape); - layer.pool = shape; - if (rank >= 0) - layer.pad = new[] { rank }; - layer.inputs = new [] {ResolveInput(input)}; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Creates a constant tensor populated with `value` as the same shape of `input`. - /// - /// Layer name - /// input node - /// value - /// created Layer instance - public Layer ConstantOfShape(string name, object input, float value) - { - Layer layer = new Layer(name, Layer.Type.ConstantOfShape); - layer.inputs = new[] { ResolveInput(input) }; - layer.alpha = value; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Apply shape to the input tensor. Number of elements in the shape must match number of elements in input tensor. - /// - /// Layer name - /// input node - /// shape - /// created Layer instance - public Layer Reshape(string name, object input, TensorShape shape) - { - return Reshape(name, input, shape.ToArray()); - } - - /// - /// Return a tensor of the shape given as tensor. - /// - /// Layer name - /// input node - /// shape - /// created Layer instance - public Layer Reshape(string name, object input, object shape) - { - Layer layer = new Layer(name, Layer.Type.Reshape); - layer.inputs = new [] {ResolveInput(input), ResolveInput(shape)}; - layer.axis = 1; // Use tensor value as the shape; -1 is legacy for using the shape of input tensor - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Broadcast the input tensor following the given shape and similar to - /// numpy.array(input) * numpy.ones(shape). Two corresponding dimension - /// must have the same value, or the input dimension is 1. - /// - /// Layer name - /// input node - /// shape - /// created Layer instance - public Layer Expand(string name, object input, int[] shape) - { - Layer layer = new Layer(name, Layer.Type.Expand); - layer.inputs = new[] { ResolveInput(input) }; - layer.pool = shape; - - m_Model.layers.Add(layer); - - return layer; - } - internal Layer Expand(string name, object input, object shape) - { - Layer layer = new Layer(name, Layer.Type.Expand); - layer.inputs = new[] { ResolveInput(input), ResolveInput(shape) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// From a Tensor of shape [S,R,N,T,D,H,W,C] return a tensor of shape [S,R,N,1,1,1,1,T*D*H*W*C] - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Flatten(string name, object input) - { - Layer layer = new Layer(name, Layer.Type.Flatten); - layer.inputs = new [] {ResolveInput(input)}; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Concatenate a list of tensors into a single tensor. All input tensors must have the same shape, except for the axis to concatenate on. - /// If axisIs8D==true axis rank is from [S,R,N,T,D,H,W,C] overwise from [N,H,W,C] - /// `axis` must be superior to -4 - /// `axis` must be inferior to 8 when axisIs8D==true or inferior to 4 if axisIs8D==false - /// - /// Layer name - /// input node - /// axis - /// is axis 8D - /// created Layer instance - public Layer Concat(string name, object[] inputs, int axis = -1, bool axisIs8D=false) - { - Layer layer = new Layer(name, Layer.Type.Concat); - layer.axis = axisIs8D?axis:TensorExtensions.Convert4DTo8DAxis(axis); - layer.inputs = inputs.Select(i => ResolveInput(i)).ToArray(); - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Produces a slice of the input tensor along all axes. - /// The following rules apply: - /// begin=0, end=0, stride=1: copy the full range of elements from the given axis - /// begin=A, end=B, stride=1: copy the range [A, B) (excluding the Bth element) from the given axis - /// begin=A, end=B, stride=I: copy every Ith element in the range [A, B) from the given axis - /// begin=N, end=N, stride=0: shrink axis to a single Nth element - /// output.shape[*] = (ends[*] - starts[*]) / max(1, stride[*]) - /// - /// Layer name - /// input node - /// starts - /// ends - /// strides - /// created Layer instance - public Layer StridedSlice(string name, object input, int[] starts, int[] ends, int[] strides) - { - Layer layer = new Layer(name, Layer.Type.StridedSlice); - layer.inputs = new [] {ResolveInput(input)}; - layer.pad = starts; - layer.pool = ends; - layer.stride = strides; - - m_Model.layers.Add(layer); - - return layer; - } - - internal Layer StridedSlice(string name, object input, int[] starts, int[] ends, int[] strides, int[] axes) - { - Layer layer = new Layer(name, Layer.Type.StridedSlice); - layer.inputs = new[] { ResolveInput(input) }; - layer.pad = starts; - layer.pool = ends; - layer.stride = strides; - layer.axes = axes; - - m_Model.layers.Add(layer); - - return layer; - } - - internal Layer StridedSlice(string name, object input, object starts, object ends, object strides, object axes) - { - Layer layer = new Layer(name, Layer.Type.StridedSlice); - - List inputs = new List { ResolveInput(input), ResolveInput(starts), ResolveInput(ends) }; - if (strides != null) - inputs.Add(ResolveInput(strides)); - if (axes != null) - inputs.Add(ResolveInput(axes)); - layer.inputs = inputs.ToArray(); - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Constructs a tensor by repeating the input tensor the number of times given by repeats - /// For example input = [[1, 2], [3, 4]], repeats = [1, 2], Tile(input, repeats) = [[1, 2, 1, 2], [3, 4, 3, 4]] - /// - /// Layer name - /// input node - /// tile repeats - /// created Layer instance - public Layer Tile(string name, object input, int[] repeats) - { - Layer layer = new Layer(name, Layer.Type.Tile); - layer.inputs = new[] { ResolveInput(input) }; - layer.pool = repeats; - - m_Model.layers.Add(layer); - - return layer; - } - internal Layer Tile(string name, object input, object repeats) - { - Layer layer = new Layer(name, Layer.Type.Tile); - layer.inputs = new[] { ResolveInput(input), ResolveInput(repeats) }; - //layer.pool = repeats; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Make a shallow copy of the input tensor. - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Copy(string name, object input) - { - Layer layer = new Layer(name, Layer.Type.Nop); - layer.inputs = new [] {ResolveInput(input)}; - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Maps integer to one-hot vector of length equal to depth. - /// - /// Layer name - /// input node - /// depth - /// on value - /// off value - /// created Layer instance - public Layer OneHot(string name, object input, int depth, int on, int off) - { - Layer layer = new Layer(name, Layer.Type.OneHot); - layer.inputs = new [] {ResolveInput(input)}; - layer.pool = new int[] { depth }; - layer.alpha = on; - layer.beta = off; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Performs RoiAlign as described in the Mask R-CNN paper - /// - /// input - /// rois - /// batch indices - /// outputHeight - /// outputWidth - /// samplingRatio - /// spatialScale - /// output Tensor - public Layer RoiAlign(string name, object input, object rois, object batchIndices, int outputHeight, int outputWidth, int samplingRatio, float spatialScale) - { - Layer layer = new Layer(name, Layer.Type.RoiAlign); - layer.inputs = new[] { ResolveInput(input), ResolveInput(rois), ResolveInput(batchIndices) }; - layer.pool = new int[] { outputHeight, outputWidth }; - layer.axis = samplingRatio; - layer.alpha = spatialScale; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Retrieve the indices for top-K largest or smallest elements along a specified axis. - /// - /// Layer name - /// input node - /// k - /// axis - /// largest - /// sorted - /// created Layer instance - public Layer TopKIndices(string name, object input, object k, int axis, bool largest, bool sorted) - { - var layer = new Layer(name, Layer.Type.TopKIndices); - layer.inputs = new [] {ResolveInput(input), ResolveInput(k)}; - layer.axis = axis; - layer.pad = new [] { largest ? 1 : 0, sorted ? 1 : 0 }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Given the indices for top-K largest or smallest elements along a specified axis, return the values - /// - /// Layer name - /// input node - /// indices node - /// axis - /// created Layer instance - public Layer TopKValues(string name, object input, object indices, int axis) - { - var layer = new Layer(name, Layer.Type.TopKValues); - layer.inputs = new [] {ResolveInput(input), ResolveInput(indices)}; - layer.axis = axis; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Returns the indices of the elements that are non-zero - /// For example an input tensor of shape(1,2,3,1): - /// [0, 2, 3], - /// [4, 1, 0] - /// - /// Would return a tensor of shape(2, 1, 1, 4) - /// N = 2 as the rank of input tensor is 2. - /// C = 4 as there exist 3 non zero value in input tensor. - /// [0, 0, 1, 1], - /// [1, 2, 0, 1] - /// - /// Layer name - /// input node - /// created Layer instance - public Layer NonZero(string name, object input) - { - var layer = new Layer(name, Layer.Type.NonZero); - layer.inputs = new [] {ResolveInput(input) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Transpose - /// - /// Layer name - /// input node - /// list of axis permutations - /// created Layer instance - public Layer Transpose(string name, object input, int[] permutations) - { - Layer layer = new Layer(name, Layer.Type.Transpose); - layer.inputs = new[] { ResolveInput(input) }; - layer.pool = permutations; - - m_Model.layers.Add(layer); - - return layer; - } - - internal Layer Squeeze(string name, object input, int[] axes) - { - Layer layer = new Layer(name, Layer.Type.Squeeze); - layer.inputs = new[] { ResolveInput(input) }; - layer.pool = axes; - - m_Model.layers.Add(layer); - - return layer; - } - - internal Layer Squeeze(string name, object input, object axes) - { - Layer layer = new Layer(name, Layer.Type.Squeeze); - layer.inputs = new[] { ResolveInput(input), ResolveInput(axes) }; - - m_Model.layers.Add(layer); - - return layer; - } - internal Layer Unsqueeze(string name, object input, int[] axes) - { - Layer layer = new Layer(name, Layer.Type.Unsqueeze); - layer.inputs = new[] { ResolveInput(input) }; - layer.pool = axes; - - m_Model.layers.Add(layer); - - return layer; - } - - internal Layer Unsqueeze(string name, object input, object axes) - { - Layer layer = new Layer(name, Layer.Type.Unsqueeze); - layer.inputs = new[] { ResolveInput(input), ResolveInput(axes) }; - - m_Model.layers.Add(layer); - - return layer; - } - - private Layer Activation(Layer.Activation activation, string name, object input) - { - Layer layer = new Layer(name, activation); - layer.inputs = new [] {ResolveInput(input)}; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// No-op layer - /// - /// Layer name - /// input node - /// input rank - /// created Layer instance - public Layer Identity(string name, object input, int rank = -1) - { - Layer identity = Activation(Layer.Activation.None, name, input); - if (rank > 0) - identity.pad = new[] { rank }; - return identity; - } - - - /// - /// Element-wise `Relu` activation function: f(x) = max(0, x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Relu(string name, object input) - { - return Activation(Layer.Activation.Relu, name, input); - } - - /// - /// Element-wise `Pow` activation function: f(x) = pow(x, alpha) - /// - /// Layer name - /// input node - /// power input will be raised to - /// created Layer instance - public Layer Pow(string name, object input, float alpha) - { - Layer layer = Activation(Layer.Activation.Pow, name, input); - layer.alpha = alpha; - return layer; - } - - /// - /// Return the Softmax (normalized exponential) values of the input along provided axis. - /// Thus output will be of shape of the input. - /// If axisIs8D==true axis rank is from [S,R,N,T,D,H,W,C] otherwise from [N,H,W,C] - /// `axis` must be superior to -4 - /// `axis` must be inferior to 8 when axisIs8D==true or inferior to 4 if axisIs8D==false - /// - /// Layer name - /// input node - /// axis - /// is axis 8D - /// created Layer instance - public Layer Softmax(string name, object input, int axis=3, bool axisIs8D=false) - { - Layer layer = Activation(Layer.Activation.Softmax, name, input); - layer.axis = axisIs8D ? axis : TensorExtensions.Convert4DTo8DAxis(axis); - return layer; - } - - /// - /// Return the logSoftmax (log of normalized exponential) values of the input along flatWidth of the input tensor. - /// Thus output will be of shape of the input. - /// If axisIs8D==true axis rank is from [S,R,N,T,D,H,W,C] otherwise from [N,H,W,C] - /// `axis` must be superior to -4 - /// `axis` must be inferior to 8 when axisIs8D==true or inferior to 4 if axisIs8D==false - /// - /// Layer name - /// input node - /// axis - /// is axis 8D - /// created Layer instance - public Layer LogSoftmax(string name, object input, int axis=3, bool axisIs8D=false) - { - Layer layer = Activation(Layer.Activation.LogSoftmax, name, input); - layer.axis = axisIs8D ? axis : TensorExtensions.Convert4DTo8DAxis(axis); - return layer; - } - - /// - /// Element-wise `Sqrt` activation function - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Sqrt(string name, object input) - { - return Activation(Layer.Activation.Sqrt, name, input); - } - - /// - /// Element-wise `Tanh` activation function: f(x) = (1 - e^{-2x})/(1 + e^{-2x}) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Tanh(string name, object input) - { - return Activation(Layer.Activation.Tanh, name, input); - } - - /// - /// Element-wise `Softplus` activation function: f(x) = ln(e^{x} + 1) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Softplus(string name, object input) - { - return Activation(Layer.Activation.Softplus, name, input); - } - - /// - /// Element-wise `Sigmoid` activation function: f(x) = 1/(1 + e^{-x}) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Sigmoid(string name, object input) - { - return Activation(Layer.Activation.Sigmoid, name, input); - } - - /// - /// Element-wise `HardSigmoid` activation function: f(x) = maX(0, min(1, a * x + b)) - /// - /// Layer name - /// input node - /// alpha - /// beta - /// created Layer instance - public Layer HardSigmoid(string name, object input, float alpha = 0.2f, float beta = 0.5f) - { - Layer layer = new Layer(name, Layer.Activation.HardSigmoid); - layer.inputs = new[] { ResolveInput(input) }; - layer.alpha = alpha; - layer.beta = beta; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Element-wise `Elu` activation function: f(x) = x if x >= 0 else alpha*(e^x - 1) - /// alpha default is 1.0 - /// - /// Layer name - /// input node - /// alpha - /// created Layer instance - public Layer Elu(string name, object input, float alpha = 1.0f) - { - var layer = Activation(Layer.Activation.Elu, name, input); - layer.alpha = alpha; - return layer; - } - - /// - /// Element-wise `Relu6` activation function. f(x) = min(max(x, 0), 6) - /// see http://www.cs.utoronto.ca/~kriz/conv-cifar10-aug2010.pdf - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Relu6(string name, object input) - { - return Activation(Layer.Activation.Relu6, name, input); - } - - /// - /// Element-wise `LeakyRelu` activation function: f(x) = x if x >= 0 else alpha * x - /// alpha default is 0.01 - /// - /// Layer name - /// input node - /// alpha - /// created Layer instance - public Layer LeakyRelu(string name, object input, float alpha = 0.01f) - { - var layer = Activation(Layer.Activation.LeakyRelu, name, input); - layer.alpha = alpha; - return layer; - } - - /// - /// Element-wise `Selu` activation function: f(x) = gamma * x if x >= 0 else (alpha * e^x - alpha) - /// alpha default is 1.67326 - /// gamma default is 1.0507 - /// - /// Layer name - /// input node - /// alpha - /// gamma - /// created Layer instance - public Layer Selu(string name, object input, float alpha = 1.67326f, float gamma = 1.0507f) - { - var layer = Activation(Layer.Activation.Selu, name, input); - layer.alpha = alpha; - layer.beta = gamma; - return layer; - } - - /// - /// Element-wise `PRelu` activation function: f(x) = x if x >= 0 else slope * x - /// - /// Layer name - /// input node - /// slope input node - /// created Layer instance - public Layer PRelu(string name, object input, object slope) - { - object[] inputs = new [] {input, slope}; - - Layer layer = new Layer(name, Layer.Activation.PRelu); - layer.inputs = inputs.Select(i => ResolveInput(i)).ToArray(); - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Element-wise `Swish` activation function. f(x) = sigmoid(x) * x = x/(1 + e^{-x}) - /// see https://arxiv.org/abs/1710.05941 - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Swish(string name, object input) - { - return Activation(Layer.Activation.Swish, name, input); - } - - /// - /// Element-wise `Clip` function that limits values within an interval: f(x, xmin, xmax) = min(max(x, xmin), xmax) - /// - /// Layer name - /// input node - /// min - /// max - /// created Layer instance - public Layer Clip(string name, object input, float min, float max) - { - var layer = Activation(Layer.Activation.Clip, name, input); - layer.alpha = min; - layer.beta = max; - - return layer; - } - - /// - /// Element-wise `Exp` function that calculates exponential of the input: f(x) = e^{x} - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Exp(string name, object input) - { - return Activation(Layer.Activation.Exp, name, input); - } - - /// - /// Element-wise `Log` function that calculates the natural log of the input: f(x) = log(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Log(string name, object input) - { - return Activation(Layer.Activation.Log, name, input); - } - - /// - /// Element-wise function that flips the sign of the input: f(x) = -x - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Neg(string name, object input) - { - return Activation(Layer.Activation.Neg, name, input); - } - - /// - /// Element-wise function that calculates reciprocal of the input: f(x) = 1/x - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Reciprocal(string name, object input) - { - return Activation(Layer.Activation.Reciprocal, name, input); - } - - /// - /// Element-wise function that calculates absolute values of the input: f(x) = abs(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Abs(string name, object input) - { - return Activation(Layer.Activation.Abs, name, input); - } - - /// - /// Element-wise function that produces rounding towards the greatest integer less than or equal to the input value: f(x) = ceil(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Ceil(string name, object input) - { - return Activation(Layer.Activation.Ceil, name, input); - } - - /// - /// Element-wise function that produces rounding towards least integer greater than or equal to the input value: f(x) = floor(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Floor(string name, object input) - { - return Activation(Layer.Activation.Floor, name, input); - } - - /// - /// Element-wise function that produces rounding of the input value: f(x) = round(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Round(string name, object input) - { - return Activation(Layer.Activation.Round, name, input); - } - - /// - /// Element-wise `Acos` activation function: f(x) = acos(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Acos(string name, object input) - { - return Activation(Layer.Activation.Acos, name, input); - } - - /// - /// Element-wise `Acosh` activation function: f(x) = acosh(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Acosh(string name, object input) - { - return Activation(Layer.Activation.Acosh, name, input); - } - - /// - /// Element-wise `Asin` activation function: f(x) = asin(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Asin(string name, object input) - { - return Activation(Layer.Activation.Asin, name, input); - } - - /// - /// Element-wise `Asinh` activation function: f(x) = asinh(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Asinh(string name, object input) - { - return Activation(Layer.Activation.Asinh, name, input); - } - - /// - /// Element-wise `Atan` activation function: f(x) = atan(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Atan(string name, object input) - { - return Activation(Layer.Activation.Atan, name, input); - } - - /// - /// Element-wise `Atanh` activation function: f(x) = atanh(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Atanh(string name, object input) - { - return Activation(Layer.Activation.Atanh, name, input); - } - - /// - /// Element-wise `Cos` activation function: f(x) = cos(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Cos(string name, object input) - { - return Activation(Layer.Activation.Cos, name, input); - } - - /// - /// Element-wise `Cosh` activation function: f(x) = cosh(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Cosh(string name, object input) - { - return Activation(Layer.Activation.Cosh, name, input); - } - - /// - /// Element-wise `Sin` activation function: f(x) = sin(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Sin(string name, object input) - { - return Activation(Layer.Activation.Sin, name, input); - } - - /// - /// Element-wise `Sinh` activation function: f(x) = sinh(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Sinh(string name, object input) - { - return Activation(Layer.Activation.Sinh, name, input); - } - - /// - /// Element-wise `Tan` activation function: f(x) = tan(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Tan(string name, object input) - { - return Activation(Layer.Activation.Tan, name, input); - } - - /// - /// Element-wise `Erf` activation function: f(x) = erf(x) - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Erf(string name, object input) - { - return Activation(Layer.Activation.Erf, name, input); - } - - - private Layer Broadcast(Layer.Type type, string name, object[] inputs) - { - Layer layer = new Layer(name, type); - layer.inputs = inputs.Select(i => ResolveInput(i)).ToArray(); - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Element-wise `add` of each of the input tensors with multidimensional broadcasting support. - /// - /// Layer name - /// input nodes - /// created Layer instance - public Layer Add(string name, object[] inputs) - { - return Broadcast(Layer.Type.Add, name, inputs); - } - - /// - /// Element-wise `sub` of each of the input tensors with multidimensional broadcasting support. - /// - /// Layer name - /// input nodes - /// created Layer instance - public Layer Sub(string name, object[] inputs) - { - return Broadcast(Layer.Type.Sub, name, inputs); - } - - /// - /// Element-wise multiplication of each of the input tensors with multidimensional broadcasting support. - /// - /// Layer name - /// input nodes - /// created Layer instance - public Layer Mul(string name, object[] inputs) - { - return Broadcast(Layer.Type.Mul, name, inputs); - } - - /// - /// Element-wise division of each of the input tensors with multidimensional broadcasting support. - /// First element is divided by the 2nd, then result is divided by the third one and so on. - /// - /// Layer name - /// input nodes - /// created Layer instance - public Layer Div(string name, object[] inputs) - { - return Broadcast(Layer.Type.Div, name, inputs); - } - - /// - /// Element-wise pow of each of the input tensors with multidimensional broadcasting support. - /// First element get raised to the pow of the 2nd, then result is raised to the pow of the third one and so on. - /// - /// Layer name - /// input nodes - /// created Layer instance - public Layer Pow(string name, object[] inputs) - { - return Broadcast(Layer.Type.Pow, name, inputs); - } - - /// - /// Element-wise `min` of each of the input tensors with multidimensional broadcasting support. - /// - /// Layer name - /// input nodes - /// created Layer instance - public Layer Min(string name, object[] inputs) - { - return Broadcast(Layer.Type.Min, name, inputs); - } - - /// - /// Element-wise `max` of each of the input tensors with multidimensional broadcasting support. - /// - /// Layer name - /// input nodes - /// created Layer instance - public Layer Max(string name, object[] inputs) - { - return Broadcast(Layer.Type.Max, name, inputs); - } - - /// - /// Element-wise `mean` of each of the input tensors with multidimensional broadcasting support. - /// - /// Layer name - /// input nodes - /// created Layer instance - public Layer Mean(string name, object[] inputs) - { - return Broadcast(Layer.Type.Mean, name, inputs); - } - - /// - /// Performs a `greater` logical operation elementwise on the input tensors with multidimensional broadcasting support. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// - /// Layer name - /// left input node - /// right input node - /// created Layer instance - public Layer Greater(string name, object input0, object input1) - { - return Broadcast(Layer.Type.Greater, name, new [] {input0, input1}); - } - - /// - /// Performs a `greaterEqual` logical operation elementwise on the input tensors with multidimensional broadcasting support. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// - /// Layer name - /// left input node - /// right input node - /// created Layer instance - public Layer GreaterEqual(string name, object input0, object input1) - { - return Broadcast(Layer.Type.GreaterEqual, name, new [] {input0, input1}); - } - - /// - /// Performs a `less` logical operation elementwise on the input tensors with multidimensional broadcasting support. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// - /// Layer name - /// left input node - /// right input node - /// created Layer instance - public Layer Less(string name, object input0, object input1) - { - return Broadcast(Layer.Type.Less, name, new [] {input0, input1}); - } - - /// - /// Performs a `less equal` logical operation elementwise on the input tensors with multidimensional broadcasting support. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// - /// Layer name - /// left input node - /// right input node - /// created Layer instance - public Layer LessEqual(string name, object input0, object input1) - { - return Broadcast(Layer.Type.LessEqual, name, new [] {input0, input1}); - } - - /// - /// Performs a `equal` logical operation elementwise on the input tensors with multidimensional broadcasting support. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// - /// Layer name - /// left input node - /// right input node - /// created Layer instance - public Layer Equal(string name, object input0, object input1) - { - return Broadcast(Layer.Type.Equal, name, new [] {input0, input1}); - } - - /// - /// Performs a `and` logical operation elementwise on the input tensors with multidimensional broadcasting support. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// Input is consider false if 0.0 elementwise true otherwise. - /// - /// Layer name - /// left input node - /// right input node - /// created Layer instance - public Layer LogicalAnd(string name, object input0, object input1) - { - return Broadcast(Layer.Type.LogicalAnd, name, new [] {input0, input1}); - } - - /// - /// Performs a `or` logical operation elementwise on the input tensors with multidimensional broadcasting support. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// Input is consider false if 0.0 elementwise true otherwise. - /// - /// Layer name - /// left input node - /// right input node - /// created Layer instance - public Layer LogicalOr(string name, object input0, object input1) - { - return Broadcast(Layer.Type.LogicalOr, name, new [] {input0, input1}); - } - - /// - /// Performs a `xor` logical operation elementwise on the input tensors with multidimensional broadcasting support. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// Input is consider false if 0.0 elementwise true otherwise. - /// - /// Layer name - /// left input node - /// right input node - /// created Layer instance - public Layer LogicalXor(string name, object input0, object input1) - { - return Broadcast(Layer.Type.LogicalXor, name, new [] {input0, input1}); - } - - /// - /// Performs a `not` logical operation elementwise on the input tensor. - /// Return 1.0 elementwise if condition is true 0.0 otherwise. - /// Input is consider false if 0.0 elementwise true otherwise. - /// - /// Layer name - /// input node - /// created Layer instance - public Layer LogicalNot(string name, object input) - { - Layer layer = new Layer(name, Layer.Type.LogicalNot); - layer.inputs = new[] { ResolveInput(input) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Performs a `sign` operation elementwise on the input tensor. - /// Return 1.0 elementwise if x > 0 else -1.0 if x < 0 else 0.0 - /// - /// Layer name - /// input node - /// created Layer instance - public Layer Sign(string name, object input) - { - Layer layer = new Layer(name, Layer.Type.Sign); - layer.inputs = new[] { ResolveInput(input) }; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Return elements, either from X or Y, depending on condition (with broadcasting support, based on the shape of the condition) - /// Return X elementwise if condition is true Y otherwise. - /// Input is consider false if 0.0 elementwise true otherwise. - /// - /// Layer name - /// condition - /// first input - /// second input - /// created Layer instance - public Layer Where(string name, object condition, object input1, object input2) - { - Layer layer = new Layer(name, Layer.Type.Where); - layer.inputs = new[] { ResolveInput(condition), ResolveInput(input1), ResolveInput(input2) }; - - m_Model.layers.Add(layer); - - return layer; - } - - // Generic-ONNX style pad - internal Layer Pad(string name, object input, object pad, object value, Layer.PadMode mode, Layer.AutoPad autoPadMode) - { - Layer layer = new Layer(name, Layer.Type.Pad); - var valuestring = ResolveInput(value); - if (string.IsNullOrEmpty(valuestring)) - { - layer.inputs = new[] { ResolveInput(input), ResolveInput(pad) }; - layer.beta = 0.0f; - } - else - layer.inputs = new[] { ResolveInput(input), ResolveInput(pad), ResolveInput(value) }; - - layer.axis = (int)mode; - layer.pool = new[] { (int)autoPadMode }; - - m_Model.layers.Add(layer); - - return layer; - } - - internal Layer Pad(string name, object input, Int32[] pad, float constantValue, Layer.PadMode mode, Layer.AutoPad autoPadMode) - { - Layer layer = new Layer(name, Layer.Type.Pad); - layer.inputs = new[] { ResolveInput(input) }; - layer.beta = constantValue; - layer.pad = pad; - layer.axis = (int)mode; - layer.pool = new[] { (int)autoPadMode }; - - m_Model.layers.Add(layer); - - return layer; - } - - // known Layer.Type - internal Layer Pad(Layer.Type type, string name, object input, Int32[] pad, float constantValue = 0.0f) - { - Layer layer = new Layer(name, type); - layer.inputs = new[] { ResolveInput(input) }; - layer.beta = constantValue; - layer.pad = pad; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Pads H and W dimension with a given constant value (default to 0). - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// If pad contain negative values H and W dimensions will be cropped instead. - /// - /// For example a tensor of shape(1,2,3,1) - /// [1, 2, 3], - /// [4, 5, 6] - /// - /// With pad [2, 1, 2, 1] - /// - /// Result in a tensor of shape(1,4,7,1) - /// [0, 0, 0, 0, 0, 0, 0], - /// [0, 0, 1, 2, 3, 0, 0], - /// [0, 0, 4, 5, 6, 0, 0], - /// [0, 0, 0, 0, 0, 0, 0] - /// - /// Layer name - /// input node - /// padding - /// border constant value - /// created Layer instance - public Layer Border2D(string name, object input, Int32[] pad, float constantValue = 0.0f) - { - return Pad(Layer.Type.Border2D, name, input, pad, constantValue); - } - - /// - /// Pads D,H and W dimension with a given constant value (default to 0). - /// Pad should be of size 6 and format is [pre W, pre H, pre D, post W, post H, post D]. - /// If pad contain negative values H and W dimensions will be cropped instead. - /// - /// Layer name - /// input node - /// padding - /// constant value to use for border - /// created Layer instance - public Layer Border3D(string name, object input, Int32[] pad, float constantValue = 0.0f) - { - return Pad(Layer.Type.Border3D, name, input, pad, constantValue); - } - - /// - /// Pads H and W dimension by repeating the edge values of the input. - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// - /// For example a tensor of shape(1,2,3,1): - /// [1, 2, 3], - /// [4, 5, 6] - /// - /// With pad [2, 1, 2, 1] - /// - /// Result in a tensor of shape(1,4,7,1) - /// [1, 1, 1, 2, 3, 3, 3], - /// [1, 1, 1, 2, 3, 3, 3], - /// [4, 4, 4, 5, 6, 6, 6], - /// [4, 4, 4, 5, 6, 6, 6] - /// - /// Layer name - /// input node - /// padding - /// created Layer instance - public Layer Pad2DEdge(string name, object input, Int32[] pad) - { - return Pad(Layer.Type.Pad2DEdge, name, input, pad); - } - - /// - /// Pads H and W dimension by mirroring on the first and last values along those axis. - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// - /// For example a tensor of shape(1,2,3,1): - /// [1, 2, 3], - /// [4, 5, 6] - /// - /// With pad [2, 1, 2, 1] - /// - /// Result in a tensor of shape(1,4,7,1) - /// [6, 5, 4, 5, 6, 5, 4], - /// [3, 2, 1, 2, 3, 2, 1], - /// [6, 5, 4, 5, 6, 5, 4], - /// [3, 2, 1, 2, 3, 2, 1] - /// - /// Layer name - /// input node - /// padding - /// created Layer instance - public Layer Pad2DReflect(string name, object input, Int32[] pad) - { - return Pad(Layer.Type.Pad2DReflect, name, input, pad); - } - - /// - /// Pads H and W dimension with symmetric replication along those axis. - /// Pad should be of size 4 and format is [pre W, pre H, post W, post H]. - /// - /// For example a tensor of shape(1,2,3,1): - /// [1, 2, 3], - /// [4, 5, 6] - /// - /// With pad [2, 1, 2, 1] - /// - /// Result in a tensor of shape(1,4,7,1) - /// [2, 1, 1, 2, 3, 3, 2], - /// [2, 1, 1, 2, 3, 3, 2], - /// [5, 4, 4, 5, 6, 6, 5], - /// [5, 4, 4, 5, 6, 6, 5] - /// - /// Layer name - /// input node - /// padding - /// created Layer instance - public Layer Pad2DSymmetric(string name, object input, Int32[] pad) - { - return Pad(Layer.Type.Pad2DSymmetric, name, input, pad); - } - - /// - /// Generates a Tensor with random values drawn from a normal distribution. - /// The shape of the tensor is specified by input tensor - /// The normal distribution is specified by mean and scale - /// - /// Layer name - /// input node - /// mean - /// scale - /// seed - /// created Layer instance - public Layer RandomNormal(string name, object input, float mean, float scale, float seed) - { - Assert.IsFalse(input is TensorShape); // TensorShape must be handled by separate RandomNormal(name, shape...) implementation - - Layer layer = new Layer(name, Layer.Type.RandomNormal); - layer.inputs = new[] { ResolveInput(input) }; - layer.alpha = scale; - layer.beta = mean; - layer.pad = new int[1] {(int)seed}; - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Generates a Tensor with random values drawn from a normal distribution. - /// The shape of the tensor is specified by scale - /// The normal distribution is specified by mean and scale - /// - /// Layer name - /// shape - /// mean - /// scale - /// seed - /// created Layer instance - public Layer RandomNormal(string name, TensorShape shape, float mean, float scale, float seed) - { - Layer layer = new Layer(name, Layer.Type.RandomNormal); - layer.alpha = scale; - layer.beta = mean; - layer.pad = new int[1] {(int)seed}; - layer.pool = shape.ToArray(); - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Generates a Tensor with random values drawn from a uniform distribution. - /// The shape of the tensor is specified by input tensor - /// The uniform distribution scale is specified by min and max range - /// - /// Layer name - /// input node - /// min - /// max - /// seed - /// created Layer instance - public Layer RandomUniform(string name, object input, float min, float max, float seed) - { - Assert.IsFalse(input is TensorShape); // TensorShape must be handled by separate RandomUniform(name, shape...) implementation - - Layer layer = new Layer(name, Layer.Type.RandomUniform); - layer.inputs = new[] { ResolveInput(input) }; - layer.alpha = (max-min); - layer.beta = min; - layer.pad = new int[1] {(int)seed}; - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Generates a Tensor with random values drawn from a uniform distribution. - /// The shape of the tensor is specified by shape - /// The uniform distribution scale is specified by min and max range - /// - /// Layer name - /// shape - /// min - /// max - /// seed - /// created Layer instance - public Layer RandomUniform(string name, TensorShape shape, float min, float max, float seed) - { - Layer layer = new Layer(name, Layer.Type.RandomUniform); - layer.alpha = (max-min); - layer.beta = min; - layer.pad = new int[1] {(int)seed}; - layer.pool = shape.ToArray(); - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Generate a Tensor with random samples drawn from a multinomial distribution according to the probabilities of each of the possible outcomes. - /// Output batch is same as input. - /// Output channel is `numberOfSamplesDrawnPerInputChannel`. - /// - /// Layer name - /// input node - /// number of samples drawn per input channel - /// seed - /// created Layer instance - public Layer Multinomial(string name, object input, int numberOfSamplesDrawnPerInputChannel, float seed) - { - Layer layer = new Layer(name, Layer.Type.Multinomial); - layer.inputs = new[] { ResolveInput(input) }; - layer.pad = new int[1] {(int)seed}; - layer.pool = new int[1] {numberOfSamplesDrawnPerInputChannel}; - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Computes a reduce operation (max/min/mean/prod/sum) of the input tensor's element along the provided axis - /// If axisIs8D==true axis rank is from [S,R,N,T,D,H,W,C] overwise from [N,H,W,C] - /// `axis` must be superior to -4 - /// `axis` must be inferior to 8 when axisIs8D==true or inferior to 4 if axisIs8D==false - /// - /// operation type - /// Layer name - /// input node - /// axis - /// is axis 8D - /// is shape rank reduced - /// created Layer instance - public Layer Reduce(Layer.Type type, string name, object input, int axis = -1, bool axisIs8D=false, int keepDims = 1) - { - Layer layer = new Layer(name, type); - layer.inputs = new[] { ResolveInput(input) }; - layer.axis = axisIs8D?axis:TensorExtensions.Convert4DTo8DAxis(axis); - layer.alpha = keepDims; - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Generate a tensor containing a sequence of numbers that begin at `start` and extends by increments of `delta` up to `limit` (exclusive). - /// the number of elements are defined as follows: - /// number_of_elements = max( ceil( (limit - start) / delta ) , 0 ) - /// output is calculated as follows: - /// output[i] = start + (i * delta) - /// - /// Layer name - /// start - /// limit - /// delta - /// created Layer instance - public Layer Range(string name, object start, object limit, object delta) - { - Layer layer = new Layer(name, Layer.Type.Range); - layer.inputs = new[] { ResolveInput(start), ResolveInput(limit), ResolveInput(delta) }; - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Gathers input along provided axis. Swizzling pattern is given by input indices: - /// If axisIs8D==false - /// axis == 0: gatheredData[b, y, x, c] = data[indices[b], y, x, c] - /// axis == 1: gatheredData[b, y, x, c] = data[b, indices[y], x, c] - /// ... - /// Else - /// axis == 0: gatheredData[s, r, n, t, d, y, x, c] = data[indices[s], r, n, t, d, y, x, c] - /// axis == 1: gatheredData[s, r, n, t, d, y, x, c] = data[indices[s], indices[y], n, t, d, y, x, c] - /// ... - /// While in both case - /// axis == -1: gatheredData[..., x, c] = data[...x, indices[c]] - /// `axis` must be superior to -4 - /// `axis` must be inferior to 8 when axisIs8D==true or inferior to 4 if axisIs8D==false - /// - /// Layer name - /// input node - /// indices - /// axis - /// is axis 8D - /// created Layer instance - public Layer Gather(string name, object input, object indices, int axis = -1, bool axisIs8D=false) - { - object[] inputs = new[] { input, indices }; - - Layer layer = new Layer(name, Layer.Type.Gather); - layer.inputs = inputs.Select(i => ResolveInput(i)).ToArray(); - layer.axis = axisIs8D?axis:TensorExtensions.Convert4DTo8DAxis(axis); - m_Model.layers.Add(layer); - - return layer; - } - - public Layer ScatterND(string name, object input, object indices, object updates, Layer.ScatterNDReductionMode reductionType) - { - Layer layer = new Layer(name, Layer.Type.ScatterND); - layer.inputs = new[] { ResolveInput(input), ResolveInput(indices), ResolveInput(updates) }; - layer.axis = (int)reductionType; - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// Filter out boxes that have high intersection-over-union (IOU) overlap with previously selected boxes. - /// Bounding boxes with score less than scoreThreshold are removed. - /// - /// Layer name - /// boxes input node - /// scores input node - /// max output boxes per class input node - /// IOU threshold input node - /// score input node - /// center point box - /// created Layer instance - public Layer NonMaxSuppression(string name, object boxes, object scores, object maxOutputBoxesPerClass, - object iouThreshold, object scoreThreshold, int centerPointBox) - { - var layer = new Layer(name, Layer.Type.NonMaxSuppression); - - if (maxOutputBoxesPerClass is float bpc && iouThreshold is float iou && scoreThreshold is float score) - { - layer.inputs = new[] { ResolveInput(boxes), ResolveInput(scores) }; - layer.pool = new[] { (int)bpc }; - layer.alpha = iou; - layer.beta = score; - } - else - { - layer.inputs = new [] - { - ResolveInput(boxes), ResolveInput(scores), ResolveInput(maxOutputBoxesPerClass), - ResolveInput(iouThreshold), ResolveInput(scoreThreshold) - }; - } - layer.axis = centerPointBox; - - m_Model.layers.Add(layer); - - return layer; - } - - /// - /// LSTM - /// - /// Layer name - /// input node - /// output nodes - /// W data - /// R data - /// B data (optional) - /// Number of neurons in the hidden layer - /// Initial value of the hidden layer (optional) - /// Initial value of the hidden layer (optional) - /// created Layer instances - public Layer[] LSTM(string name, object input, string[] outputs, object w, object r, object b, int hiddenSize, - object initialHidden = null, object initialCell = null) - { - Layer layer = new Layer(name, Layer.Type.LSTM); - - // LSTM's first output may not be used (Y), but we need to preserve the layer regardless, so any additional outputs get computed - layer.flags |= Layer.Flags.Preserve; - - string layerHidden = $"{name}_wm_h"; - string layerCell = $"{name}_wm_c"; - - if (initialHidden == null) - { - // Add memory inputs (if not specified) since they are used as inputs to this layer (will be initialized to 0) - initialHidden = layerHidden; - } - else - { - // We don't support directions (i.e. only forward direction) and have built the implementation around - // removing direction axes from W,R,B to allow for 2D matrix multiplications. - // [num_directions, batch_size, hidden_size] NCH -> [batch_size, hidden_size] CH - initialHidden = Transpose($"{layerHidden}_for_{name}", initialHidden, new[] { 1, 2, 0 }); - } - - if (initialCell == null) - { - // Add memory inputs (if not specified) since they are used as inputs to this layer (will be initialized to 0) - initialCell = layerCell; - } - else - { - // We don't support directions (i.e. only forward direction) and have built the implementation around - // removing direction axes from W,R,B to allow for 2D matrix multiplications. - // [num_directions, batch_size, hidden_size] NCH -> [batch_size, hidden_size] CH - initialCell = Transpose($"{layerCell}_for_{name}", initialCell, new[] { 1, 2, 0 }); - } - - m_Model.layers.Add(layer); - - Layer stateHidden = Transpose(outputs[1] ?? $"{name}_Y_h", layerHidden, new[] { 2, 0, 1 }); // Y_h - Layer stateCell = Transpose(outputs[2] ?? $"{name}_Y_c", layerCell, new[] { 2, 0, 1 }); // Y_c - - // LSTM-node working memory (if no input was specified) and additional outputs - Memory(layerHidden, stateHidden, new TensorShape(-1, 1, 1, hiddenSize)); - Memory(layerCell, stateCell, new TensorShape(-1, 1, 1, hiddenSize)); - - var inputs = new List(); - inputs.Add(ResolveInput(input)); - - if (w is Tensor W && r is Tensor R && b is Tensor B) - { - OpsUtils.BakeConstantWRBIntoLSTMLayer(layer, W, R, B); - } - else - { - // Dynamic input - inputs.Add(ResolveInput(w)); - inputs.Add(ResolveInput(r)); - inputs.Add(ResolveInput(b)); - } - - inputs.Add(ResolveInput(initialHidden)); - inputs.Add(ResolveInput(initialCell)); - - layer.inputs = inputs.ToArray(); - layer.pool = new[] { hiddenSize }; - - return new [] { layer, stateHidden, stateCell }; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/ModelBuilder.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/ModelBuilder.cs.meta deleted file mode 100644 index 2c619a8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/ModelBuilder.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 19ceced96eb441539830855be9d99f12 -timeCreated: 1566476409 \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/Core/ModelLoader.cs b/Packages/com.unity.barracuda/Runtime/Core/ModelLoader.cs deleted file mode 100644 index fe8f8dd..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/ModelLoader.cs +++ /dev/null @@ -1,606 +0,0 @@ -// #define DEBUG_TIMING -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; - -[assembly: InternalsVisibleTo("Unity.Barracuda.Tests")] - -namespace Unity.Barracuda { - -/// -/// Barracuda `Model` loader -/// -public static class ModelLoader -{ - /// - /// Return an object oriented representation (aka: `Model`) of a neural network from a binary representation of type `NNModel`. - /// By default details are not logged to the console, set `verbose` to true to see loading details. - /// - /// model - /// verbose - /// skip loading weights (fast loading, metadata only) - /// loaded Model - public static Model Load(NNModel model, bool verbose = false, bool skipWeights = false) - { - return Load(model.modelData.Value, verbose, skipWeights); - } - - /// - /// Return an object oriented representation (aka: `Model`) of a neural network from a binary representation of type `NNModel`. - /// By default details are not logged to the console, set `verbose` to true to see loading details. - /// - /// binary representation of model - /// object-oriented representation of model (must initialize before calling method) - /// verbose - /// skip loading weights (fast loading, metadata only) - /// the maximum amount of time to spend between in computation before yielding - /// IEnumerator (use with StartCoroutine) - public static IEnumerator LoadAsync(NNModel nnModel, Model model, bool verbose = false, bool skipWeights = false, float maxTimePerYield = 0.01f) - { - Assert.IsNotNull(model); - var enumerator = LoadAsync(Open(nnModel.modelData.Value), model, verbose, true, skipWeights, maxTimePerYield); - - while (enumerator.MoveNext()) - { - model = (Model)enumerator.Current; - if (model != null) - yield return null; - } - } - - /// - /// Return an object oriented representation (aka: `Model`) of a neural network from a `.bc` file from the the streaming asset folder. - /// By default details are not logged to the console, set `verbose` to true to see loading details. - /// - /// file name - /// verbose - /// skip loading weights (fast loading, metadata only) - /// loaded Model - public static Model LoadFromStreamingAssets(string filename, bool verbose = false, bool skipWeights = false) - { - return Load(Path.Combine(Application.streamingAssetsPath, filename), verbose, skipWeights); - } - - /// - /// Return an object oriented representation (aka: `Model`) of a neural network from a `.bc` file from the the streaming asset folder. - /// By default details are not logged to the console, set `verbose` to true to see loading details. - /// - /// file name - /// object-oriented representation of model (must initialize before calling method) - /// verbose - /// skip loading weights (fast loading, metadata only) - /// the maximum amount of time to spend between in computation before yielding - /// IEnumerator (use with StartCoroutine) - public static IEnumerator LoadAsyncFromStreamingAssets(string filename, Model model, bool verbose = false, bool skipWeights = false, float maxTimePerYield = 0.01f) - { - Assert.IsNotNull(model); - var enumerator = LoadAsync(Open(Path.Combine(Application.streamingAssetsPath, filename)), model, verbose, true, skipWeights, maxTimePerYield); - - do - { - model = (Model)enumerator.Current; - if (model != null) - yield return null; - } while (enumerator.MoveNext()); - } - - /// - /// Return an object oriented representation (aka: `Model`) of a neural network from a `.bc` file. - /// By default details are not logged to the console, set `verbose` to true to see loading details. - /// - /// file name - /// verbose - /// skip loading weights (fast loading, metadata only) - /// loaded Model - public static Model Load(string filepath, bool verbose = false, bool skipWeights = false) - { - return Load(Open(filepath), verbose, true, skipWeights); - } - - /// - /// Return an object oriented representation (aka: `Model`) of a neural network from a `.bc` file. - /// By default details are not logged to the console, set `verbose` to true to see loading details. - /// - /// file name - /// object-oriented representation of model (must initialize before calling method) - /// verbose - /// skip loading weights (fast loading, metadata only) - /// the maximum amount of time to spend between in computation before yielding - /// IEnumerator (use with StartCoroutine) - public static IEnumerator LoadAsync(string filepath, Model model, bool verbose = false, bool skipWeights = false, float maxTimePerYield = 0.01f) - { - Assert.IsNotNull(model); - var enumerator = LoadAsync(Open(filepath), model, verbose, true, skipWeights, maxTimePerYield); - - while (enumerator.MoveNext()) - { - model = (Model)enumerator.Current; - if (model != null) - yield return null; - } - } - - - /// - /// Return an object oriented representation (aka: `Model`) of a neural network from a byte[] array. - /// By default details are not logged to the console, set `verbose` to true to see loading details. - /// - /// binary representation of model as a byte array - /// verbose - /// skip loading weights (fast loading, metadata only) - /// loaded Model - public static Model Load(byte[] stream, bool verbose = false, bool skipWeights = false) - { - return Load(Open(stream), verbose, true, skipWeights); - } - - /// - /// Return an object oriented representation (aka: `Model`) of a neural network from a byte[] array. - /// By default details are not logged to the console, set `verbose` to true to see loading details. - /// - /// binary representation of model as a byte array - /// object-oriented representation of model (must initialize before calling method) - /// verbose - /// skip loading weights (fast loading, metadata only) - /// the maximum amount of time to spend between in computation before yielding - /// IEnumerator (use with StartCoroutine) - public static IEnumerator LoadAsync(byte[] stream, Model model, bool verbose = false, bool skipWeights = false, float maxTimePerYield = 0.01f) - { - Assert.IsNotNull(model); - var enumerator = LoadAsync(Open(stream), model, verbose, true, skipWeights, maxTimePerYield); - - while (enumerator.MoveNext()) - { - model = (Model)enumerator.Current; - if (model != null) - yield return null; - } - } - - #region Private and internal - - internal static Model Load(byte[] stream, bool verbose = true, bool applyPatching = true, bool skipWeights = false) - { - return Load(Open(stream), verbose, applyPatching, skipWeights); - } - - private static int ConvertLayerAxisFor8DShapeSupportIfNeeded(int axis, long version, Layer.Type layerType) - { - if (version > Model.LastVersionWithout8DSupport) - return axis; - - //Prior to version 17, 8D tensors were not supported thus axis was expressed in NCHW format for Gather, Concat and Reduce layers. - if (layerType == Layer.Type.ReduceL2 || - layerType == Layer.Type.ReduceLogSum || - layerType == Layer.Type.ReduceLogSumExp || - layerType == Layer.Type.ReduceMax || - layerType == Layer.Type.ReduceMean || - layerType == Layer.Type.ReduceMin || - layerType == Layer.Type.ReduceProd || - layerType == Layer.Type.ReduceSum || - layerType == Layer.Type.ReduceSumSquare || - layerType == Layer.Type.Gather || - layerType == Layer.Type.Concat) - axis = TensorExtensions.Convert4DTo8DAxis(axis); - - return axis; - } - - static Model Load(BinaryReader fileReader, bool verbose = true, bool applyPatching = true, bool skipWeights = false) - { - Model model = null; - var enumerator = LoadAsync(fileReader, null, verbose, applyPatching, skipWeights); - - while (enumerator.MoveNext()) - { - model = (Model)enumerator.Current; - if (model != null) - break; - } - - return model; - } - - static IEnumerator LoadAsync(BinaryReader fileReader, Model model, bool verbose = true, bool applyPatching = true, bool skipWeights = false, float maxTimePerYield = 0f) - { - using (BinaryReader file = fileReader) - { - Profiler.BeginSample("Barracuda.LoadLayers"); - float timeStart = Time.realtimeSinceStartup; - - if (model == null) - model = new Model(); - List layers = new List(); - - long version = file.ReadInt64() % 0xff; // magic - if (version != Model.Version && version != Model.LastVersionWithout8DSupport && version != Model.LastVersionWithoutWeightsAlignmentSupport) - throw new NotSupportedException($"Format version not supported: {version}"); - - var count = file.ReadInt32(); - model.inputs = new List(count); - for (var i = 0; i < count; ++i) - { - model.inputs.Add(new Model.Input {name = ReadString(file), shape = ReadInt32Array(file)}); - - if (maxTimePerYield > 0 && Time.realtimeSinceStartup - timeStart > maxTimePerYield) - { -#if DEBUG_TIMING - UnityEngine.Debug.Log(Time.realtimeSinceStartup - timeStart); -#endif - yield return null; - timeStart = Time.realtimeSinceStartup; - } - } - - model.outputs = ReadStringArray(file).ToList(); - - count = file.ReadInt32(); - model.memories = new List(count); - for (var m = 0; m < count; ++m) - { - model.memories.Add(new Model.Memory - { - shape = new TensorShape(ReadInt32Array(file)), - input = ReadString(file), - output = ReadString(file) - }); - - if (maxTimePerYield > 0 && Time.realtimeSinceStartup - timeStart > maxTimePerYield) - { -#if DEBUG_TIMING - UnityEngine.Debug.Log(Time.realtimeSinceStartup - timeStart); -#endif - yield return null; - timeStart = Time.realtimeSinceStartup; - } - } - - int numberOfLayers = file.ReadInt32(); - for (var l = 0; l < numberOfLayers; ++l) - { - var name = ReadString(file); - var layerType = (Layer.Type)file.ReadInt32(); - var activation = (Layer.Activation)file.ReadInt32(); - Layer layer = new Layer(name, layerType, activation); - ReadInt32Array(file); // dummy - ReadInt32Array(file); // dummy - layer.pad = ReadInt32Array(file); - layer.stride = ReadInt32Array(file); - layer.pool = ReadInt32Array(file); - layer.axis = ConvertLayerAxisFor8DShapeSupportIfNeeded(file.ReadInt32(), version, layerType); - layer.alpha = file.ReadSingle(); - layer.beta = file.ReadSingle(); - ReadInt32Array(file); // dummy - - layer.inputs = ReadStringArray(file); - - if (maxTimePerYield > 0 && Time.realtimeSinceStartup - timeStart > maxTimePerYield) - { -#if DEBUG_TIMING - UnityEngine.Debug.Log(Time.realtimeSinceStartup - timeStart); -#endif - yield return null; - timeStart = Time.realtimeSinceStartup; - } - - layer.datasets = new Layer.DataSet[file.ReadInt32()]; - for (var i = 0; i < layer.datasets.Length; ++i) - { - if (maxTimePerYield > 0 && Time.realtimeSinceStartup - timeStart > maxTimePerYield) - { -#if DEBUG_TIMING - UnityEngine.Debug.Log(Time.realtimeSinceStartup - timeStart); -#endif - yield return null; - timeStart = Time.realtimeSinceStartup; - } - - layer.datasets[i].name = ReadString(file); - layer.datasets[i].shape = new TensorShape(ReadInt32Array(file)); - layer.datasets[i].offset = file.ReadInt64(); - layer.datasets[i].itemSizeInBytes = file.ReadInt32(); - layer.datasets[i].length = file.ReadInt32(); - } - - layers.Add(layer); - - if (verbose) - D.Log( - $"layer {l}, {layer.name} type: {layer.type} " + - $"{((layer.activation != Layer.Activation.None) ? $"activation {layer.activation} " : "")}" + - $"tensors: {layer.datasets.Length} inputs: {String.Join(",", layer.inputs)}"); - - if (verbose) - foreach (var t in layer.datasets) - D.Log($" Tensor: {t.shape} offset: {t.offset} len: {t.length}"); - - if (applyPatching) - PatchLayer(layers, layer); - - if (maxTimePerYield > 0 && Time.realtimeSinceStartup - timeStart > maxTimePerYield) - { -#if DEBUG_TIMING - UnityEngine.Debug.Log(Time.realtimeSinceStartup - timeStart + ": " + l); -#endif - yield return null; - timeStart = Time.realtimeSinceStartup; - } - } - model.layers = layers; - - Int64 numWeightsToRead = 0; - for (var l = 0; l < model.layers.Count; ++l) - { - for (var d = 0; d < model.layers[l].datasets.Length; ++d) - { - numWeightsToRead += model.layers[l].datasets[d].length; - - if (maxTimePerYield > 0 && Time.realtimeSinceStartup - timeStart > maxTimePerYield) - { -#if DEBUG_TIMING - UnityEngine.Debug.Log(Time.realtimeSinceStartup - timeStart); -#endif - yield return null; - timeStart = Time.realtimeSinceStartup; - } - } - } - - Profiler.EndSample(); - - DataType weightsDataType = DataType.Float; - if (version >= 20) - { - //Version 20 introduce weights type but full model need to be in the same type. Per layer no supported yet. - weightsDataType = (DataType)file.ReadInt32(); - } - - if (version >= 19) - { - //Padding so weights are aligned on Model.WeightsAlignment bytes - long streamCurrentPosition = file.BaseStream.Position; - long paddingForAlignment = Model.WeightsAlignment - (streamCurrentPosition % Model.WeightsAlignment); - file.BaseStream.Seek(paddingForAlignment, SeekOrigin.Current); - } - - if (skipWeights) - SkipLargeByteArray(file, numWeightsToRead * BarracudaArray.DataItemSize(weightsDataType)); - else - { - if (maxTimePerYield > 0 && Time.realtimeSinceStartup - timeStart > maxTimePerYield) - { -#if DEBUG_TIMING - UnityEngine.Debug.Log(Time.realtimeSinceStartup - timeStart); -#endif - yield return null; - timeStart = Time.realtimeSinceStartup; - } - - var sharedWeightsArray = ReadLargeWeightArray(file, numWeightsToRead, weightsDataType); - - Assert.AreEqual(weightsDataType, sharedWeightsArray.Type); - for (var l = 0; l < model.layers.Count; ++l) - { - model.layers[l].weights = sharedWeightsArray; - - if (maxTimePerYield > 0 && Time.realtimeSinceStartup - timeStart > maxTimePerYield) - { -#if DEBUG_TIMING - UnityEngine.Debug.Log(Time.realtimeSinceStartup - timeStart); -#endif - yield return null; - timeStart = Time.realtimeSinceStartup; - } - } - } - - // Importer Reporting - try - { - model.IrSource = ReadString(file); - model.IrVersion = ReadString(file); - model.ProducerName = ReadString(file); - int numWarnings = file.ReadInt32(); - for (var i = 0; i < numWarnings; ++i) - { - model.Warnings.Add(new Model.ImporterWarning(ReadString(file), ReadString(file))); - } - - if (version >= 18) - { - int numMetadataProps = file.ReadInt32(); - for (var i = 0; i < numMetadataProps; ++i) - { - model.Metadata.Add(ReadString(file), ReadString(file)); - } - } - } - catch (EndOfStreamException) - { - //Do nothing Importer Reporting data might not be present for backward compatibility reasons - } - - yield return model; - } - } - - private static void PatchLayer(List layers, Layer layer) - { - // Split Load so that each constant tensor gets its own layer - // for the sake of simplicity of the execution code - if (layer.type == Layer.Type.Load && - layer.datasets.Length > 1) - { - foreach (var t in layer.datasets) - { - Layer layerC = new Layer(t.name, Layer.Type.Load); // load using tensor name - layerC.inputs = layer.inputs; - layerC.datasets = new[] { t }; - - layers.Add(layerC); - } - - // patch original layer - layer.name = layer.name + "_nop"; - layer.type = Layer.Type.Nop; - layer.datasets = new Layer.DataSet[] {}; - } - - // Split activation part into separate layer when activation fusing is not supported. - // NOTE: Keras specific. Only Keras exporter packs both Dense/Conv and Activation into the same layer. - // @TODO: move layer split directly into Keras exporter - if (layer.type != Layer.Type.Activation && - layer.activation != Layer.Activation.None && - (!ModelOptimizer.IsLayerSupportingActivationFusing(layer.type) || !ModelOptimizer.IsActivationFusable(layer.activation))) - { - var affineOutput = layer.name + "_tmp"; - - Layer layerA = new Layer(layer.name, layer.activation);// take the original layer name - layerA.inputs = new[] { affineOutput }; - - // patch original layer - layer.name = affineOutput; - layer.activation = Layer.Activation.None; - Assert.AreEqual(layers[layers.Count-1].name, layer.name); - Assert.AreEqual(layers[layers.Count-1].activation, layer.activation); - - layers.Add(layerA); - } - - // @TODO: Enable Dropout - // @TEMP: disabled runtime Dropout noise to get more predictable results for auto testing - if (layer.type == Layer.Type.Dropout) - { - layer.type = Layer.Type.Activation; - layer.activation = Layer.Activation.None; - } - } - - private static void SkipLargeByteArray(BinaryReader file, Int64 count) - { - file.BaseStream.Seek(count, SeekOrigin.Current); - } - - private static BarracudaArray ReadLargeWeightArray(BinaryReader file, Int64 count, DataType dataType) - { - int bytesToRead; - Int64 bytesToReadInt64 = count * BarracudaArray.DataItemSize(dataType); - try - { - bytesToRead = Convert.ToInt32(bytesToReadInt64); // throws OverflowException - } - catch (OverflowException) - { - throw new OverflowException($"Files larger than 2GB currently are not supported. Attempt to read {bytesToReadInt64} bytes."); - } - - //1-Try to remap byte[] stream to avoid allocation - Profiler.BeginSample("Barracuda.RemapWeights"); - BarracudaArray remappedWeights = null; - try - { - Stream stream = file.BaseStream; - var memoryStream = stream as MemoryStream; - var sourceBuffer = memoryStream?.GetBuffer(); - int currentPosition = (int)memoryStream?.Position; - remappedWeights = new BarracudaArrayFromManagedArray(sourceBuffer, currentPosition, dataType, (int) count); - } - #if UNITY_EDITOR - catch (InvalidOperationException e) - { - UnityEngine.Debug.Log("ModelLoader: Can't remap memory stream to underlying data type, allocation and copy will occurs. Exception: " + e); - } - #else - catch (InvalidOperationException) {} - #endif - if (remappedWeights != null) - { - //We remapped memory. Need to advance stream position to be consistent with read behavior. - file.BaseStream.Position += bytesToRead; - Profiler.EndSample(); - return remappedWeights; - } - Profiler.EndSample(); - - //2-Can't remap will copy from managed memory to native - Profiler.BeginSample("Barracuda.AllocWeights"); - BarracudaArray loadedWeights = new BarracudaArray((int)count, dataType); - Profiler.EndSample(); - - Profiler.BeginSample("Barracuda.LoadWeights"); - try - { - var readBuffer = new byte[4096]; // 4Kb is close to optimal read size. - // See for measurements: https://www.jacksondunstan.com/articles/3568 - // Read size vs relative read-time: - // 64b: x10, 128b: x6, 256b: x4, 1Kb: x3, 4Kb: x3 - int writeOffset = 0; - while (writeOffset < bytesToRead) - { - var bytesLeftToRead = bytesToRead - writeOffset; - var readSizeInBytes = Math.Min(readBuffer.Length, bytesLeftToRead); - - Assert.IsTrue(readSizeInBytes > 0); - Assert.IsTrue(readSizeInBytes <= readBuffer.Length); - readSizeInBytes = file.BaseStream.Read(readBuffer, offset:0, count:readSizeInBytes); - if (readSizeInBytes == 0) - throw new IOException($"Unexpected EOF reached. Read {writeOffset / sizeof(float)} out of expected {count} floats before reaching end of file."); - - BarracudaArray.BlockCopy( - sourceArray:readBuffer, sourceByteOffset:0, - destinationArray:loadedWeights, destinationByteOffset:writeOffset, - lengthInBytes:readSizeInBytes); - writeOffset += readSizeInBytes; - } - Assert.AreEqual(writeOffset, bytesToRead); - } - finally - { - Profiler.EndSample(); - } - - return loadedWeights; - } - - private static Int32[] ReadInt32Array(BinaryReader file) - { - var arr = new Int32[file.ReadInt32()]; - byte[] bytes = file.ReadBytes(Convert.ToInt32(arr.Length * sizeof(Int32))); - Buffer.BlockCopy(bytes, 0, arr, 0, bytes.Length); - return arr; - } - - private static string ReadString(BinaryReader file) - { - var chars = file.ReadChars(file.ReadInt32()); - return new string(chars); - } - - private static string[] ReadStringArray(BinaryReader file) - { - var arr = new string[file.ReadInt32()]; - for (var i = 0; i < arr.Length; ++i) - arr[i] = ReadString(file); - return arr; - } - - private static BinaryReader Open(string filename) - { - return new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)); - } - - private static BinaryReader Open(byte[] bytes) - { - return new BinaryReader(new MemoryStream(bytes, 0, bytes.Length, false, true)); - } - #endregion -} - - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/ModelLoader.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/ModelLoader.cs.meta deleted file mode 100644 index 8fe55d1..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/ModelLoader.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: ab890607c8319490aaa5d1dee1fc4069 -timeCreated: 1495569481 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/ModelWriter.cs b/Packages/com.unity.barracuda/Runtime/Core/ModelWriter.cs deleted file mode 100644 index b2401fa..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/ModelWriter.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Threading; - -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; - -namespace Unity.Barracuda { - - /// - /// Serializes model to binary stream - /// - public class ModelWriter - { - /// - /// Save model to file - /// - /// file name - /// `Model` - /// verbose flag - public static void Save(string fileName, Model model, bool verbose = false) - { - BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create)); - Save(writer, model, verbose); - writer.Close(); - } - - /// - /// Save model to file - /// - /// `BinaryWriter` - /// `Model` - /// verbose flag - public static void Save(BinaryWriter writer, Model model, bool verbose = false) - { - Profiler.BeginSample("Barracuda.ModelWriter.Save"); - - writer.Write((long)Model.Version); - - writer.Write(model.inputs.Count); - for (var i = 0; i < model.inputs.Count; ++i) - { - WriteString(writer, model.inputs[i].name); - WriteInt32Array(writer, model.inputs[i].shape); - } - WriteStringArray(writer, model.outputs); - - writer.Write(model.memories.Count); - for (var m = 0; m < model.memories.Count; ++m) - { - WriteInt32Array(writer, model.memories[m].shape.ToArray()); - WriteString(writer, model.memories[m].input); - WriteString(writer, model.memories[m].output); - } - - // Write layers - long offsetFromModelStartToLayer = 0; - writer.Write(model.layers.Count); - for (var l = 0; l < model.layers.Count; ++l) - { - Layer layer = model.layers[l]; - WriteString(writer, layer.name); - writer.Write((Int32)layer.type); - writer.Write((Int32)layer.activation); - writer.Write(0); //dummy 0 size array - writer.Write(0); //dummy 0 size array - WriteInt32Array(writer, layer.pad); - WriteInt32Array(writer, layer.stride); - WriteInt32Array(writer, layer.pool); - writer.Write(layer.axis); - writer.Write(layer.alpha); - writer.Write(layer.beta); - writer.Write(0); //dummy 0 size array - - WriteStringArray(writer, layer.inputs); - - long offsetFromLayerStart = 0; - writer.Write(layer.datasets.Length); - for (var i = 0; i < layer.datasets.Length; ++i) - { - WriteString(writer, layer.datasets[i].name); - WriteInt32Array(writer, layer.datasets[i].shape.ToArray()); - // Recalculate all offsets to be global inside the model - // this way weights can be stored in one block at the end of the file - Assert.AreEqual(offsetFromLayerStart, layer.datasets[i].offset - layer.datasets[0].offset); - writer.Write(offsetFromModelStartToLayer + offsetFromLayerStart); - writer.Write(layer.datasets[i].itemSizeInBytes); - writer.Write(layer.datasets[i].length); - offsetFromLayerStart += layer.datasets[i].length; - } - offsetFromModelStartToLayer += offsetFromLayerStart; - - if (verbose) - D.Log("layer " + l + ", " + layer.name + " type: " + layer.type.ToString() + - ((layer.activation != Layer.Activation.None) ? " activation " + layer.activation : "") + - " tensors: " + layer.datasets.Length + - " inputs: " + String.Join(",", layer.inputs)); - - if (verbose) - foreach (var t in layer.datasets) - D.Log(" Tensor: " + t.shape + " offset: " + t.offset + " len: " + t.length); - } - - //Version 20 introduce weights type but full model need to be in the same type. Per layer no supported yet. - Assert.IsTrue(model.layers.Count >= 0); - var weightsDataType = model.layers[0].weights.Type; - var sizeOfDataItem = BarracudaArray.DataItemSize(weightsDataType); - writer.Write((int)weightsDataType); - - //Pad to 4 bytes - long writerCurrentPosition = writer.BaseStream.Position; - long paddingForAlignment = Model.WeightsAlignment - (writerCurrentPosition % Model.WeightsAlignment); - writer.Write(new byte[paddingForAlignment]); - - // Write tensor data - for (var l = 0; l < model.layers.Count; ++l) - { - for (var d = 0; d < model.layers[l].datasets.Length; ++d) - { - Assert.AreEqual(weightsDataType, model.layers[0].weights.Type); - byte[] dst = new byte[model.layers[l].datasets[d].length * sizeOfDataItem]; - BarracudaArray.BlockCopy(model.layers[l].weights, (int)(model.layers[l].datasets[d].offset * sizeOfDataItem), dst, 0, dst.Length); - writer.Write(dst); - } - } - - WriteString(writer, model.IrSource); - WriteString(writer, model.IrVersion); - WriteString(writer, model.ProducerName); - int numWarnings = model.Warnings.Count; - writer.Write(numWarnings); - for (var i = 0; i < numWarnings; ++i) - { - WriteString(writer, model.Warnings[i].LayerName); - WriteString(writer, model.Warnings[i].Message); - } - - int numMetadataProps = model.Metadata.Count; - writer.Write(numMetadataProps); - foreach (KeyValuePair kvp in model.Metadata) - { - WriteString(writer, kvp.Key); - WriteString(writer, kvp.Value); - } - - Profiler.EndSample(); - } - - - - static void WriteInt32Array(BinaryWriter writer, Int32[] arr) - { - writer.Write(arr.Length); - for (var i = 0; i < arr.Length; ++i) - writer.Write(arr[i]); - } - - static void WriteString(BinaryWriter writer, string str) - { - writer.Write(str.Length); - writer.Write(str.ToCharArray()); - } - - static void WriteStringArray(BinaryWriter writer, string[] strArray) - { - writer.Write(strArray.Length); - foreach(string str in strArray) - WriteString(writer, str); - } - - static void WriteStringArray(BinaryWriter writer, List strArray) - { - writer.Write(strArray.Count); - foreach(string str in strArray) - WriteString(writer, str); - } - } -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/ModelWriter.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/ModelWriter.cs.meta deleted file mode 100644 index 63067f0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/ModelWriter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 444f70d41cf065440a76d75c1a3d47e1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/PluginInterfaces.cs b/Packages/com.unity.barracuda/Runtime/Core/PluginInterfaces.cs deleted file mode 100644 index 2fbbc35..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/PluginInterfaces.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using Unity.Jobs; - -namespace Unity.Barracuda -{ - /// - /// BLAS plugin interface, allows to supply platform specific implementation of matrix multiplication - /// - public interface BLASPlugin - { - /// - /// Query if BLAS implementation is coming from platform's native library - /// - /// `true` if BLAS implementation is coming from platform's native library - bool IsNative(); - - /// - /// Query if current platform is supported by the BLAS plugin - /// - /// `true` if plugin supports current platform - bool IsCurrentPlatformSupported(); - - /// - /// Perform matrix multiplication C = A x B + C - /// - /// pointer to the matrix A - /// matrix A row count - /// matrix A column count - /// pointer to the matrix B - /// matrix B row count - /// matrix B column count - /// pointer to the matrix C - /// matrix C row count - /// matrix C column count - /// inner loop block size (if applicable) bs x bs - /// matrix A data is in transposed layout - /// matrix B data is in transposed layout - unsafe void SGEMM(float* Ap, int AM, int AN, - float* Bp, int BM, int BN, - float* Cp, int CM, int CN, int bs, - bool transposeA = false, bool transposeB = false); - - /// - /// Launches matrix multiplication C = A x B + C in async-manner - /// - /// input data dependency job handle - /// pointer to the matrix A - /// matrix A row count - /// matrix A column count - /// pointer to the matrix B - /// matrix B row count - /// matrix B column count - /// pointer to the matrix C - /// matrix C row count - /// matrix C column count - /// inner loop block size (if applicable) bs x bs - /// matrix A data is in transposed layout - /// matrix B data is in transposed layout - /// job handle - unsafe JobHandle ScheduleSGEMM(JobHandle dependsOn, - float* Ap, int AM, int AN, - float* Bp, int BM, int BN, - float* Cp, int CM, int CN, int bs, - bool transposeA = false, bool transposeB = false); - } - - internal class BLASPluginFactory - { - public static BLASPlugin CreateBLASPlugin() - { - BLASPlugin blas = null; - - // TODO make plugins discoverable via custom attributes - Stack plugins = new Stack(); - plugins.Push(typeof(CSharpBLAS).FullName); - plugins.Push("Unity.Barracuda.BurstBLAS"); - - if (Application.platform == RuntimePlatform.IPhonePlayer) - plugins.Push("Unity.Barracuda.iOSBLAS"); - else if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor) - plugins.Push("Unity.Barracuda.MacBLAS"); - - while (plugins.Count > 0) - { - var candidate = plugins.Pop(); - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - var t = assembly.GetType(candidate); - if (t != null) - { - try - { - var inst = Activator.CreateInstance(t) as BLASPlugin; - - if (inst != null && inst.IsCurrentPlatformSupported()) - { - blas = inst; - } - } - catch (Exception e) - { - D.LogWarning($"Failed to load {t} with exception {e}"); - break; - } - } - } - - // Found working candidate - if (blas != null) - break; - } - - return blas; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/PluginInterfaces.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/PluginInterfaces.cs.meta deleted file mode 100644 index 9295133..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/PluginInterfaces.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: cb590b30d6c1477e9316410e67c4c568 -timeCreated: 1538563588 \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources.meta deleted file mode 100644 index 085e3d8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: eabca0df46712e749a81dc088ab44b9a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda.meta deleted file mode 100644 index 482436e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d9b5510711813424987da60c447d6db3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Activation.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Activation.cginc deleted file mode 100644 index cdfc9e2..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Activation.cginc +++ /dev/null @@ -1,2047 +0,0 @@ -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL_RW(O) - -float _Alpha; -float _Beta; -uint _LoopStride; - -//DISPATCH ARGS(O.length, 1, 1); -#define FLAT_ACTIVATION(name, op_name) \ -void name##_Flat(uint3 dispatchThreadID : SV_DispatchThreadID)\ -{\ - TENSOR_ARGS2(X, O);\ -\ - uint i = dispatchThreadID.x;\ - if (i >= O.GetLength()) return;\ -\ - float v = X.FastGet(i);\ - v = op_name (v);\ - O.FastSet(i, v);\ -} - -//DISPATCH ARGS(O.length/2, 1, 1) -#define FLAT_ACTIVATION_STRICT(name, op_name) \ -void name##_FlatStrict(uint3 groupId : SV_GroupID, uint3 groupThreadId : SV_GroupThreadID)\ -{\ - TENSOR_ARGS2(X, O);\ -\ - uint numThreadsPerTG = NUMTHREAD(512, 128, 64);\ - uint i1 = (groupId.x * 2 + 0) * numThreadsPerTG + groupThreadId.x;\ - uint i2 = (groupId.x * 2 + 1) * numThreadsPerTG + groupThreadId.x;\ - float v1 = X.FastGet(i1);\ - float v2 = X.FastGet(i2);\ - v1 = op_name (v1);\ - v2 = op_name (v2);\ - O.FastSet(i1, v1);\ - O.FastSet(i2, v2);\ -} - -//DISPATCH ARGS(O.length, 1, 1); -#define LOOP_ACTIVATION(name, op_name) \ -void name##_Loop(uint3 dispatchThreadID : SV_DispatchThreadID)\ -{\ - TENSOR_ARGS2(X, O);\ -\ - uint i = dispatchThreadID.x;\ - uint len = O.GetLength();\ -\ - while (i < len) {\ - float v = X.FastGet(i); \ - v = op_name (v); \ - O.FastSet(i, v); \ - i += _LoopStride; \ - }\ -} - -#define ACTIVATION(name, op_name) \ -NUMTHREADS((512,1,1), (128,1,1), (64,1,1))\ -FLAT_ACTIVATION(name, op_name)\ -NUMTHREADS((512,1,1), (128,1,1), (64,1,1))\ -FLAT_ACTIVATION_STRICT(name, op_name)\ -NUMTHREADS((512,1,1), (128,1,1), (64,1,1))\ -LOOP_ACTIVATION(name, op_name) - -float relu(float v) -{ - return max(v, 0.0f); -} - -float relu6(float v) -{ - return min(max(v, 0.0f), 6.0f); -} - -float swish(float v) -{ - return v / (1.f + exp(-v)); -} - -float prelu(float v, float alpha) -{ - return max(v, 0.0f) + alpha * min(v, 0.0f); -} - -float selu(float v) -{ - return _Beta * (max(v, 0.0f) + min(_Alpha * (exp(v) - 1.0f), 0.0f)); -} - -float softplus(float v) -{ - return log(exp(v) + 1.f); -} - -float sigmoid(float v) -{ - return rcp(1.f + exp(-v)); -} - -float hardsigmoid(float v) -{ - return max(0.0f, min(1.0f, _Alpha * v + _Beta)); -} - -float elu(float v) -{ - return (v <= 0.f) ? _Alpha * (exp(v) - 1.f) : v; -} - -float lrelu(float v) -{ - return max(v, _Alpha * v); -} - -float signed_pow(float f) -{ - return pow(abs(f), _Alpha); -} - -float logical_not(float v) -{ - return (v == 0.0f) ? 1.0f : 0.0f; -} - -float neg(float v) -{ - return -v; -} - -float tanh_safe(float x) -{ - return tanh(clamp(x,-16.0f,16.0f));//clamp to avoid NaNs for large values. -} - -float activation_clip(float v) -{ - return clamp(v, _Alpha, _Beta); -} - -float acosh(float v) -{ - return log(v + sqrt(v*v - 1.0f)); -} - -float asinh(float v) -{ - return log(v + sqrt(v*v + 1.0f)); -} - -float atanh(float v) -{ - return 0.5f * log((1.0f + v) / (1.0f - v)); -} - -float erf(float v) -{ - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x = abs(v); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t = 1.0f / (1.0f + p * x); - float t2 = t * t; - float t3 = t2 * t; - float t4 = t3 * t; - float t5 = t4 * t; - - return sign(v)*(1 - (a1*t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5)*exp(-x * x)); -} - - -ACTIVATION(Abs, abs) -ACTIVATION(Neg, neg) -ACTIVATION(Ceil, ceil) -ACTIVATION(Floor, floor) -ACTIVATION(Round, round) -ACTIVATION(Reciprocal, rcp) -ACTIVATION(Relu, relu) -ACTIVATION(Relu6, relu6) -ACTIVATION(Tanh, tanh_safe) -ACTIVATION(Softplus, softplus) -ACTIVATION(Sigmoid, sigmoid) -ACTIVATION(HardSigmoid, hardsigmoid) -ACTIVATION(Swish, swish) -ACTIVATION(Elu, elu) -ACTIVATION(Selu, selu) -ACTIVATION(LeakyRelu, lrelu) -ACTIVATION(Exp, exp) -ACTIVATION(Log, log) -ACTIVATION(Sqrt, sqrt) -ACTIVATION(Pow, signed_pow) -ACTIVATION(LogicalNot, logical_not) -ACTIVATION(Sign, sign) -ACTIVATION(Clip, activation_clip) -ACTIVATION(Acos, acos) -ACTIVATION(Acosh, acosh) -ACTIVATION(Asin, asin) -ACTIVATION(Asinh, asinh) -ACTIVATION(Atan, atan) -ACTIVATION(Atanh, atanh) -ACTIVATION(Cos, cos) -ACTIVATION(Cosh, cosh) -ACTIVATION(Sin, sin) -ACTIVATION(Sinh, sinh) -ACTIVATION(Tan, tan) -ACTIVATION(Erf, erf) - -// ------------------- - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Relu)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = relu(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Relu6)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = relu6(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Selu)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = selu(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Tanh)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = tanh_safe(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Softplus)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = softplus(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) - void KERNEL_FUNC(Sigmoid)(uint3 dispatchThreadID : SV_DispatchThreadID) - { - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = sigmoid(v); - O.Set(n, y, x, c, v); - } - } - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(HardSigmoid)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = hardsigmoid(v); - O.Set(n, y, x, c, v); - } -} - - NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Swish)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = swish(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Elu)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = elu(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(LeakyRelu)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = lrelu(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Exp)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = exp(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Log)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = log(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Sqrt)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = sqrt(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Pow)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = signed_pow(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Clip)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = activation_clip(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Acos)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = acos(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Acosh)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = log(v + sqrt(v * v - 1.0f)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Asin)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = asin(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Asinh)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = log(v + sqrt(v*v + 1.0f)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Atan)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = atan(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Atanh)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = 0.5f * log((1.0f + v) / (1.0f - v)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Cos)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = cos(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Cosh)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = 0.5f * (exp(v) + exp(-v)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Sin)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = sin(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Sinh)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = 0.5f * (exp(v) - exp(-v)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Tan)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = tan(v); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Erf)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = erf(x); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Relu_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = relu(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Relu_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = relu(v); - O.Set(n, y, x, c, v); -} - - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Relu6_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = relu6(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Relu6_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = relu6(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Selu_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = selu(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Selu_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = selu(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Tanh_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = tanh_safe(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Tanh_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = tanh_safe(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Erf_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = erf(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Erf_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = erf(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Softplus_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = softplus(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Softplus_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = softplus(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Sigmoid_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = sigmoid(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Sigmoid_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = sigmoid(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(HardSigmoid_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = hardsigmoid(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(HardSigmoid_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = hardsigmoid(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Swish_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = swish(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Swish_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = swish(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Elu_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = elu(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Elu_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = elu(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(LeakyRelu_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = lrelu(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(LeakyRelu_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = lrelu(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Exp_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = exp(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Exp_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = exp(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Log_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = log(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Log_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = log(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Sqrt_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = sqrt(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Sqrt_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = sqrt(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Acos_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = acos(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Acos_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = acos(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Acosh_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = log(v + sqrt(v * v - 1.0f)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Acosh_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = log(v + sqrt(v * v - 1.0f)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Asin_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = asin(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Asin_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = asin(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Asinh_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = log(v + sqrt(v*v + 1.0f)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Asinh_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = log(v + sqrt(v*v + 1.0f)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Atan_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = atan(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Atan_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = atan(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Atanh_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = 0.5f * log((1.0f + v) / (1.0f - v)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Atanh_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = 0.5f * log((1.0f + v) / (1.0f - v)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Cos_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = cos(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Cos_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = cos(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Cosh_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = 0.5f * (exp(v) + exp(-v)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Cosh_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = 0.5f * (exp(v) + exp(-v)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Sin_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = sin(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Sin_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = sin(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Sinh_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = 0.5f * (exp(v) - exp(-v)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Sinh_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = 0.5f * (exp(v) - exp(-v)); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Tan_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = tan(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Tan_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = tan(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(Pow_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = signed_pow(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(Pow_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = signed_pow(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((16, 16, 1), (16, 8, 1), (16, 4, 1)) -void KERNEL_FUNC(Clip_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = activation_clip(v); - O.Set(n, y, x, c, v); -} - -NUMTHREADS((512, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(Clip_Nyxc)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.batch * O.height * O.width * O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint nyxc = dispatchThreadID.x; - - uint c = nyxc % X.channels; - uint nyx = nyxc / X.channels; - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (n >= X.batch) return; - - float v = X.Get(n, y, x, c); - v = activation_clip(v); - O.Set(n, y, x, c, v); -} - -TENSOR_DECL(W) -TENSOR_DECL(B) -TENSOR_DECL(WBK) - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(PRelu)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS(X, W, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - float slope = W.Get(0, 0, 0, c); - - for (uint n = 0; n < X.batch; ++n) - { - float slope = W.BroadcastGet(n, y, x, c); - float v = X.Get(n, y, x, c); - v = prelu(v,slope); - O.Set(n, y, x, c, v); - } - -} - - -NUMTHREADS((256, 1, 1), (128, 1, 1), (64, 1, 1)) -void PRelu_Flat(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.length, 1, 1); - TENSOR_ARGS3(X, W, O); - - uint i = dispatchThreadID.x; - if (i >= O.GetLength()) return; - - float slope = W.FastBroadcastGet(i); - float v = X.FastGet(i); - v = prelu(v, slope); - O.FastSet(i, v); - -} - -NUMTHREADS((256, 1, 1), (128, 1, 1), (64, 1, 1)) -void PRelu_Loop(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.length, 1, 1); - TENSOR_ARGS3(X, W, O); - - uint i = dispatchThreadID.x; - uint len = O.GetLength(); - - while (i < len) - { - float slope = W.FastBroadcastGet(i); - float v = X.FastGet(i); - v = prelu(v, slope); - O.FastSet(i, v); - - i += _LoopStride; - } - -} - -NUMTHREADS((32, 4, 1), (32, 2, 1), (16, 2, 1)) -void KERNEL_FUNC(PRelu_CNyx2)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARGS3(X, W, O); - - uint c = dispatchThreadID.x; - uint i = dispatchThreadID.y * X.channels + c; - - if (c >= X.channels) return; - if (i >= X.GetLength()) return; - - float slope = W.FastBroadcastGet(i); - float v = X.FastGet(i); - v = prelu(v, slope); - O.FastSet(i, v); - -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Activation.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Activation.cginc.meta deleted file mode 100644 index 240281c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Activation.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: f89931ec4ed9542308f3425d051750b9 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationA.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationA.compute deleted file mode 100644 index f15f6bd..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationA.compute +++ /dev/null @@ -1,34 +0,0 @@ -// Most often used kernels - -#pragma kernel Relu_Flat -#pragma kernel Relu_FlatStrict -#pragma kernel Relu_Loop -#pragma kernel Relu6_Flat -#pragma kernel Relu6_FlatStrict -#pragma kernel Relu6_Loop - -#pragma kernel Tanh_Flat -#pragma kernel Tanh_FlatStrict -#pragma kernel Tanh_Loop -#pragma kernel Swish_Flat -#pragma kernel Swish_FlatStrict -#pragma kernel Swish_Loop - -#pragma kernel Sigmoid_Flat -#pragma kernel Sigmoid_FlatStrict -#pragma kernel Sigmoid_Loop - -#pragma kernel LeakyRelu_Flat -#pragma kernel LeakyRelu_FlatStrict -#pragma kernel LeakyRelu_Loop - -#pragma kernel Clip_Flat -#pragma kernel Clip_FlatStrict -#pragma kernel Clip_Loop - - -#pragma kernel PRelu_Flat -#pragma kernel PRelu_Loop - - -#include "Activation.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationA.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationA.compute.meta deleted file mode 100644 index 6281c05..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationA.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 517d235ce3daa4bcd88fd5494d4b99ed -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationB.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationB.compute deleted file mode 100644 index a9cc802..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationB.compute +++ /dev/null @@ -1,13 +0,0 @@ -#pragma kernel Reciprocal_Flat -#pragma kernel Reciprocal_FlatStrict -#pragma kernel Reciprocal_Loop - -#pragma kernel Sqrt_Flat -#pragma kernel Sqrt_FlatStrict -#pragma kernel Sqrt_Loop - -#pragma kernel HardSigmoid_Flat -#pragma kernel HardSigmoid_FlatStrict -#pragma kernel HardSigmoid_Loop - -#include "Activation.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationB.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationB.compute.meta deleted file mode 100644 index 77fbff4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationB.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 110f1fc1578364452982dd20f246f765 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationBase.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationBase.compute deleted file mode 100644 index fc8b765..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationBase.compute +++ /dev/null @@ -1,249 +0,0 @@ -#pragma kernel Abs_Flat -#pragma kernel Abs_FlatStrict -#pragma kernel Abs_Loop -#pragma kernel Neg_Flat -#pragma kernel Neg_FlatStrict -#pragma kernel Neg_Loop -#pragma kernel Ceil_Flat -#pragma kernel Ceil_FlatStrict -#pragma kernel Ceil_Loop -#pragma kernel Floor_Flat -#pragma kernel Floor_FlatStrict -#pragma kernel Floor_Loop -#pragma kernel Round_Flat -#pragma kernel Round_FlatStrict -#pragma kernel Round_Loop - -#pragma kernel Selu_Flat -#pragma kernel Selu_FlatStrict -#pragma kernel Selu_Loop - -#pragma kernel Softplus_Flat -#pragma kernel Softplus_FlatStrict -#pragma kernel Softplus_Loop - -#pragma kernel Elu_Flat -#pragma kernel Elu_FlatStrict -#pragma kernel Elu_Loop - -#pragma kernel Exp_Flat -#pragma kernel Exp_FlatStrict -#pragma kernel Exp_Loop -#pragma kernel Log_Flat -#pragma kernel Log_FlatStrict -#pragma kernel Log_Loop -#pragma kernel Pow_Flat -#pragma kernel Pow_FlatStrict -#pragma kernel Pow_Loop -#pragma kernel LogicalNot_Flat -#pragma kernel LogicalNot_FlatStrict -#pragma kernel Sign_Loop -#pragma kernel Sign_Flat -#pragma kernel Sign_FlatStrict -#pragma kernel Sign_Loop - -#pragma kernel Acos_Flat -#pragma kernel Acos_FlatStrict -#pragma kernel Acos_Loop -#pragma kernel Acosh_Flat -#pragma kernel Acosh_FlatStrict -#pragma kernel Acosh_Loop -#pragma kernel Asin_Flat -#pragma kernel Asin_FlatStrict -#pragma kernel Asin_Loop -#pragma kernel Asinh_Flat -#pragma kernel Asinh_FlatStrict -#pragma kernel Asinh_Loop -#pragma kernel Atan_Flat -#pragma kernel Atan_FlatStrict -#pragma kernel Atan_Loop -#pragma kernel Atanh_Flat -#pragma kernel Atanh_FlatStrict -#pragma kernel Atanh_Loop -#pragma kernel Cos_Flat -#pragma kernel Cos_FlatStrict -#pragma kernel Cos_Loop -#pragma kernel Cosh_Flat -#pragma kernel Cosh_FlatStrict -#pragma kernel Cosh_Loop -#pragma kernel Sin_Flat -#pragma kernel Sin_FlatStrict -#pragma kernel Sin_Loop -#pragma kernel Sinh_Flat -#pragma kernel Sinh_FlatStrict -#pragma kernel Sinh_Loop -#pragma kernel Tan_Flat -#pragma kernel Tan_FlatStrict -#pragma kernel Tan_Loop -#pragma kernel Erf_Flat -#pragma kernel Erf_FlatStrict -#pragma kernel Erf_Loop - -#pragma kernel Relu_NHWC CHANNELS_FIRST=0 -#pragma kernel Relu_NCHW CHANNELS_FIRST=1 -#pragma kernel Relu_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Relu_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Relu_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Relu_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Relu6_NHWC CHANNELS_FIRST=0 -#pragma kernel Relu6_NCHW CHANNELS_FIRST=1 -#pragma kernel Relu6_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Relu6_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Relu6_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Relu6_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel PRelu_NHWC CHANNELS_FIRST=0 -#pragma kernel PRelu_NCHW CHANNELS_FIRST=1 -#pragma kernel PRelu_CNyx2_NHWC CHANNELS_FIRST=0 -//#pragma kernel PRelu_CNyx2_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Selu_NHWC CHANNELS_FIRST=0 -#pragma kernel Selu_NCHW CHANNELS_FIRST=1 -#pragma kernel Selu_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Selu_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Selu_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Selu_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Tanh_NHWC CHANNELS_FIRST=0 -#pragma kernel Tanh_NCHW CHANNELS_FIRST=1 -#pragma kernel Tanh_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Tanh_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Tanh_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Tanh_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Swish_NHWC CHANNELS_FIRST=0 -#pragma kernel Swish_NCHW CHANNELS_FIRST=1 -#pragma kernel Swish_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Swish_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Swish_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Swish_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Softplus_NHWC CHANNELS_FIRST=0 -#pragma kernel Softplus_NCHW CHANNELS_FIRST=1 -#pragma kernel Softplus_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Softplus_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Softplus_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Softplus_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Sigmoid_NHWC CHANNELS_FIRST=0 -#pragma kernel Sigmoid_NCHW CHANNELS_FIRST=1 -#pragma kernel Sigmoid_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Sigmoid_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Sigmoid_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Sigmoid_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel HardSigmoid_NHWC CHANNELS_FIRST=0 -#pragma kernel HardSigmoid_NCHW CHANNELS_FIRST=1 -#pragma kernel HardSigmoid_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel HardSigmoid_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel HardSigmoid_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel HardSigmoid_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Elu_NHWC CHANNELS_FIRST=0 -#pragma kernel Elu_NCHW CHANNELS_FIRST=1 -#pragma kernel Elu_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Elu_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Elu_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Elu_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel LeakyRelu_NHWC CHANNELS_FIRST=0 -#pragma kernel LeakyRelu_NCHW CHANNELS_FIRST=1 -#pragma kernel LeakyRelu_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel LeakyRelu_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel LeakyRelu_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel LeakyRelu_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Exp_NHWC CHANNELS_FIRST=0 -#pragma kernel Exp_NCHW CHANNELS_FIRST=1 -#pragma kernel Exp_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Exp_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Exp_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Exp_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Log_NHWC CHANNELS_FIRST=0 -#pragma kernel Log_NCHW CHANNELS_FIRST=1 -#pragma kernel Log_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Log_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Log_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Log_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Sqrt_NHWC CHANNELS_FIRST=0 -#pragma kernel Sqrt_NCHW CHANNELS_FIRST=1 -#pragma kernel Sqrt_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Sqrt_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Sqrt_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Sqrt_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Pow_NHWC CHANNELS_FIRST=0 -#pragma kernel Pow_NCHW CHANNELS_FIRST=1 -#pragma kernel Pow_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Pow_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Pow_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Pow_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Clip_NHWC CHANNELS_FIRST=0 -#pragma kernel Clip_NCHW CHANNELS_FIRST=1 -#pragma kernel Clip_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Clip_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Clip_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Clip_Nyxc_NCHW CHANNELS_FIRST=1 -#pragma kernel Acos_NHWC CHANNELS_FIRST=0 -#pragma kernel Acos_NCHW CHANNELS_FIRST=1 -#pragma kernel Acos_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Acos_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Acos_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Acos_Nyxc_NHWCCHANNELS_FIRST=1 -#pragma kernel Acosh_NHWC CHANNELS_FIRST=0 -#pragma kernel Acosh_NCHW CHANNELS_FIRST=1 -#pragma kernel Acosh_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Acosh_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Acosh_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Acosh_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Asin_NHWC CHANNELS_FIRST=0 -#pragma kernel Asin_NCHW CHANNELS_FIRST=1 -#pragma kernel Asin_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Asin_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Asin_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Asin_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Asinh_NHWC CHANNELS_FIRST=0 -#pragma kernel Asinh_NCHW CHANNELS_FIRST=1 -#pragma kernel Asinh_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Asinh_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Asinh_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Asin_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Atan_NHWC CHANNELS_FIRST=0 -#pragma kernel Atan_NCHW CHANNELS_FIRST=1 -#pragma kernel Atan_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Atan_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Atan_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Atan_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Atanh_NHWC CHANNELS_FIRST=0 -#pragma kernel Atanh_NCHW CHANNELS_FIRST=1 -#pragma kernel Atanh_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Atanh_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Atanh_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Atanh_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Cos_NHWC CHANNELS_FIRST=0 -#pragma kernel Cos_NCHW CHANNELS_FIRST=1 -#pragma kernel Cos_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Cos_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Cos_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Cos_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Cosh_NHWC CHANNELS_FIRST=0 -#pragma kernel Cosh_NCHW CHANNELS_FIRST=1 -#pragma kernel Cosh_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Cosh_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Cosh_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Cosh_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Sin_NHWC CHANNELS_FIRST=0 -#pragma kernel Sin_NCHW CHANNELS_FIRST=1 -#pragma kernel Sin_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Sin_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Sin_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Sin_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Sinh_NHWC CHANNELS_FIRST=0 -#pragma kernel Sinh_NCHW CHANNELS_FIRST=1 -#pragma kernel Sinh_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Sinh_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Sinh_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Sinh_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Tan_NHWC CHANNELS_FIRST=0 -#pragma kernel Tan_NCHW CHANNELS_FIRST=1 -#pragma kernel Tan_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Tan_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Tan_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Tan_Nyxc_NHWC CHANNELS_FIRST=1 -#pragma kernel Erf_NHWC CHANNELS_FIRST=0 -#pragma kernel Erf_NCHW CHANNELS_FIRST=1 -#pragma kernel Erf_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel Erf_CNyx_NHWC CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel Erf_Nyxc_NHWC CHANNELS_FIRST=0 -//#pragma kernel Erf_Nyxc_NHWC CHANNELS_FIRST=1 - -#include "Activation.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationBase.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationBase.compute.meta deleted file mode 100644 index 1c31e43..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ActivationBase.compute.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: fdc94044b2f234c0fa80ada3771a2ae7 -timeCreated: 1495527718 -licenseType: Pro -ComputeShaderImporter: - currentAPIMask: 196608 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/BarracudaReferenceImpl.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/BarracudaReferenceImpl.compute deleted file mode 100644 index 4b9fb4e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/BarracudaReferenceImpl.compute +++ /dev/null @@ -1,2815 +0,0 @@ -#pragma kernel Dense_NHWC CHANNELS_FIRST=0 -#pragma kernel Dense_NCHW CHANNELS_FIRST=1 -#pragma kernel Dense3_NHWC CHANNELS_FIRST=0 -#pragma kernel Dense3_NCHW CHANNELS_FIRST=1 -#pragma kernel Conv2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Conv2D_NCHW CHANNELS_FIRST=1 -#pragma kernel Conv3D_NHWC CHANNELS_FIRST=0 -#pragma kernel Conv3D_NCHW CHANNELS_FIRST=1 -#pragma kernel Conv2DWinograd_2x2_3x3_NHWC CHANNELS_FIRST=0 -#pragma kernel Conv2DWinograd_2x2_3x3_NCHW CHANNELS_FIRST=1 -#pragma kernel DepthwiseConv2D_NHWC CHANNELS_FIRST=0 -#pragma kernel DepthwiseConv2D_NCHW CHANNELS_FIRST=1 -#pragma kernel Conv2DTrans_NHWC CHANNELS_FIRST=0 -#pragma kernel Conv2DTrans_NCHW CHANNELS_FIRST=1 -#pragma kernel Upsample2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Upsample2D_NCHW CHANNELS_FIRST=1 -#pragma kernel Upsample3D_NHWC CHANNELS_FIRST=0 -#pragma kernel Upsample3D_NCHW CHANNELS_FIRST=1 -#pragma kernel UpsampleBilinear2D_NHWC CHANNELS_FIRST=0 -#pragma kernel UpsampleBilinear2D_NCHW CHANNELS_FIRST=1 -#pragma kernel UpsampleTrilinear3D_NHWC CHANNELS_FIRST=0 -#pragma kernel UpsampleTrilinear3D_NCHW CHANNELS_FIRST=1 -#pragma kernel Resample2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Resample2D_NCHW CHANNELS_FIRST=1 -#pragma kernel ResampleBilinear2D_NHWC CHANNELS_FIRST=0 -#pragma kernel ResampleBilinear2D_NCHW CHANNELS_FIRST=1 -#pragma kernel DepthToSpace_CRD_NHWC CHANNELS_FIRST=0 -#pragma kernel DepthToSpace_CRD_NCHW CHANNELS_FIRST=1 -#pragma kernel DepthToSpace_DCR_NHWC CHANNELS_FIRST=0 -#pragma kernel DepthToSpace_DCR_NCHW CHANNELS_FIRST=1 -#pragma kernel SpaceToDepth_NHWC CHANNELS_FIRST=0 -#pragma kernel SpaceToDepth_NCHW CHANNELS_FIRST=1 -#pragma kernel Unstride2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Unstride2D_NCHW CHANNELS_FIRST=1 -#pragma kernel MaxPool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel MaxPool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel AvgPool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel AvgPool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel GlobalMaxPool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel GlobalMaxPool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel GlobalAvgPool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel GlobalAvgPool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel GlobalAvgVariancePool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel GlobalAvgVariancePool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel ScaleBias_NHWC CHANNELS_FIRST=0 -#pragma kernel ScaleBias_NCHW CHANNELS_FIRST=1 -#pragma kernel InstanceNorm_NHWC CHANNELS_FIRST=0 -#pragma kernel InstanceNorm_NCHW CHANNELS_FIRST=1 -#pragma kernel Dropout_NHWC CHANNELS_FIRST=0 -#pragma kernel Dropout_NCHW CHANNELS_FIRST=1 -#pragma kernel Relu_NHWC CHANNELS_FIRST=0 -#pragma kernel Relu_NCHW CHANNELS_FIRST=1 -#pragma kernel Abs_NHWC CHANNELS_FIRST=0 -#pragma kernel Abs_NCHW CHANNELS_FIRST=1 -#pragma kernel Neg_NHWC CHANNELS_FIRST=0 -#pragma kernel Neg_NCHW CHANNELS_FIRST=1 -#pragma kernel Ceil_NHWC CHANNELS_FIRST=0 -#pragma kernel Ceil_NCHW CHANNELS_FIRST=1 -#pragma kernel Floor_NHWC CHANNELS_FIRST=0 -#pragma kernel Floor_NCHW CHANNELS_FIRST=1 -#pragma kernel Round_NHWC CHANNELS_FIRST=0 -#pragma kernel Round_NCHW CHANNELS_FIRST=1 -#pragma kernel Reciprocal_NHWC CHANNELS_FIRST=0 -#pragma kernel Reciprocal_NCHW CHANNELS_FIRST=1 -#pragma kernel Swish_NHWC CHANNELS_FIRST=0 -#pragma kernel Swish_NCHW CHANNELS_FIRST=1 -#pragma kernel Softmax_NHWC CHANNELS_FIRST=0 -#pragma kernel Softmax_NCHW CHANNELS_FIRST=1 -#pragma kernel LogSoftmax_NHWC CHANNELS_FIRST=0 -#pragma kernel LogSoftmax_NCHW CHANNELS_FIRST=1 -#pragma kernel Tanh_NHWC CHANNELS_FIRST=0 -#pragma kernel Tanh_NCHW CHANNELS_FIRST=1 -#pragma kernel Softplus_NHWC CHANNELS_FIRST=0 -#pragma kernel Softplus_NCHW CHANNELS_FIRST=1 -#pragma kernel Sigmoid_NHWC CHANNELS_FIRST=0 -#pragma kernel Sigmoid_NCHW CHANNELS_FIRST=1 -#pragma kernel HardSigmoid_NHWC CHANNELS_FIRST=0 -#pragma kernel HardSigmoid_NCHW CHANNELS_FIRST=1 -#pragma kernel Relu6_NHWC CHANNELS_FIRST=0 -#pragma kernel Relu6_NCHW CHANNELS_FIRST=1 -#pragma kernel Elu_NHWC CHANNELS_FIRST=0 -#pragma kernel Elu_NCHW CHANNELS_FIRST=1 -#pragma kernel LeakyRelu_NHWC CHANNELS_FIRST=0 -#pragma kernel LeakyRelu_NCHW CHANNELS_FIRST=1 -#pragma kernel PRelu_NHWC CHANNELS_FIRST=0 -#pragma kernel PRelu_NCHW CHANNELS_FIRST=1 -#pragma kernel Selu_NHWC CHANNELS_FIRST=0 -#pragma kernel Selu_NCHW CHANNELS_FIRST=1 -#pragma kernel Exp_NHWC CHANNELS_FIRST=0 -#pragma kernel Exp_NCHW CHANNELS_FIRST=1 -#pragma kernel Log_NHWC CHANNELS_FIRST=0 -#pragma kernel Log_NCHW CHANNELS_FIRST=1 -#pragma kernel Sqrt_NHWC CHANNELS_FIRST=0 -#pragma kernel Sqrt_NCHW CHANNELS_FIRST=1 -#pragma kernel Pow_NHWC CHANNELS_FIRST=0 -#pragma kernel Pow_NCHW CHANNELS_FIRST=1 -#pragma kernel Acos_NHWC CHANNELS_FIRST=0 -#pragma kernel Acos_NCHW CHANNELS_FIRST=1 -#pragma kernel Acosh_NHWC CHANNELS_FIRST=0 -#pragma kernel Acosh_NCHW CHANNELS_FIRST=1 -#pragma kernel Asin_NHWC CHANNELS_FIRST=0 -#pragma kernel Asin_NCHW CHANNELS_FIRST=1 -#pragma kernel Asinh_NHWC CHANNELS_FIRST=0 -#pragma kernel Asinh_NCHW CHANNELS_FIRST=1 -#pragma kernel Atan_NHWC CHANNELS_FIRST=0 -#pragma kernel Atan_NCHW CHANNELS_FIRST=1 -#pragma kernel Atanh_NHWC CHANNELS_FIRST=0 -#pragma kernel Atanh_NCHW CHANNELS_FIRST=1 -#pragma kernel Cos_NHWC CHANNELS_FIRST=0 -#pragma kernel Cos_NCHW CHANNELS_FIRST=1 -#pragma kernel Cosh_NHWC CHANNELS_FIRST=0 -#pragma kernel Cosh_NCHW CHANNELS_FIRST=1 -#pragma kernel Sin_NHWC CHANNELS_FIRST=0 -#pragma kernel Sin_NCHW CHANNELS_FIRST=1 -#pragma kernel Sinh_NHWC CHANNELS_FIRST=0 -#pragma kernel Sinh_NCHW CHANNELS_FIRST=1 -#pragma kernel Tan_NHWC CHANNELS_FIRST=0 -#pragma kernel Tan_NCHW CHANNELS_FIRST=1 -#pragma kernel Erf_NHWC CHANNELS_FIRST=0 -#pragma kernel Erf_NCHW CHANNELS_FIRST=1 -#pragma kernel Clip_NHWC CHANNELS_FIRST=0 -#pragma kernel Clip_NCHW CHANNELS_FIRST=1 -#pragma kernel Tile_NHWC CHANNELS_FIRST=0 -#pragma kernel Tile_NCHW CHANNELS_FIRST=1 -#pragma kernel Copy_NHWC CHANNELS_FIRST=0 -#pragma kernel Copy_NCHW CHANNELS_FIRST=1 -#pragma kernel Copy8D -#pragma kernel ReshapeFromNHWCModel_NCHW CHANNELS_FIRST=1 -#pragma kernel Reshape8DFromChannelFirstModel_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastAdd_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastAdd_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastSub_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastSub_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastMul_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastMul_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastDiv_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastDiv_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastPow_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastPow_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastMin_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastMin_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastMax_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastMax_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastMean_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastMean_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastGreater_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastGreater_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastGreaterEqual_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastGreaterEqual_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLess_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLess_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLessEqual_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLessEqual_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastEqual_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastEqual_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLogicalOr_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLogicalOr_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLogicalAnd_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLogicalAnd_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLogicalXor_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLogicalXor_NCHW CHANNELS_FIRST=1 -#pragma kernel LogicalNot_NHWC CHANNELS_FIRST=0 -#pragma kernel LogicalNot_NCHW CHANNELS_FIRST=1 -#pragma kernel Sign_NHWC CHANNELS_FIRST=0 -#pragma kernel Sign_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastWhere_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastWhere_NCHW CHANNELS_FIRST=1 -#pragma kernel ArgMax_NHWC CHANNELS_FIRST=0 -#pragma kernel ArgMax_NCHW CHANNELS_FIRST=1 -#pragma kernel ArgMin_NHWC CHANNELS_FIRST=0 -#pragma kernel ArgMin_NCHW CHANNELS_FIRST=1 -#pragma kernel ReduceMin_NHWC CHANNELS_FIRST=0 -#pragma kernel ReduceMin_NCHW CHANNELS_FIRST=1 -#pragma kernel ReduceMax_NHWC CHANNELS_FIRST=0 -#pragma kernel ReduceMax_NCHW CHANNELS_FIRST=1 -#pragma kernel ReduceSum_NHWC CHANNELS_FIRST=0 -#pragma kernel ReduceSum_NCHW CHANNELS_FIRST=1 -#pragma kernel ReduceMean_NHWC CHANNELS_FIRST=0 -#pragma kernel ReduceMean_NCHW CHANNELS_FIRST=1 -#pragma kernel ReduceProd_NHWC CHANNELS_FIRST=0 -#pragma kernel ReduceProd_NCHW CHANNELS_FIRST=1 -#pragma kernel Border2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Border2D_NCHW CHANNELS_FIRST=1 -#pragma kernel Border3D_NHWC CHANNELS_FIRST=0 -#pragma kernel Border3D_NCHW CHANNELS_FIRST=1 -#pragma kernel Pad2DEdge_NHWC CHANNELS_FIRST=0 -#pragma kernel Pad2DEdge_NCHW CHANNELS_FIRST=1 -#pragma kernel Pad2DReflect_NHWC CHANNELS_FIRST=0 -#pragma kernel Pad2DReflect_NCHW CHANNELS_FIRST=1 -#pragma kernel Pad2DSymmetric_NHWC CHANNELS_FIRST=0 -#pragma kernel Pad2DSymmetric_NCHW CHANNELS_FIRST=1 -#pragma kernel StridedSlice_NHWC CHANNELS_FIRST=0 -#pragma kernel StridedSlice_NCHW CHANNELS_FIRST=1 -#pragma kernel Gather_NHWC CHANNELS_FIRST=0 -#pragma kernel Gather_NCHW CHANNELS_FIRST=1 -#pragma kernel ScatterND_NHWC CHANNELS_FIRST=0 -#pragma kernel ScatterND_NCHW CHANNELS_FIRST=1 -#pragma kernel Transpose2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Transpose2D_NCHW CHANNELS_FIRST=1 -#pragma kernel Transpose_NHWC CHANNELS_FIRST=0 -#pragma kernel Transpose_NCHW CHANNELS_FIRST=1 -#pragma kernel Transpose8D -#pragma kernel TransposeToChannelFirst -#pragma kernel Expand_NHWC CHANNELS_FIRST=0 -#pragma kernel Expand_NCHW CHANNELS_FIRST=1 -#pragma kernel ConstantOfShape_NHWC CHANNELS_FIRST=0 -#pragma kernel ConstantOfShape_NCHW CHANNELS_FIRST=1 -#pragma kernel LRN_NHWC CHANNELS_FIRST=0 -#pragma kernel LRN_NCHW CHANNELS_FIRST=1 -#pragma kernel OneHot_NHWC CHANNELS_FIRST=0 -#pragma kernel OneHot_NCHW CHANNELS_FIRST=1 -#pragma kernel RoiAlign_NHWC CHANNELS_FIRST=0 -#pragma kernel RoiAlign_NCHW CHANNELS_FIRST=1 - -#include "Tensor.cginc" -#include "Random.cginc" - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SUFFIX) KERNEL##SUFFIX##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SUFFIX) KERNEL##SUFFIX##_NHWC -#endif -#define FUNC_NAME(KERNEL, SUFFIX) FUNC_NAME_CALL(KERNEL, SUFFIX) - -TENSOR_DECL(X) -TENSOR_DECL(W) -TENSOR_DECL(K) -TENSOR_DECL(B) -TENSOR_DECL_RW(O) - -uint4 _Pad; -uint4 _Pool; -uint4 _Stride; -uint4 _ChannelWriteMask; -uint _Axis; -float _Alpha; -float _Beta; -float _Epsilon; -float _Seed; -int _IsFirstDispatch; - -[numthreads(8,8,1)] -void KERNEL_FUNC(Dense)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_ARGS4(X, W, B, O); - - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - - if (x >= O.GetFlatWidth()) return; - if (y >= O.GetFlatHeight()) return; - - float acc = B.FastGet(x); - for (uint i = 0; i < X.GetFlatWidth(); ++i) - acc += X.Get(y, i) * W.Get(i, x); - - O.SetWithActivation(y, x, acc); -} - -[numthreads(8, 8, 1)] -void KERNEL_FUNC(Dense3)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.channels, 1); - TENSOR_ARGS4(X, W, B, O); - - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - uint z = dispatchThreadID.z; - - if (x >= O.width) return; - if (y >= O.channels) return; - - float acc = B.FastGet(x); - for (uint i = 0; i < X.width; ++i) - acc += X.Get(z, 0, i, y) * W.Get(i, x); - - O.Set(z, 0, x, y, acc); -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(PRelu)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, W, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = X.Get8D(s,r,n,t,d,h,w,c); - float slope = W.BroadcastGet8D(s,r,n,t,d,h,w,c); - - v = max(0.0f,v) + slope * min(0.0f,v); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -//DISPATCH ARGS(O.channels, O.width, O.height); -#define ACTIVATION(name, op_name) \ -[numthreads(4, 4, 4)] \ -void KERNEL_FUNC(name)(uint3 dispatchThreadID : SV_DispatchThreadID)\ -{\ - TENSOR_ARGS2_8D(X, O);\ -\ - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z;\ - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return;\ -\ - for (uint s = 0; s < O.sequenceLength; ++s)\ - for (uint r = 0; r < O.numberOfDirections; ++r)\ - for (uint n = 0; n < O.batch; ++n)\ - for (uint t = 0; t < O.extraDimension; ++t)\ - for (uint d = 0; d < O.depth; ++d)\ - {\ - float v = X.Get8D(s,r,n,t,d,h,w,c);\ - v = op_name (v);\ - O.Set8D(s,r,n,t,d,h,w,c,v);\ - }\ -} - -float ReluOp(float v) -{ - v = 0.5f * (v + abs(v)); - return v; -} -ACTIVATION(Relu, ReluOp); - -float SeluOp(float v) -{ - v = _Beta * (max(v, 0.0f) + min(_Alpha * (exp(v) - 1.0f), 0.0f)); - return v; -} -ACTIVATION(Selu, SeluOp); - -float AbsOp(float v) -{ - v = abs(v); - return v; -} -ACTIVATION(Abs, AbsOp); - -float NegOp(float v) -{ - v = -v; - return v; -} -ACTIVATION(Neg, NegOp); - -float CeilOp(float v) -{ - v = ceil(v); - return v; -} -ACTIVATION(Ceil, CeilOp); - -float FloorOp(float v) -{ - v = floor(v); - return v; -} -ACTIVATION(Floor, FloorOp); - -float RoundOp(float v) -{ - v = round(v); - return v; -} -ACTIVATION(Round, RoundOp); - - -float ReciprocalOp(float v) -{ - v = 1.0f / v; - return v; -} -ACTIVATION(Reciprocal, ReciprocalOp); - -float SwishOp(float v) -{ - v = v / (1 + exp(-v)); - return v; -} -ACTIVATION(Swish, SwishOp); - -float TanhOp(float v) -{ - v = tanh(clamp(v,-16.0f,16.0f));//clamp to avoid NaNs for large values. - return v; -} -ACTIVATION(Tanh, TanhOp); - -float SoftplusOp(float v) -{ - v = log(exp(v) + 1); - return v; -} -ACTIVATION(Softplus, SoftplusOp); - -float SigmoidOp(float v) -{ - v = 1 / (1 + exp(-v)); - return v; -} -ACTIVATION(Sigmoid, SigmoidOp); - -float HardSigmoidOp(float v) -{ - v = max(0.0f, min(1.0f, _Alpha * v + _Beta)); - return v; -} -ACTIVATION(HardSigmoid, HardSigmoidOp); - -float Relu6Op(float v) -{ - v = min(max(0, v), 6); - return v; -} -ACTIVATION(Relu6, Relu6Op); - -float EluOp(float v) -{ - if (v <= 0) - v = _Alpha * (exp(v) - 1); - return v; -} -ACTIVATION(Elu, EluOp); - -float LeakyReluOp(float v) -{ - v = max(v, _Alpha * v); - return v; -} -ACTIVATION(LeakyRelu, LeakyReluOp); - -float ExpOp(float v) -{ - v = exp(v); - return v; -} -ACTIVATION(Exp, ExpOp); - -float LogOp(float v) -{ - v = log(v); - return v; -} -ACTIVATION(Log, LogOp); - -float SqrtOp(float v) -{ - v = sqrt(v); - return v; -} -ACTIVATION(Sqrt, SqrtOp); - -float AcosOp(float v) -{ - v = acos(v); - return v; -} -ACTIVATION(Acos, AcosOp); - -float AcoshOp(float v) -{ - v = log(v + sqrt(v * v - 1.0f)); - return v; -} -ACTIVATION(Acosh, AcoshOp); - -float AsinOp(float v) -{ - v = asin(v); - return v; -} -ACTIVATION(Asin, AsinOp); - -float AsinhOp(float v) -{ - v = log(v + sqrt(v*v + 1.0f)); - return v; -} -ACTIVATION(Asinh, AsinhOp); - -float AtanOp(float v) -{ - v = atan(v); - return v; -} -ACTIVATION(Atan, AtanOp); - -float AtanhOp(float v) -{ - v = 0.5f * log((1.0f + v) / (1.0f - v)); - return v; -} -ACTIVATION(Atanh, AtanhOp); - -float CosOp(float v) -{ - v = cos(v); - return v; -} -ACTIVATION(Cos, CosOp); - -float CoshOp(float v) -{ - v = 0.5f * (exp(v) + exp(-v)); - return v; -} -ACTIVATION(Cosh, CoshOp); - -float SinOp(float v) -{ - v = sin(v); - return v; -} -ACTIVATION(Sin, SinOp); - -float SinhOp(float v) -{ - v = 0.5f * (exp(v) - exp(-v)); - return v; -} -ACTIVATION(Sinh, SinhOp); - -float TanOp(float v) -{ - v = tan(v); - return v; -} -ACTIVATION(Tan, TanOp); - -float signed_pow(float f, float e) -{ - // handle negative f - float v = pow(abs(f), e); - float s = (e % 2 == 1) ? - sign(f): // exponent is odd => sign(f) * pow(abs(f), e) - 1; // exponent is even => pow(abs(f), e) - return v * s; -} -float PowOp(float v) -{ - v = signed_pow(v, _Alpha); - return v; -} -ACTIVATION(Pow, PowOp); - -float ClipOp(float v) -{ - v = clamp(v, _Alpha, _Beta); - return v; -} -ACTIVATION(Clip, ClipOp); - -float ErfOp(float v) -{ - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x = abs(v); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t = 1.0f / (1.0f + p * x); - float t2 = t * t; - float t3 = t2 * t; - float t4 = t3 * t; - float t5 = t4 * t; - - return sign(v)*(1 - (a1*t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5)*exp(-x * x)); -} -ACTIVATION(Erf, ErfOp); - -[numthreads(4,4,4)] -void KERNEL_FUNC(BroadcastAdd)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = - X.BroadcastGet8D(s,r,n,t,d,h,w,c) + - B.BroadcastGet8D(s,r,n,t,d,h,w,c); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(BroadcastSub)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = - X.BroadcastGet8D(s,r,n,t,d,h,w,c) - - B.BroadcastGet8D(s,r,n,t,d,h,w,c); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(BroadcastMul)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = - X.BroadcastGet8D(s,r,n,t,d,h,w,c) * - B.BroadcastGet8D(s,r,n,t,d,h,w,c); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(BroadcastDiv)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = - X.BroadcastGet8D(s,r,n,t,d,h,w,c) / - B.BroadcastGet8D(s,r,n,t,d,h,w,c); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(BroadcastPow)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = signed_pow( - X.BroadcastGet8D(s,r,n,t,d,h,w,c), - B.BroadcastGet8D(s,r,n,t,d,h,w,c)); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(BroadcastMin)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = min( - X.BroadcastGet8D(s,r,n,t,d,h,w,c), - B.BroadcastGet8D(s,r,n,t,d,h,w,c)); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(BroadcastMax)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = max( - X.BroadcastGet8D(s,r,n,t,d,h,w,c), - B.BroadcastGet8D(s,r,n,t,d,h,w,c)); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastMean)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = X.BroadcastGet8D(s,r,n,t,d,h,w,c); - a *= _IsFirstDispatch ? _Alpha : 1.0f; - float b = B.BroadcastGet8D(s,r,n,t,d,h,w,c) * _Alpha; - float v = a + b; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastGreater)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = X.BroadcastGet8D(s,r,n,t,d,h,w,c); - float b = B.BroadcastGet8D(s,r,n,t,d,h,w,c); - float v = (a > b) ? 1.0f : 0.0f; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastGreaterEqual)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = X.BroadcastGet8D(s,r,n,t,d,h,w,c); - float b = B.BroadcastGet8D(s,r,n,t,d,h,w,c); - float v = (a >= b) ? 1.0f : 0.0f; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastLess)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = X.BroadcastGet8D(s,r,n,t,d,h,w,c); - float b = B.BroadcastGet8D(s,r,n,t,d,h,w,c); - float v = (a < b) ? 1.0f : 0.0f; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastLessEqual)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = X.BroadcastGet8D(s,r,n,t,d,h,w,c); - float b = B.BroadcastGet8D(s,r,n,t,d,h,w,c); - float v = (a <= b) ? 1.0f : 0.0f; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastEqual)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = X.BroadcastGet8D(s,r,n,t,d,h,w,c); - float b = B.BroadcastGet8D(s,r,n,t,d,h,w,c); - float v = (a == b) ? 1.0f : 0.0f; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastLogicalOr)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = (X.BroadcastGet8D(s,r,n,t,d,h,w,c) == 0.0f) ? 0.0f: 1.0f; - float b = (B.BroadcastGet8D(s,r,n,t,d,h,w,c) == 0.0f) ? 0.0f: 1.0f; - float v = ((a + b) >= 1.0f) ? 1.0f : 0.0f; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastLogicalAnd)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = (X.BroadcastGet8D(s,r,n,t,d,h,w,c) == 0.0f) ? 0.0f: 1.0f; - float b = (B.BroadcastGet8D(s,r,n,t,d,h,w,c) == 0.0f) ? 0.0f: 1.0f; - float v = ((a + b) > 1.5f) ? 1.0f : 0.0f; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastLogicalXor)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_TWOINPUTS_8D(X, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float a = (X.BroadcastGet8D(s,r,n,t,d,h,w,c) == 0.0f) ? 0.0f: 1.0f; - float b = (B.BroadcastGet8D(s,r,n,t,d,h,w,c) == 0.0f) ? 0.0f: 1.0f; - float v = ((a + b) == 1.0f) ? 1.0f : 0.0f; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -float LogicalNotOp(float v) -{ - v = (v == 0.0f) ? 1.0f: 0.0f; - return v; -} -ACTIVATION(LogicalNot, LogicalNotOp); - -ACTIVATION(Sign, sign); - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(BroadcastWhere)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_THREEINPUTS_8D(X, W, K, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - bool cond = (X.BroadcastGet8D(s,r,n,t,d,h,w,c) != 0.0f); - float a = W.BroadcastGet8D(s,r,n,t,d,h,w,c); - float b = K.BroadcastGet8D(s,r,n,t,d,h,w,c); - float v = cond ? a : b; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 1)] -void KERNEL_FUNC(ArgMax)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height, 1); - TENSOR_ARGS3_8D(X, B, O); - - uint w = dispatchThreadID.x; uint h = dispatchThreadID.y; - if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - int maxIdx = 0; - float maxV = X.Get8D(s,r,n,t,d,h,w,0); - for (uint c = 1; c < X.channels; ++c) - { - float v = X.Get8D(s,r,n,t,d,h,w,c); - if (v > maxV) - { - maxV = v; - maxIdx = c; - } - } - O.Set8D(s,r,n,t,d,h,w,0,maxIdx); - } -} - -[numthreads(4, 4, 1)] -void KERNEL_FUNC(ArgMin)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height, 1); - TENSOR_ARGS3_8D(X, B, O); - - uint w = dispatchThreadID.x; uint h = dispatchThreadID.y; - if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - int minIdx = 0; - float minV = X.Get8D(s,r,n,t,d,h,w,0); - for (uint c = 1; c < X.channels; ++c) - { - float v = X.Get8D(s,r,n,t,d,h,w,c); - if (v < minV) - { - minV = v; - minIdx = c; - } - } - O.Set8D(s,r,n,t,d,h,w,0,minIdx); - } -} - -#define REDUCE(name, op_name, defaultValue, shouldNormalize) \ -[numthreads(4,4,1)] \ -void KERNEL_FUNC(name)(uint3 dispatchThreadID : SV_DispatchThreadID)\ -{\ - TENSOR_ARGS3_8D(X, B, O);\ -\ - uint w = dispatchThreadID.x; uint h = dispatchThreadID.y;\ - if (w >= O.width) return; if (h >= O.height) return;\ -\ - for (uint s = 0; s < O.sequenceLength; ++s)\ - for (uint r = 0; r < O.numberOfDirections; ++r)\ - for (uint n = 0; n < O.batch; ++n)\ - for (uint t = 0; t < O.extraDimension; ++t)\ - for (uint d = 0; d < O.depth; ++d)\ - {\ - float v = defaultValue;\ - for (uint c = 0; c < X.channels; ++c)\ - v = op_name (v, X.Get8D(s,r,n,t,d,h,w,c) );\ -\ - if (shouldNormalize)\ - v /= X.channels;\ - O.Set8D(s,r,n,t,d,h,w,0,v);\ - }\ -} - -float ReduceMinOp(float v, float x) -{ - v = min(v, x); - return v; -} -REDUCE(ReduceMin, ReduceMinOp, FLT_MAX, 0); - -float ReduceMaxOp(float v, float x) -{ - v = max(v, x); - return v; -} -REDUCE(ReduceMax, ReduceMaxOp, -FLT_MAX, 0); - -float ReduceSumOp(float v, float x) -{ - v += x; - return v; -} -REDUCE(ReduceSum, ReduceSumOp, 0, 0); -REDUCE(ReduceMean, ReduceSumOp, 0, 1); - -float ReduceProdOp(float v, float x) -{ - v *= x; - return v; -} -REDUCE(ReduceProd, ReduceProdOp, 1, 0); - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Tile)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - // NOTE: dispatched over X (not O) - //DISPATCH ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = X.Get8D(s % X.sequenceLength, r % X.numberOfDirections, n % X.batch, t % X.extraDimension, d % X.depth, h % X.height, w % X.width, c % X.channels); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Copy)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - // NOTE: dispatched over X (not O) - //DISPATCH ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= X.channels) return; if (x >= X.width) return; if (y >= X.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - O.Set(n + _Pad[0], y + _Pad[1], x + _Pad[2], c + _Pad[3], v); - } -} - -[numthreads(4,4,4)] -void Copy8D(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - // TODO: handle `_Pad` for 8D concats (see `Copy` kernel and `Concat()` operator). - // NOTE: dispatched over X (not O) - //DISPATCH_ARGS(X.channels, X.width, X.height); in ChannelLast aka SRNTDHWC - //DISPATCH_ARGS(X.width, X.height, X.depth); in ChannelFirst aka SRNCTDHW - TENSOR_ARGS2(X, O); - - uint d0_size = _Stride.x; - uint d1_size = _Stride.y; - uint d2_size = _Stride.z; - uint d3_size = _Stride.w; - uint d4_size = _Pool.x; - uint d5_size = _Pool.y; - uint d6_size = _Pool.z; - uint d7_size = _Pool.w; - - uint d7 = dispatchThreadID.x; - uint d6 = dispatchThreadID.y; - uint d5 = dispatchThreadID.z; - if (d7 >= d7_size) return; - if (d6 >= d6_size) return; - if (d5 >= d5_size) return; - - uint d5_7offset = d5 * d6_size * d7_size + d6 * d7_size + d7; - uint d0_4stride = d5_size * d6_size * d7_size; - uint d0_4offset = 0; - - for (uint d0 = 0; d0 < d0_size; ++d0) - for (uint d1 = 0; d1 < d1_size; ++d1) - for (uint d2 = 0; d2 < d2_size; ++d2) - for (uint d3 = 0; d3 < d3_size; ++d3) - for (uint d4 = 0; d4 < d4_size; ++d4) - { - uint srcIndex = d0_4offset + d5_7offset; - float value = X.FastGet(srcIndex); - O.FastSet(srcIndex, value); - - d0_4offset += d0_4stride; - } -} - -[numthreads(4,4,4)] -void ReshapeFromNHWCModel_NCHW(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height,O.channels); - TENSOR_ARGS2(X, O); - - uint w = dispatchThreadID.x; - uint h = dispatchThreadID.y; - uint c = dispatchThreadID.z; - if (c >= O.channels) return; - if (h >= O.height) return; - if (w >= O.width) return; - - for (uint n = 0; n < O.batch; ++n) - { - //find the memory offset of target item in HWC format - uint index_NHWC = O.IndexHWC(n,h,w,c); - //from this offset find indices of item in HWC format before the reshape - uint c_NHWC, y_NHWC, x_NHWC, b_NHWC; - X.GetPositionFromIndexNHWC(index_NHWC, b_NHWC, y_NHWC, x_NHWC, c_NHWC); - - //finally copy item - float v = X.Get(b_NHWC, y_NHWC, x_NHWC, c_NHWC); - O.Set(n, h, w, c, v); - } -} - -uint Get8DOffsetFromIndices(uint d0,uint d1,uint d2,uint d3,uint d4,uint d5,uint d6,uint d7, - uint s0,uint s1,uint s2,uint s3,uint s4,uint s5,uint s6,uint s7) -{ - return d0 * s7 * s6 * s5 * s4 * s3 * s2 * s1 + - d1 * s7 * s6 * s5 * s4 * s3 * s2 + - d2 * s7 * s6 * s5 * s4 * s3 + - d3 * s7 * s6 * s5 * s4 + - d4 * s7 * s6 * s5 + - d5 * s7 * s6 + - d6 * s7 + - d7; -} - -[numthreads(4,4,4)] -void Reshape8DFromChannelFirstModel_NCHW(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height,O.channels); - TENSOR_ARGS2(X, O); - - uint sX = _Pad.x; - uint rX = _Pad.y; - uint nX = X.batch; - uint cX = X.channels; - uint tX = _Pad.z; - uint dX = _Pad.w; - uint hX = X.height; - uint wX = X.width; - - uint sO = _Pool.x; - uint rO = _Pool.y; - uint nO = O.batch; - uint cO = O.channels; - uint tO = _Pool.z; - uint dO = _Pool.w; - uint hO = O.height; - uint wO = O.width; - - uint w = dispatchThreadID.x; - uint h = dispatchThreadID.y; - uint c = dispatchThreadID.z; - if (c >= cO) return; - if (h >= hO) return; - if (w >= wO) return; - - for (uint s = 0; s < sO; ++s) - for (uint r = 0; r < rO; ++r) - for (uint n = 0; n < nO; ++n) - for (uint t = 0; t < tO; ++t) - for (uint d = 0; d < dO; ++d) - { - //find the memory offset of target item in `channelLast` format - uint targetIndex_InChannelLast = Get8DOffsetFromIndices(s ,r ,n ,t ,d ,h ,w ,c , - sO,rO,nO,tO,dO,hO,wO,cO); - - //from this offset find indices of item in `channelLast` format before the reshape - uint sL, rL, nL, tL, dL, hL, wL, cL; - sL = (targetIndex_InChannelLast / (cX * wX * hX * dX * tX * nX * rX)) % sX; - rL = (targetIndex_InChannelLast / (cX * wX * hX * dX * tX * nX)) % rX; - nL = (targetIndex_InChannelLast / (cX * wX * hX * dX * tX)) % nX; - tL = (targetIndex_InChannelLast / (cX * wX * hX * dX)) % tX; - dL = (targetIndex_InChannelLast / (cX * wX * hX)) % dX; - hL = (targetIndex_InChannelLast / (cX * wX)) % hX; - wL = (targetIndex_InChannelLast / cX) % wX; - cL = targetIndex_InChannelLast % cX; - - //find `channelFirst` memory offsets - uint sourceIndex = Get8DOffsetFromIndices(sL,rL,nL,cL,tL,dL,hL,wL, - sX,rX,nX,cX,tX,dX,hX,wX); - uint targetIndex = Get8DOffsetFromIndices(s ,r ,n ,c ,t ,d ,h ,w , - sO,rO,nO,cO,tO,dO,hO,wO); - - //finally copy item - float v = X.FastGet(sourceIndex); - O.FastSet(targetIndex, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Dropout)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float4 seed1 = float4((float)s / O.sequenceLength, (float)r / O.numberOfDirections, (float)t / O.extraDimension, (float)d / O.depth); - float4 seed2 = float4((float)n / O.batch, (float)h / O.height, (float)w / O.width, (float)c / O.channels); - float4 seed = frac(seed1 + seed2 + _Seed); - - float v = X.Get8D(s,r,n,t,d,h,w,c); - v *= Bernoulli(seed, 1 - _Alpha) / (1 - _Alpha); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(ScaleBias)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS4_8D(X, W, B, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - float scale = W.Get(0, 0, 0, c); - float bias = B.Get(0, 0, 0, c); - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = X.Get8D(s,r,n,t,d,h,w,c); - v = v * scale + bias; - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(16,4,1)] -void KERNEL_FUNC(Softmax)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_ARGS2_8D(X, O); - - uint y = dispatchThreadID.x; - uint x = dispatchThreadID.y; - - uint height = (uint)_Stride[0]; - uint reducedDim = (uint)_Stride[1]; - uint width = (uint)_Stride[2]; - - if (y >= height) return; - if (x >= width) return; - - float maxV = -FLT_MAX; - uint r; - for (r = 0; r < reducedDim; ++r) - { - float v = X.FastGet(y * width * reducedDim + r * width + x); - if (v > maxV) - maxV = v; - } - - float acc = 0.0f; - for (r = 0; r < reducedDim; ++r) - { - float v = X.FastGet(y * width * reducedDim + r * width + x); - acc += exp(v - maxV); - } - - for (r = 0; r < reducedDim; ++r) - { - float v = X.FastGet(y * width * reducedDim + r * width + x); - v = exp(v - maxV) / acc; - O.FastSet(y * width * reducedDim + r * width + x, v); - } -} - -[numthreads(16, 4, 1)] -void KERNEL_FUNC(LogSoftmax)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_ARGS2_8D(X, O); - - uint y = dispatchThreadID.x; - uint x = dispatchThreadID.y; - - uint height = (uint)_Stride[0]; - uint reducedDim = (uint)_Stride[1]; - uint width = (uint)_Stride[2]; - - if (y >= height) return; - if (x >= width) return; - - float maxV = -FLT_MAX; - uint r; - for (r = 0; r < reducedDim; ++r) - { - float v = X.FastGet(y * width * reducedDim + r * width + x); - if (v > maxV) - maxV = v; - } - - float acc = 0.0f; - for (r = 0; r < reducedDim; ++r) - { - float v = X.FastGet(y * width * reducedDim + r * width + x); - acc += exp(v - maxV); - } - - for (r = 0; r < reducedDim; ++r) - { - float v = X.FastGet(y * width * reducedDim + r * width + x); - v = (v - maxV) - log(acc); - O.FastSet(y * width * reducedDim + r * width + x, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Upsample2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - // NOTE: dispatched over X (not O) - //DISPATCH ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= X.channels) return; - if (x >= X.width) return; - if (y >= X.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, y, x, c); - - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint oy = y * _Pool.y + dy; - uint ox = x * _Pool.x + dx; - O.Set(n, oy, ox, c, v); - } - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Upsample3D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - // NOTE: dispatched over X (not O) - //DISPATCH ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= X.channels) return; - if (x >= X.width) return; - if (y >= X.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - for (uint d = 0; d < X.depth; ++d) - { - float v = X.Get5D(n, d, y, x, c); - - for (uint dd = 0; dd < _Pool.z; ++dd) - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint od = d * _Pool.z + dd; - uint oy = y * _Pool.y + dy; - uint ox = x * _Pool.x + dx; - O.Set5D(n, od, oy, ox, c, v); - } - } - } -} - -float BilinearInterpolation(float fracSrcPosX, float fracSrcPosY, float p00, float p01, float p10, float p11) -{ - float v = - p00 * (1.0f-fracSrcPosX) * (1.0f-fracSrcPosY) + - p01 * (1.0f-fracSrcPosX) * fracSrcPosY + - p10 * fracSrcPosX * (1.0f-fracSrcPosY) + - p11 * fracSrcPosX * fracSrcPosY; - return v; -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(UpsampleBilinear2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - float2 dstPos = float2(x, y); - float2 srcPos = (dstPos + 0.5) / _Pool.xy - 0.5; - - for (uint n = 0; n < O.batch; ++n) - { - float p00 = X.ClampGet(n, floor(srcPos) + float2(0, 0), c); - float p01 = X.ClampGet(n, floor(srcPos) + float2(0, 1), c); - float p10 = X.ClampGet(n, floor(srcPos) + float2(1, 0), c); - float p11 = X.ClampGet(n, floor(srcPos) + float2(1, 1), c); - float v = BilinearInterpolation(frac(srcPos.x), frac(srcPos.y), p00, p01, p10, p11); - - O.Set(n, y, x, c, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(UpsampleTrilinear3D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - float2 dstPosXY = float2(x, y); - float2 srcPosXY = (dstPosXY + 0.5f) / _Pool.xy - 0.5f; - - for (uint n = 0; n < O.batch; ++n) - { - for (uint d = 0; d < O.depth; ++d) - { - float srcPosD = (d + 0.5f) / _Pool.z - 0.5f; - float3 srcPos = float3(srcPosXY.x, srcPosXY.y, srcPosD); - - float p000 = X.ClampGet5D(n, floor(srcPos) + float3(0, 0, 0), c); - float p100 = X.ClampGet5D(n, floor(srcPos) + float3(0, 0, 1), c); - float p010 = X.ClampGet5D(n, floor(srcPos) + float3(0, 1, 0), c); - float p110 = X.ClampGet5D(n, floor(srcPos) + float3(0, 1, 1), c); - float p001 = X.ClampGet5D(n, floor(srcPos) + float3(1, 0, 0), c); - float p101 = X.ClampGet5D(n, floor(srcPos) + float3(1, 0, 1), c); - float p011 = X.ClampGet5D(n, floor(srcPos) + float3(1, 1, 0), c); - float p111 = X.ClampGet5D(n, floor(srcPos) + float3(1, 1, 1), c); - float e = BilinearInterpolation(frac(srcPos.x), frac(srcPos.y), p000, p100, p010, p110); - float f = BilinearInterpolation(frac(srcPos.x), frac(srcPos.y), p001, p101, p011, p111); - float v = e * ( 1 - frac(srcPos.z)) + f * frac(srcPos.z); - O.Set5D(n, d, y, x, c, v); - } - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Resample2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - float2 dstSize = float2(O.width, O.height); - float2 srcSize = float2(X.width, X.height); - float2 dstPos = float2(x, y); - float2 srcPos = floor(dstPos / (dstSize / srcSize)); - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.ClampGet(n, srcPos, c); - O.Set(n, y, x, c, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(ResampleBilinear2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - float2 dstSize = float2(O.width, O.height); - float2 srcSize = float2(X.width, X.height); - float2 dstPos = float2(x, y); - float2 srcPos = (dstPos + 0.5) * (srcSize / dstSize) - 0.5; - - for (uint n = 0; n < O.batch; ++n) - { - float p00 = X.ClampGet(n, floor(srcPos) + float2(0, 0), c); - float p01 = X.ClampGet(n, floor(srcPos) + float2(0, 1), c); - float p10 = X.ClampGet(n, floor(srcPos) + float2(1, 0), c); - float p11 = X.ClampGet(n, floor(srcPos) + float2(1, 1), c); - - float v = - p00 * (1-frac(srcPos.x)) * (1-frac(srcPos.y)) + - p01 * (1-frac(srcPos.x)) * frac(srcPos.y) + - p10 * frac(srcPos.x) * (1-frac(srcPos.y)) + - p11 * frac(srcPos.x) * frac(srcPos.y); - - O.Set(n, y, x, c, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(DepthToSpace_CRD)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height, O.channels); - TENSOR_ARGS2(X, O) - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint bsX = _Pool.x; - uint bsY = _Pool.y; - - for (uint b = 0; b < O.batch; ++b) - { - uint iy = y / bsY; - uint by = y % bsY; - uint ix = x / bsX; - uint bx = x % bsX; - - float v = X.Get(b, iy, ix, (c * bsX * bsY) + (by * bsX) + bx); - O.Set(b, y, x, c, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(DepthToSpace_DCR)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height, O.channels); - TENSOR_ARGS2(X, O) - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint bsX = _Pool.x; - uint bsY = _Pool.y; - - for (uint b = 0; b < O.batch; ++b) - { - uint iy = y / bsY; - uint by = y % bsY; - uint ix = x / bsX; - uint bx = x % bsX; - - float v = X.Get(b, iy, ix, (by * bsX * O.channels) + (bx * O.channels) + c); - O.Set(b, y, x, c, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(SpaceToDepth)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height, O.channels); - TENSOR_ARGS2(X, O) - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint bsX = _Pool.x; - uint bsY = _Pool.y; - - int ic = c % X.channels; - int bx = c / X.channels % bsX; - int by = c / X.channels / bsX; - int ix = x * bsX + bx; - int iy = y * bsY + by; - - for (uint b = 0; b < O.batch; ++b) - { - float v = X.Get(b, iy, ix, ic); - O.Set(b, y, x, c, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(MaxPool2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float maxV = -FLT_MAX; - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint2 pos = uint2(x, y) * _Stride.xy + uint2(dx, dy); - float v = X.SafeGet(n, pos, c, _Pad.xy, -FLT_MAX ); - maxV = max(v, maxV); - } - - O.Set(n, y, x, c, maxV); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(AvgPool2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint2 leftCorner = _Pad.xy; - uint2 rightCorner = uint2(X.width, X.height) + _Pad.xy; - for (uint n = 0; n < X.batch; ++n) - { - float acc = 0; - float counter = 0; - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint oy = y * _Stride.y + dy; - uint ox = x * _Stride.x + dx; - - bool mask = (oy >= leftCorner.y) && (ox >= leftCorner.x) && (oy < rightCorner.y) && (ox < rightCorner.x); - acc += (mask) ? X.Get(n, min(oy - _Pad.y, X.height - 1), min(ox - _Pad.x, X.width - 1), c) : 0; - counter += (mask) ? 1 : 0; - } - - acc /= counter; - O.Set(n, y, x, c, acc); - } -} - -[numthreads(32,1,1)] -void KERNEL_FUNC(GlobalMaxPool2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - if (c >= O.channels) return; - //ASSERT(X.batch == O.batch) - - for (uint n = 0; n < X.batch; ++n) - { - float maxV = -FLT_MAX; - for (uint y = 0; y < X.height; ++y) - for (uint x = 0; x < X.width; ++x) - { - float v = X.Get(n, y, x, c); - maxV = max(v, maxV); - } - - O.Set(n, 0, 0, c, maxV); - } -} - -[numthreads(32,1,1)] -void KERNEL_FUNC(GlobalAvgPool2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - if (c >= O.channels) return; - //ASSERT(X.batch == O.batch) - - for (uint n = 0; n < X.batch; ++n) - { - float v = 0; - for (uint y = 0; y < X.height; ++y) - for (uint x = 0; x < X.width; ++x) - v += X.Get(n, y, x, c); - - v /= (X.height * X.width); - O.Set(n, 0, 0, c, v); - } -} - - -[numthreads(32, 1, 1)] -void KERNEL_FUNC(GlobalAvgVariancePool2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - if (c >= O.channels) return; - //ASSERT(X.batch == O.batch) - - for (uint n = 0; n < X.batch; ++n) - { - float mean = 0; - float mean2 = 0; - for (uint y = 0; y < X.height; ++y) - { - for (uint x = 0; x < X.width; ++x) - { - float v = X.Get(n, y, x, c); - mean += v; - mean2 += v * v; - } - } - - mean /= (X.height * X.width); - mean2 /= (X.height * X.width); - - O.Set(n, 0, 0, c, mean); - O.Set(n, 1, 0, c, mean2 - mean * mean); - } -} - -[numthreads(32,1,1)] -void KERNEL_FUNC(InstanceNorm)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, 1, 1); - TENSOR_ARGS4(X, W, B, O); - - uint c = dispatchThreadID.x; - if (c >= O.channels) return; - //ASSERT(X.shape == O.shape) - - float gamma = W.Get(0, 0, 0, c); - float beta = B.Get(0, 0, 0, c); - - // There are 2 sources of numerical errors when computing Variance over large number of elements: - // 1) summing N floating point numbers in sequence has a worst-case error that grows proportional to N - // 2) because SumSq and (Sum×Sum)/N can be very similar numbers, cancellation can lead to the precision of the result - // to be much less than the inherent precision of the floating-point arithmetic used to perform the computation. - // This is particularly bad if the standard deviation is small relative to the mean! - // Below algorithm is improved by adopting the method of the assumed mean and Neumaier compensated summation - // see: https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance - // see: https://en.wikipedia.org/wiki/Kahan_summation_algorithm - - for (uint n = 0; n < O.batch; ++n) - { - uint i; - uint count = O.height * O.width; - - // estimate mean, result is approximate due to litimited floating point precision - // however it is good enough for the following calculation of variance over the shifted data - float approximateMean = X.Get(n, 0, c); - { - float sum = 0; - for (i = 0; i < count; ++i) - { - float delta = X.Get(n, i, c) - approximateMean; - sum += delta; - } - approximateMean += sum / count; - } - - // compute mean & variance - // to improve precision, variance over shifted data is cacluated: Var(X - K) = Var(X) - // estimated mean is used instead of 1st element to make reference impl more stable in respect to the order of the elements - // see: https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance - // K <- approximateMean - // Ex <- sum - // Ex2 <- sumSq - - float sum = 0, sumSq = 0; - float correction = 0, correctionSq = 0; - for (i = 0; i < count; ++i) - { - float delta = X.Get(n, i, c) - approximateMean; - sum = neumaierAdd(sum, delta, correction); - sumSq = neumaierAdd(sumSq, delta * delta, correctionSq); - } - sum += correction; - sumSq += correctionSq; - - float mean = approximateMean + sum / count; - float var = (sumSq - (sum * sum) / count) / count; - - // apply normalization - for (uint j = 0; j < count; ++j) - { - float v = X.Get(n, j, c); - v = gamma * (v - mean) / sqrt(var + _Epsilon) + beta; - O.SetWithActivation(n, j, c, v); - } - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(LRN)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - float bias = _Epsilon; - float sizef = (float)_Axis; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float regionCenter = (sizef - 1.0f) / 2.0f; - uint regionStart = max(0, c - (uint)floor(regionCenter)); - uint regionEnd = min(X.channels, c + (uint)ceil(regionCenter)+1); - float sumOfSquared = 0.0f; - for (uint ci = regionStart; ci < regionEnd; ++ci) - { - float regionValue = X.Get8D(s,r,n,t,d,h,w,ci); - sumOfSquared += regionValue * regionValue; - } - - float v = X.Get8D(s,r,n,t,d,h,w,c) / signed_pow(bias + _Alpha * sumOfSquared / sizef, _Beta); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -// https://github.com/andravin/wincnn -// https://arxiv.org/pdf/1509.09308.pdf -// Winograd: 4x4 image, 3x3 kernel, 2x2 output -static const float4x4 Winograd_BT = float4x4(float4(1, 0, -1, 0), float4(0, 1, 1, 0), float4(0, -1, 1, 0), float4(0, -1, 0, 1)); -static const float4x4 Winograd_B = transpose(Winograd_BT); - -static const float4x3 Winograd_G = float4x3(float3(1, 0, 0), float3(0.5, 0.5, 0.5), float3(0.5, -0.5, 0.5), float3(0, 0, 1)); -static const float3x4 Winograd_GT = transpose(Winograd_G); - -static const float2x4 Winograd_AT = float2x4(float4(1, 1, 1, 0), float4(0, 1, -1, 1)); -static const float4x2 Winograd_A = transpose(Winograd_AT); - - -[numthreads(64, 1, 1)] -void KERNEL_FUNC(Conv2DWinograd_2x2_3x3)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_ARGS4(X, K, B, O); - - uint k = dispatchThreadID.x; - if (k >= K.channels) return; - - uint2 index = 2 * dispatchThreadID.yz; - - uint2 pad = uint2(_Pad[0], _Pad[1]); - uint2 XDim = uint2(X.width, X.height); - - for (uint n = 0; n < O.batch; ++n) - { - float2x2 acc = B.FastGet(k); - - for (uint c = 0; c < X.channels; ++c) - { - // 16 loads per thread - float4x4 d; - d[0][0] = X.SafeGet(n, index.xy + uint2(0, 0) - pad, c); - d[0][1] = X.SafeGet(n, index.xy + uint2(1, 0) - pad, c); - d[0][2] = X.SafeGet(n, index.xy + uint2(2, 0) - pad, c); - d[0][3] = X.SafeGet(n, index.xy + uint2(3, 0) - pad, c); - d[1][0] = X.SafeGet(n, index.xy + uint2(0, 1) - pad, c); - d[1][1] = X.SafeGet(n, index.xy + uint2(1, 1) - pad, c); - d[1][2] = X.SafeGet(n, index.xy + uint2(2, 1) - pad, c); - d[1][3] = X.SafeGet(n, index.xy + uint2(3, 1) - pad, c); - d[2][0] = X.SafeGet(n, index.xy + uint2(0, 2) - pad, c); - d[2][1] = X.SafeGet(n, index.xy + uint2(1, 2) - pad, c); - d[2][2] = X.SafeGet(n, index.xy + uint2(2, 2) - pad, c); - d[2][3] = X.SafeGet(n, index.xy + uint2(3, 2) - pad, c); - d[3][0] = X.SafeGet(n, index.xy + uint2(0, 3) - pad, c); - d[3][1] = X.SafeGet(n, index.xy + uint2(1, 3) - pad, c); - d[3][2] = X.SafeGet(n, index.xy + uint2(2, 3) - pad, c); - d[3][3] = X.SafeGet(n, index.xy + uint2(3, 3) - pad, c); - - float3x3 g; - g[0][0] = K.Get(0, 0, c, k); - g[0][1] = K.Get(0, 1, c, k); - g[0][2] = K.Get(0, 2, c, k); - g[1][0] = K.Get(1, 0, c, k); - g[1][1] = K.Get(1, 1, c, k); - g[1][2] = K.Get(1, 2, c, k); - g[2][0] = K.Get(2, 0, c, k); - g[2][1] = K.Get(2, 1, c, k); - g[2][2] = K.Get(2, 2, c, k); - - float4x4 v = mul(Winograd_G, mul(g, Winograd_GT)); - float4x4 u = mul(Winograd_BT, mul(d, Winograd_B)); - float2x2 y = mul(Winograd_AT, mul(v*u, Winograd_A)); - - acc += y; - } - - // 4 writes per thread - if (index.y < O.height && index.x < O.width) - O.SetWithActivation(n, index.y + 0, index.x + 0, k, acc[0][0]); - if (index.y + 1 < O.height && index.x < O.width) - O.SetWithActivation(n, index.y + 1, index.x + 0, k, acc[1][0]); - if (index.y < O.height && index.x + 1 < O.width) - O.SetWithActivation(n, index.y + 0, index.x + 1, k, acc[0][1]); - if (index.y + 1 < O.height && index.x + 1 < O.width) - O.SetWithActivation(n, index.y + 1, index.x + 1, k, acc[1][1]); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Conv3D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_ARGS4_8D(X, K, B, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - for (uint d = 0; d < O.depth; ++d) - { - float acc = B.FastGet(k); - for (uint dd = 0; dd < K.GetKernelSpatialDepth(); ++dd) - { - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - { - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint3 pos3d = uint3(x, y, d) * _Stride.xyz + uint3(dx, dy, dd); - for (uint c = 0; c < X.channels; ++c) - { - float v = X.SafeGet5D(n, pos3d, c, _Pad.xyz); - acc += v * K.GetKernel5D( dd, dy, dx, c, k); - } - } - } - } - - O.Set5DWithActivation( n, d, y, x, k, acc); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Conv2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_ARGS4(X, K, B, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float acc = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - { - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos = uint2(x, y) * _Stride.xy + uint2(dx, dy); - for (uint c = 0; c < X.channels; ++c) - { - float v = X.SafeGet(n, pos, c, _Pad.xy); - acc += v * K.Get(dy, dx, c, k); - } - } - } - - O.SetWithActivation(n, y, x, k, acc); - } -} - -NUMTHREADS((16,4,4), (8,4,4), (4,4,4)) -void KERNEL_FUNC(DepthwiseConv2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_ARGS4(X, K, B, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float acc = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos = uint2(x, y) * _Stride.xy + uint2(dx, dy); - float v = X.SafeGet(n, pos, k, _Pad.xy); - acc += v * K.Get(dy, dx, 0, k); - } - - O.SetWithActivation(n, y, x, k, acc); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Unstride2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - int xx = (int)x - (int)_Pad.x; - int yy = (int)y - (int)_Pad.y; - - int my = yy % _Stride.y; - int mx = xx % _Stride.x; - - int oy = yy / _Stride.y; - int ox = xx / _Stride.x; - - bool mask = ox >= 0 && oy >= 0 && ox < (int)X.width && oy < (int)X.height && - my == 0 && mx == 0; - - float v = mask ? X.Get(n, (uint)oy, (uint)ox, c) : 0; - O.Set(n, y, x, c, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Conv2DTrans)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_ARGS4(X, K, B, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint strideH = 1; - uint strideW = 1; - - for (uint n = 0; n < O.batch; ++n) - { - float acc = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); dy += strideH) - { - for (uint dx = 0; dx < K.GetKernelWidth(); dx += strideW) - { - for (uint c = 0; c < X.channels; ++c) - { - uint readX = (x + dx - _Pad.x) / _Stride.x; - uint readY = (y + dy - _Pad.y) / _Stride.y; - - // early out if read input index fall upon leftmost outer zero padding - if ((x + dx) < _Pad.x) continue; - if ((y + dy) < _Pad.y) continue; - - // early out if read input index fall upon rightmost outer zero padding - if (readX >= X.width) continue; - if (readY >= X.height) continue; - - if ((x + dx - _Pad.x) % _Stride.x != 0) continue; - if ((y + dy - _Pad.y) % _Stride.y != 0) continue; - - acc += X.Get(n, readY, readX, c) * K.Get(K.GetKernelHeight() - 1 - dy, K.GetKernelWidth() - 1 - dx, c, k); - } - } - } - - O.SetWithActivation(n, y, x, k, acc); - } -} - - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Border2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - // NOTE: negative "pad" variable crop X tensor - int croppedWidth = _Pool.x; - int croppedHeight = _Pool.y; - int croppedChannels = _Pool.z; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - int readC = c - _Pad.z; - - for (uint n = 0; n < O.batch; ++n) - { - float v; - if (readX < 0 || readX >= croppedWidth || - readY < 0 || readY >= croppedHeight || - readC < 0 || readC >= croppedChannels) - { - v = _Beta; - } - else - { - v = X.Get(n, readY, readX, readC); - } - O.Set(n, y, x, c, v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Border3D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - // NOTE: negative "pad" variable crop X tensor - int croppedWidth = _Pool.x; - int croppedHeight = _Pool.y; - int croppedDepth = _Pool.z; - int croppedChannels = _Pool.w; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - int readC = c - _Pad.w; - - for (uint n = 0; n < O.batch; ++n) - { - for (uint d = 0; d < O.depth; ++d) - { - int readD = d - _Pad.z; - float v; - if (readX < 0 || readX >= croppedWidth || - readY < 0 || readY >= croppedHeight || - readD < 0 || readD >= croppedDepth || - readC < 0 || readC >= croppedChannels) - { - v = _Beta; - } - else - { - v = X.Get5D(n, readD, readY, readX, readC); - } - O.Set5D(n, d, y, x, c, v); - } - } -} - -void ClampHWCToTensorShape(uint3 Xshape, inout int height, inout int width, inout int channel) -{ - width = max(width, 0); - height = max(height, 0); - channel = max(channel, 0); - width = min(width, (int)Xshape.x - 1); - height = min(height, (int)Xshape.y - 1); - channel = min(channel, (int)Xshape.z - 1); -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Pad2DEdge)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - int readC = c - _Pad.z; - uint3 Xshape = uint3(X.width, X.height, X.channels); - - //clamp read indices to source - ClampHWCToTensorShape(Xshape, readY, readX, readC); - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, readY, readX, readC); - O.Set(n, y, x, c, v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Pad2DReflect)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - int readC = c - _Pad.z; - uint3 Xshape = uint3(X.width, X.height, X.channels); - - int lastXIndex = Xshape.x - 1; - int lastYIndex = Xshape.y - 1; - int lastCIndex = Xshape.z - 1; - - //x reflect indexing - if (readX < 0) - readX = -readX; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex); - - //y reflect indexing - if (readY < 0) - readY = -readY; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex); - - //c reflect indexing - if (readC < 0) - readC = -readC; - else if (readC > lastCIndex) - readC = lastCIndex - (readC - lastCIndex); - - //clamp read indices to source - ClampHWCToTensorShape(Xshape, readY, readX, readC); - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, readY, readX, readC); - O.Set(n, y, x, c, v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Pad2DSymmetric)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - int readC = c - _Pad.z; - uint3 Xshape = uint3(X.width, X.height, X.channels); - - int lastXIndex = Xshape.x - 1; - int lastYIndex = Xshape.y - 1; - int lastCIndex = Xshape.z - 1; - - //x symmetric indexing - if (readX < 0) - readX = -readX - 1; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex) + 1; - - //y symmetric indexing - if (readY < 0) - readY = -readY - 1; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex) + 1; - - //c symmetric indexing - if (readC < 0) - readC = -readC - 1; - else if (readC > lastCIndex) - readC = lastCIndex - (readC - lastCIndex) + 1; - - //clamp read indices to source - ClampHWCToTensorShape(Xshape, readY, readX, readC); - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, readY, readX, readC); - O.Set(n, y, x, c, v); - } -} - -int4 _Stride4D; -int4 _Stride8D; - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(StridedSlice)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - uint4 _Pad8D = _Pool; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = X.Get8D( _Pad8D.x + s * _Stride8D.x, - _Pad8D.y + r * _Stride8D.y, - _Pad.x + n * _Stride4D.x, - _Pad8D.z + t * _Stride8D.z, - _Pad8D.w + d * _Stride8D.w, - _Pad.y + h * _Stride4D.y, - _Pad.z + w * _Stride4D.z, - _Pad.w + c * _Stride4D.w); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Gather)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS3_8D(X, K, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = 0.0; - if (_Axis == 0) - v = X.Get8D((uint)K.FastGet(s),r,n,t,d,h,w,c); - else if (_Axis == 1) - v = X.Get8D(s,(uint)K.FastGet(r),n,t,d,h,w,c); - else if (_Axis == 2) - v = X.Get8D(s,r,(uint)K.FastGet(n),t,d,h,w,c); - else if (_Axis == 3) - v = X.Get8D(s,r,n,(uint)K.FastGet(t),d,h,w,c); - else if (_Axis == 4) - v = X.Get8D(s,r,n,t,(uint)K.FastGet(d),h,w,c); - else if (_Axis == 5) - v = X.Get8D(s,r,n,t,d,(uint)K.FastGet(h),w,c); - else if (_Axis == 6) - v = X.Get8D(s,r,n,t,d,h,(uint)K.FastGet(w),c); - else if (_Axis == 7) - v = X.Get8D(s,r,n,t,d,h,w,(uint)K.FastGet(c)); - - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(ScatterND)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS4(X, K, W, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, h, w, c); - O.Set(n, h, w, c, v); - - for (uint idx = 0; idx < K.GetFlatWidth(); idx++) - { - uint indexRemap = (uint)(K.FastGet(idx)); - - if (c != indexRemap) - continue; - - float vw = W.SafeGet(n, h, w, idx); - - #if CHANNELS_FIRST - uint indexWrite = O.IndexCHW(n, h, w, indexRemap); - #else - uint indexWrite = O.IndexHWC(n, h, w, indexRemap); - #endif - - if(_Axis == 0) - O.data[indexWrite] = vw; - else if (_Axis == 1) - O.data[indexWrite] += vw; - else if (_Axis == 2) - O.data[indexWrite] *= vw; - } - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Transpose2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_ARGS3(X, K, O); - - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - - if (x >= O.GetFlatWidth()) return; - if (y >= O.GetFlatHeight()) return; - - uint readX = y; - uint readY = x; - - float v = X.Get(readY, readX); // transposed - O.Set(y, x, v); -} - -[numthreads(4, 4, 4)] -void Transpose8D(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH_ARGS(X.channels, X.width, X.height); in ChannelLast aka SRNTDHWC - //DISPATCH_ARGS(X.width, X.height, X.depth); in ChannelFirst aka SRNCTDHW - TENSOR_ARGS2(X, O); - - uint d0_size = _Pad.x; - uint d1_size = _Pad.y; - uint d2_size = _Pad.z; - uint d3_size = _Pad.w; - uint d4_size = _Pool.x; - uint d5_size = _Pool.y; - uint d6_size = _Pool.z; - uint d7_size = _Pool.w; - - uint outputStrides[8]; - outputStrides[0] = _Stride.x; - outputStrides[1] = _Stride.y; - outputStrides[2] = _Stride.z; - outputStrides[3] = _Stride.w; - outputStrides[4] = _ChannelWriteMask.x; - outputStrides[5] = _ChannelWriteMask.y; - outputStrides[6] = _ChannelWriteMask.z; - outputStrides[7] = _ChannelWriteMask.w; - - uint d7 = dispatchThreadID.x; - uint d6 = dispatchThreadID.y; - uint d5 = dispatchThreadID.z; - if (d7 >= d7_size) return; - if (d6 >= d6_size) return; - if (d5 >= d5_size) return; - - uint d5_7offset = d5 * d6_size * d7_size + d6 * d7_size + d7; - uint d0_4stride = d5_size * d6_size * d7_size; - uint d0_4offset = 0; - - for (uint d0 = 0; d0 < d0_size; ++d0) - for (uint d1 = 0; d1 < d1_size; ++d1) - for (uint d2 = 0; d2 < d2_size; ++d2) - for (uint d3 = 0; d3 < d3_size; ++d3) - for (uint d4 = 0; d4 < d4_size; ++d4) - { - float value = X.FastGet(d0_4offset + d5_7offset); - O.FastSet(d0 * outputStrides[0] + - d1 * outputStrides[1] + - d2 * outputStrides[2] + - d3 * outputStrides[3] + - d4 * outputStrides[4] + - d5 * outputStrides[5] + - d6 * outputStrides[6] + - d7 * outputStrides[7], value); - - d0_4offset += d0_4stride; - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Transpose)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH_ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= X.channels) return; - if (x >= X.width) return; - if (y >= X.height) return; - - for (uint b = 0; b < X.batch; ++b) - { - float v = X.Get(b, y, x, c); - uint4 index = uint4(b, y, x, c); - O.Set(index[_Pool.x], index[_Pool.y], index[_Pool.z], index[_Pool.w], v); - } -} - -[numthreads(4, 4, 4)] -void TransposeToChannelFirst(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH_ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = X.Get8D(s,r,n,t,d,h,w,c); - uint index = X.IndexSRNCTDHW(s,r,n,t,d,h,w,c); - O.FastSet(index, v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Expand)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - // scale is either 1 or 0 in case of expansion - uint sS = X.sequenceLength / O.sequenceLength; - uint rS = X.numberOfDirections / O.numberOfDirections; - uint nS = X.batch / O.batch; - uint tS = X.extraDimension / O.extraDimension; - uint dS = X.depth / O.depth; - uint hS = X.height / O.height; - uint wS = X.width / O.width; - uint cS = X.channels / O.channels; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - // sample either from dim or index 0 in case of expansion - float v = X.Get8D(s*sS,r*rS,n*nS,t*tS,d*dS,h*hS,w*wS,c*cS); - O.Set8D(s,r,n,t,d,h,w,c,v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(ConstantOfShape)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARG_8D_RW(O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = _Alpha; - uint index = O.IndexSRNCTDHW(s, r, n, t, d, h, w, c); - O.FastSet(index, v); - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(OneHot)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(X.flatHeight, depth, X.flatWidth); - TENSOR_ARGS2(X, O); - - uint depth = _Axis; - uint inputRank = _Pad.x; - - uint k = dispatchThreadID.x; uint j = dispatchThreadID.y; uint i = dispatchThreadID.z; - if (k >= X.width) return; if (j >= depth) return; if (i >= X.channels) return; - - for (uint n = 0; n < O.batch; ++n) - { - if (inputRank == 1) - { - uint index = (uint)(X.FastGet(n)); - float v = (j == index) ? _Alpha : _Beta; - O.Set(n, j, v); - } - else if (inputRank == 2) - { - uint index = (uint)(X.Get(n, i)); - float v = (j == index) ? _Alpha : _Beta; - O.Set(n, 0, j, i, v); - } - else - { - uint index = (uint)(X.Get(n, 0, k, i)); - float v = (j == index) ? _Alpha : _Beta; - O.Set(n, k, j, i, v); - } - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(RoiAlign)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(outputHeight, outputWidth, X.channels); - TENSOR_ARGS4(X, K, B, O); - - float spatialScale = _Alpha; - uint samplingRatio = _Axis; - - uint i = dispatchThreadID.x; uint j = dispatchThreadID.y; uint c = dispatchThreadID.z; - if (i >= O.height) return; if (j >= O.width) return; if (c >= X.channels) return; - - bool aligned = false; - float offset = aligned ? 0.5f : 0.0f; - - for (int n = 0; n < (int)K.batch; n++) - { - float j_begin = K.Get(n, 0) * spatialScale - offset; - float i_begin = K.Get(n, 1) * spatialScale - offset; - float j_end = K.Get(n, 2) * spatialScale - offset; - float i_end = K.Get(n, 3) * spatialScale - offset; - - float roi_h = i_end - i_begin; - float roi_w = j_end - j_begin; - float bin_h = roi_h / ((float)O.height); - float bin_w = roi_w / ((float)O.width); - - int batchIdx = (int)B.FastGet(n); - - - float start_h = i_begin + i * bin_h; - float grid_h = samplingRatio > 0 ? samplingRatio : ceil(bin_h); - float start_w = j_begin + j * bin_w; - float grid_w = samplingRatio > 0 ? samplingRatio : ceil(bin_w); - - float v = 0.0f; - for (int iy = 0; iy < (int)grid_h; iy++) - for (int ix = 0; ix < (int)grid_w; ix++) - { - float y = start_h + (iy + 0.5f) * bin_h / grid_h; - float x = start_w + (ix + 0.5f) * bin_w / grid_w; - - if (x >= (int)X.width || x < 0 || y >= (int)X.height || y < 0) - continue; - - y = clamp(y, 0, X.height - 1); - x = clamp(x, 0, X.width - 1); - - int y_low = (int)floor(y); - int x_low = (int)floor(x); - int y_high = y_low + 1; - int x_high = x_low + 1; - - float wy_h = y - y_low; - float wx_h = x - x_low; - float wy_l = 1.0f - wy_h; - float wx_l = 1.0f - wx_h; - - if (y_low >= 0 && y_low < (int)X.height && x_low >= 0 && x_low < (int)X.width) - v += wx_l * wy_l * X.Get(batchIdx, y_low, x_low, c); - if (y_low >= 0 && y_low < (int)X.height && x_high >= 0 && x_high < (int)X.width) - v += wx_h * wy_l * X.Get(batchIdx, y_low, x_high, c); - if (y_high >= 0 && y_high < (int)X.height && x_low >= 0 && x_low < (int)X.width) - v += wx_l * wy_h * X.Get(batchIdx, y_high, x_low, c); - if (y_high >= 0 && y_high < (int)X.height && x_high >= 0 && x_high < (int)X.width) - v += wx_h * wy_h * X.Get(batchIdx, y_high, x_high, c); - } - - v /= grid_h * grid_w; - - O.Set(n, i, j, c, v); - } -} - diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/BarracudaReferenceImpl.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/BarracudaReferenceImpl.compute.meta deleted file mode 100644 index e814797..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/BarracudaReferenceImpl.compute.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: b4b1b304aae6c404cb0cdab46b8fa084 -timeCreated: 1495527718 -licenseType: Pro -ComputeShaderImporter: - currentAPIMask: 196608 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast.cginc deleted file mode 100644 index 356e4ea..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast.cginc +++ /dev/null @@ -1,410 +0,0 @@ -#include "Tensor.cginc" - -float _Alpha; -int _IsFirstDispatch; -uint4 _XStrides; -uint4 _SStrides; -uint4 _BStrides; - -TENSOR_DECL(X) -TENSOR_DECL(S) -TENSOR_DECL(B) -TENSOR_DECL_RW(O) - -void DispatchThreadIdToTensorIndices(uint3 dispatchThreadID, out uint c, out uint x, out uint y) -{ -#if CHANNELS_FIRST - //DISPATCH ARGS(O.width, O.height, O.channels); - x = dispatchThreadID.x; - y = dispatchThreadID.y; - c = dispatchThreadID.z; -#else - //DISPATCH ARGS(O.channels, O.width, O.height); - c = dispatchThreadID.x; - x = dispatchThreadID.y; - y = dispatchThreadID.z; -#endif -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastAdd)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = - X.FastGet(dot(uint4(n, y, x, c), _XStrides)) + - B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastSub)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = - X.FastGet(dot(uint4(n, y, x, c), _XStrides)) - - B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastMul)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = - X.FastGet(dot(uint4(n, y, x, c), _XStrides)) * - B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastDiv)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = - X.FastGet(dot(uint4(n, y, x, c), _XStrides)) / - B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - O.Set(n, y, x, c, v); - } -} - -float signed_pow(float f, float e) -{ - // handle negative f - float v = pow(abs(f), e); - float s = (e % 2 == 1) ? - sign(f): // exponent is odd => sign(f) * pow(abs(f), e) - 1; // exponent is even => pow(abs(f), e) - return v * s; -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastPow)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = signed_pow( - X.FastGet(dot(uint4(n, y, x, c), _XStrides)), - B.FastGet(dot(uint4(n, y, x, c), _BStrides))); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastMin)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = min( - X.FastGet(dot(uint4(n, y, x, c), _XStrides)), - B.FastGet(dot(uint4(n, y, x, c), _BStrides))); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastMax)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = max( - X.FastGet(dot(uint4(n, y, x, c), _XStrides)), - B.FastGet(dot(uint4(n, y, x, c), _BStrides))); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(BroadcastMean)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = X.FastGet(dot(uint4(n, y, x, c), _XStrides)); - a *= _IsFirstDispatch ? _Alpha : 1.0f; - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)) * _Alpha; - float v = a + b; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastGreater)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = X.FastGet(dot(uint4(n, y, x, c), _XStrides)); - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - float v = (a > b) ? 1.0f : 0.0f; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastGreaterEqual)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = X.FastGet(dot(uint4(n, y, x, c), _XStrides)); - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - float v = (a >= b) ? 1.0f : 0.0f; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastLess)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = X.FastGet(dot(uint4(n, y, x, c), _XStrides)); - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - float v = (a < b) ? 1.0f : 0.0f; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastLessEqual)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = X.FastGet(dot(uint4(n, y, x, c), _XStrides)); - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - float v = (a <= b) ? 1.0f : 0.0f; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastEqual)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = X.FastGet(dot(uint4(n, y, x, c), _XStrides)); - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - float v = (a == b) ? 1.0f : 0.0f; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastLogicalOr)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = (X.FastGet(dot(uint4(n, y, x, c), _XStrides)) == 0.0f) ? 0.0f : 1.0f; - float b = (B.FastGet(dot(uint4(n, y, x, c), _BStrides)) == 0.0f) ? 0.0f : 1.0f; - float v = a * (1 - b) + b; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastLogicalAnd)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = X.FastGet(dot(uint4(n, y, x, c), _XStrides)); - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - float v = a * b != 0.0 ? 1.0f : 0.0f; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(BroadcastLogicalXor)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_TWOINPUTS(X, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - float a = X.FastGet(dot(uint4(n, y, x, c), _XStrides)) != 0.0f ? 1.0f : 0.0f; - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)) != 0.0f ? 1.0f : 0.0f; - float v = a * (1 - 2 * b) + b; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(BroadcastWhere)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_THREEINPUTS(X, S, B, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) - return; - if (x >= O.width) - return; - if (y >= O.height) - return; - - for (uint n = 0; n < O.batch; ++n) - { - bool cond = (X.FastGet(dot(uint4(n, y, x, c), _XStrides)) != 0.0f); - float a = S.FastGet(dot(uint4(n, y, x, c), _SStrides)); - float b = B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - float v = cond ? a : b; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(BroadcastDivExpSub)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_THREEINPUTS(X, B, S, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = - X.FastGet(dot(uint4(n, y, x, c), _XStrides)) - - B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - v = exp(v) / S.FastGet(dot(uint4(n, y, x, c), _SStrides)); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(LogSoftmaxEnd)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_THREEINPUTS(X, B, S, O); - uint c, x, y; - DispatchThreadIdToTensorIndices(dispatchThreadID, c, x, y); - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = - X.FastGet(dot(uint4(n, y, x, c), _XStrides)) - - B.FastGet(dot(uint4(n, y, x, c), _BStrides)); - v = v - log(S.FastGet(dot(uint4(n, y, x, c), _SStrides))); - O.Set(n, y, x, c, v); - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast.cginc.meta deleted file mode 100644 index a94e760..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: fc624dd44959d4dfcad99aed0abc2a8d -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NCHW.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NCHW.compute deleted file mode 100644 index d0c2f30..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NCHW.compute +++ /dev/null @@ -1,22 +0,0 @@ -#pragma kernel BroadcastAdd_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastSub_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastMul_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastDiv_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastPow_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastMin_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastMax_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastMean_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastGreater_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastGreaterEqual_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLess_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLessEqual_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastEqual_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLogicalOr_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLogicalAnd_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastLogicalXor_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastWhere_NCHW CHANNELS_FIRST=1 -#pragma kernel BroadcastDivExpSub_NCHW CHANNELS_FIRST=1 -#pragma kernel LogSoftmaxEnd_NCHW CHANNELS_FIRST=1 - - -#include "Broadcast.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NCHW.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NCHW.compute.meta deleted file mode 100644 index ed0cb90..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NCHW.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5d7fa6770eadc4ef38d7b12a5dedf404 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NHWC.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NHWC.compute deleted file mode 100644 index 8a426a9..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NHWC.compute +++ /dev/null @@ -1,22 +0,0 @@ -#pragma kernel BroadcastAdd_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastSub_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastMul_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastDiv_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastPow_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastMin_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastMax_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastMean_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastGreater_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastGreaterEqual_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLess_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLessEqual_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastEqual_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLogicalOr_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLogicalAnd_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastLogicalXor_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastWhere_NHWC CHANNELS_FIRST=0 -#pragma kernel BroadcastDivExpSub_NHWC CHANNELS_FIRST=0 -#pragma kernel LogSoftmaxEnd_NHWC CHANNELS_FIRST=0 - -#include "Broadcast.cginc" - diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NHWC.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NHWC.compute.meta deleted file mode 100644 index cfdabea..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Broadcast_NHWC.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e08c989f90a0240cdac731efb621231e -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2d.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2d.cginc deleted file mode 100644 index 15f2e70..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2d.cginc +++ /dev/null @@ -1,1915 +0,0 @@ -#include "Tensor.cginc" -#define UNITY_SHADER_NO_UPGRADE 1 - -TENSOR_DECL(X) -TENSOR_DECL(K) -TENSOR_DECL(B) -TENSOR_DECL(WBK) -TENSOR_DECL_RW(O) - -uint4 _Pad; -uint4 _Stride; - -#define DEBUG_CHECK_BOUNDS 0 - -// Conv2DBlock64x64_4x4 + index optimizations -// T -// -1|0 -1|0 -// 16: 142|142ms 144|155ms - -float ffma(float a, float b, float c) { return dot(float2(a,c), float2(b,1)); } - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) KERNEL##SUFFIX##SIZE##x##SIZE##_NCHW - #define CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) KERNEL##SUFFIX##SIZE##x##SIZE##_Cache_##TENSOR##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) KERNEL##SUFFIX##SIZE##x##SIZE##_NHWC - #define CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) KERNEL##SUFFIX##SIZE##x##SIZE##_Cache_##TENSOR##_NHWC -#endif -#define FUNC_NAME(KERNEL, SUFFIX, SIZE) FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) -#define CACHE_NAME(KERNEL, SUFFIX, SIZE, TENSOR) CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) - -#define KERNEL_NAME Conv2D - -#if BLOCK_SIZE == 8 -#if KERNEL_PER_TG == 64 - -#if CHANNELS_FIRST - //NCHW - #define CACHE_DEPTH 8 // Profiled as the fastest to avoid 'tail' of inner loops with occupancy 1 at end of dispatch. - #define CACHE_WIDTH_W_PAD 1 - #define NUM_DDR_LOAD_PER_LOOP CACHE_DEPTH // Not needed for NCHW - #define SHUFFLE_FOR_COALESCED_LOAD 0 // Not needed for NCHW - #define SHUFFLE_FOR_COALESCED_STORE 1 -#else - //NHWC - #define CACHE_DEPTH 16 // Only supported value - #define CACHE_WIDTH_W_PAD 0 // Only supported value - #define NUM_DDR_LOAD_PER_LOOP 8 // <=8 required to lower register pressure for NHWC for occupancy of 2. - #define SHUFFLE_FOR_COALESCED_LOAD 1 - #define SHUFFLE_FOR_COALESCED_STORE 1 -#endif -#define CACHE_WIDTH_X 64 // Only supported value -#define CACHE_WIDTH_W (64+CACHE_WIDTH_W_PAD) // Only supported value - -#if SHUFFLE_FOR_COALESCED_STORE - //A TG output [64pixels,64channels] = 4096 values, We will write two time 2048 values to DDR (8k LDS). - groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS)[2048]; -#else - groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS)[CACHE_DEPTH*(CACHE_WIDTH_X+CACHE_WIDTH_W)]; -#endif - -[numthreads(8,8,1)] -void FUNC_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE)(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex) -{ - //This kernel assume the following: - //Input: - // C % CACHE_DEPTH==0 <-- only if STRICT_CHANNELS==1 - //Ouput: - // W%4==0 <-- only if CHANNELS_FIRST==1 - //Kernel: - // K%64==0 <-- only if LAX_KERNEL=0 else K%16==0 is required - //DISPATCH ARGS(K.kernelCount, O.width * O.height, O.batch); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - #define LDS_ CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS) - #define X_OFFSET 0 - #define W_OFFSET CACHE_DEPTH*CACHE_WIDTH_X - - //Per thread group (scalar registers) - uint tg_NumChannels = X.channels; - uint tg_WidthX = X.width; - uint tg_HeightX = X.height; - uint tg_WidthO = O.width; - uint tg_HeightO = O.height; - uint tg_NumKernels = K.channels; - uint tg_NumInputPixels = tg_WidthX*tg_HeightX; - uint tg_NumOuputPixels = tg_WidthO*tg_HeightO; - uint tg_KernelSpatialStride = tg_NumKernels*tg_NumChannels; - uint tg_KernelBaseId = groupID.x * CACHE_WIDTH_X; - uint tg_OutputPixelBaseId = groupID.y * CACHE_WIDTH_X; - uint tg_BatchReadOffset = groupID.z * tg_NumChannels * tg_HeightX * tg_WidthX; - uint tg_BatchWriteOffset = groupID.z * tg_NumKernels * tg_HeightO * tg_WidthO; - uint tg_kernelSpatialOffset = 0; - - //8x8 block, 8 kernels by 8 pixels - //********************************** - //* Kernel Ids * 0 1 2 3 ... - //********************************** - // * ThreadIds - // Pixel Ids 0 * 0 1 2 3 ... - // 1 * 8 9 10 11 ... - // 2 * 16 17 18 19 ... - // 3 * 32 33 34 35 ... - // ... ... - float dstA[BLOCK_SIZE*BLOCK_SIZE]; - - //Load Bias [K] int dstA [Kernels, Pixels] - uint tg_kId; - uint tg_pId; - uint maxBiasIndex = O.channels - 1; - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - [unroll] for (tg_kId = 0; tg_kId < BLOCK_SIZE; ++tg_kId) - dstA[tg_pId*BLOCK_SIZE+tg_kId] = B.FastGet(min(maxBiasIndex,tg_KernelBaseId + groupThreadID.x * BLOCK_SIZE + tg_kId)); - - for (uint tg_Dy = 0; tg_Dy < K.GetKernelHeight(); tg_Dy++) - { - for (uint tg_Dx = 0; tg_Dx < K.GetKernelWidth(); tg_Dx++) - { - for (uint tg_ChannelOffset = 0; tg_ChannelOffset < tg_NumChannels; tg_ChannelOffset += CACHE_DEPTH) - { - uint tg_CacheLoadDynIdx = 0; - //Load from DDR to LDS: (64 weight + 64 pixel) * CACHE_DEPTH => 512Bytes * CACHE_DEPTH. - //Storing in registers to avoid sync inside the loop. - #if NUM_DDR_LOAD_PER_LOOP != CACHE_DEPTH - for (; tg_CacheLoadDynIdx < CACHE_DEPTH/NUM_DDR_LOAD_PER_LOOP; ++tg_CacheLoadDynIdx) - #endif - { - //Explicit register declaration as [unroll] won't unroll properly otherwise and introduce sync points. - float tempW[NUM_DDR_LOAD_PER_LOOP]; - float tempX[NUM_DDR_LOAD_PER_LOOP]; - uint tg_regCacheLoadIdx; - [unroll] for (tg_regCacheLoadIdx = 0; tg_regCacheLoadIdx < NUM_DDR_LOAD_PER_LOOP; ++tg_regCacheLoadIdx) - { - uint tg_CacheLoadIdx = tg_CacheLoadDynIdx * NUM_DDR_LOAD_PER_LOOP + tg_regCacheLoadIdx; - //K stored as HWCK, threadgroup is loading 64 kernels at a time to LDS in a linear fashion. - //HW from tg_kernelSpatialOffset - //C from tg_ChannelOffset+tg_CacheLoadIdx - //K from tg_KernelBaseId (for TG) + threadIndex ([0-63]) - uint tg_KernelReadOffset = tg_kernelSpatialOffset + tg_NumKernels*(tg_ChannelOffset+tg_CacheLoadIdx) + tg_KernelBaseId; - uint kernelReadOffset = tg_KernelReadOffset + threadIndex; - #if !STRICT_CHANNELS || LAX_KERNEL - kernelReadOffset = min(kernelReadOffset, K.GetLength()-1); - #endif - tempW[tg_regCacheLoadIdx] = K.FastGet(kernelReadOffset); - - //Compute input position and mask. - #if SHUFFLE_FOR_COALESCED_LOAD - //64 Reads per TG per loop -> 4 pixels x 16 channels across threads -> good for NHWC. - //IMPORTANT : For register pressure reason -> it is assumed that tg_WidthO % 4 == 0, so we know all - //pixels for a given TG+loop are on the same row and thus we can compute Y mask/pos using scalar registers. - uint cacheChannelId = threadIndex % 16; - int tg_outputPixelBaseId = tg_OutputPixelBaseId + tg_CacheLoadIdx * 4; - int2 tg_ouputPixelsBaseCoord = int2(tg_outputPixelBaseId % tg_WidthO, tg_outputPixelBaseId / tg_WidthO); - int2 tg_inputPixelsBaseCoord = tg_ouputPixelsBaseCoord * _Stride.xy - _Pad.xy + int2(tg_Dx, tg_Dy); - bool tg_inputPixelsYMask = (tg_inputPixelsBaseCoord.y >= 0) && (tg_inputPixelsBaseCoord.y < (int)tg_HeightX); - int inputPixelXCoord = (threadIndex / 16) * _Stride.x + tg_inputPixelsBaseCoord.x; - bool inputPixelMask = tg_inputPixelsYMask && (inputPixelXCoord >= 0) && (inputPixelXCoord < (int)tg_WidthX); - int2 inputPixelCoords = int2(inputPixelXCoord, tg_inputPixelsBaseCoord.y);//.y is scalar - #else - //64 Reads per TG per loop -> 64 pixels across threads -> good for NCHW. - uint cacheChannelId = tg_CacheLoadIdx;//scalar in that code path. - int outputPixelBaseId = tg_OutputPixelBaseId + threadIndex; - int2 outputPixelCoords = int2(outputPixelBaseId % tg_WidthO, outputPixelBaseId / tg_WidthO); - int2 inputPixelCoords = outputPixelCoords * _Stride.xy - _Pad.xy + int2(tg_Dx, tg_Dy); - bool inputPixelMask = all( (inputPixelCoords >= 0) && (inputPixelCoords < float2(tg_WidthX, tg_HeightX)) ); - #endif - int inputPixelId = inputPixelCoords.y * tg_WidthX + inputPixelCoords.x; - uint inputChannelId = tg_ChannelOffset + cacheChannelId; - bool inputChannelMask = inputChannelId < tg_NumChannels; - #if STRICT_CHANNELS - inputChannelMask = true; - #endif - #if CHANNELS_FIRST - uint pixelReadOffset = tg_NumInputPixels * inputChannelId + inputPixelId + tg_BatchReadOffset; - #else - uint pixelReadOffset = tg_NumChannels * inputPixelId + inputChannelId + tg_BatchReadOffset; - #endif - tempX[tg_regCacheLoadIdx] = X.MaskedGet(inputPixelMask && inputChannelMask, pixelReadOffset); - } - - [unroll] for (tg_regCacheLoadIdx = 0; tg_regCacheLoadIdx < NUM_DDR_LOAD_PER_LOOP; ++tg_regCacheLoadIdx) - { - uint tg_CacheLoadIdx = tg_CacheLoadDynIdx * NUM_DDR_LOAD_PER_LOOP + tg_regCacheLoadIdx; - #if SHUFFLE_FOR_COALESCED_LOAD - uint cachePixelId = tg_CacheLoadIdx * 4 + threadIndex / 16; - uint cacheChannelId = threadIndex % 16; - #else - uint cachePixelId = threadIndex; - uint cacheChannelId = tg_CacheLoadIdx;//scalar in that code path. - #endif - uint weightWriteIndex = (threadIndex>31)?threadIndex+CACHE_WIDTH_W_PAD:threadIndex; - LDS_[ W_OFFSET + tg_CacheLoadIdx*CACHE_WIDTH_W + weightWriteIndex ] = tempW[tg_regCacheLoadIdx]; - LDS_[ X_OFFSET + cacheChannelId*CACHE_WIDTH_X + cachePixelId ] = tempX[tg_regCacheLoadIdx]; - } - } - - GroupMemoryBarrierWithGroupSync(); - - //Inner loop - uint ptrX = groupThreadID.y*BLOCK_SIZE + X_OFFSET; - uint ptrW = groupThreadID.x*BLOCK_SIZE + W_OFFSET; - ptrW += (groupThreadID.x*BLOCK_SIZE>31)?CACHE_WIDTH_W_PAD:0; - for (uint tg_CacheExecuteIdx = 0; tg_CacheExecuteIdx < CACHE_DEPTH; ++tg_CacheExecuteIdx) - { - //Load LDS -> registers - float colOfX[BLOCK_SIZE]; - float rowOfW[BLOCK_SIZE]; - uint tg_q; - [unroll] for (tg_q = 0; tg_q < BLOCK_SIZE; ++tg_q) - colOfX[tg_q] = LDS_[ptrX + tg_q]; - [unroll] for (tg_q = 0; tg_q < BLOCK_SIZE; ++tg_q) - rowOfW[tg_q] = LDS_[ptrW + tg_q]; - - ptrX += CACHE_WIDTH_X; - ptrW += CACHE_WIDTH_W; - - //Mads 8 pixels by 8 kernels matmul style --> 64 mads - [unroll] for (uint tg_X = 0; tg_X < BLOCK_SIZE; ++tg_X) - [unroll] for (uint tg_W = 0; tg_W < BLOCK_SIZE; ++tg_W) - dstA[tg_X*BLOCK_SIZE+tg_W] = ffma(colOfX[tg_X], rowOfW[tg_W], dstA[tg_X*BLOCK_SIZE+tg_W]); - } - - GroupMemoryBarrierWithGroupSync(); - } - - tg_kernelSpatialOffset += tg_KernelSpatialStride; - } - } - - #if SHUFFLE_FOR_COALESCED_STORE - //----------------------------------------------------- - //Use LDS to shuffle TG registers into coalesced writes - //----------------------------------------------------- - //A TG output [64pixels,64channels] = 4096 values, We will process [32,64] values at a time per TG. - #if CHANNELS_FIRST - //NCHW - for (uint tg_registerChannelOffset = 0; tg_registerChannelOffset < BLOCK_SIZE; tg_registerChannelOffset += 4) - { - //Store 8 pixels x 4 channels per threads to LDS. - [unroll] for (tg_kId = 0; tg_kId < 4; ++tg_kId) - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - { - //To avoid bank conflict store in 32 groups [8pixelsGroups,4channelsGroups] each group contain 64 values [8pixels,8kernels] for a total of 2048 values [64pixels,32channels] - uint ldsOffsetOfGroup = CACHE_WIDTH_X * (tg_kId*BLOCK_SIZE+tg_pId);//64 * ([0,3]*8+[0,7]) = [0,1984] - LDS_[ldsOffsetOfGroup + threadIndex] = dstA[BLOCK_SIZE * tg_pId + (tg_registerChannelOffset + tg_kId)]; - } - - GroupMemoryBarrierWithGroupSync(); - - //We have a buffers of [64pixels,32channels] floats, each thread will store [1pixels,32channels] so a threadgroup is storing 64 pixels at a time to DDR in a linear fashion. - uint readPixelId = threadIndex; - uint writePixelId = tg_OutputPixelBaseId + readPixelId; - - #define WRITE_8CHANNELS_IF_POSSIBLE(groupID) \ - tg_ddrChannelGroupBaseId[groupID] = tg_KernelBaseId + 16 * groupID; \ - if (tg_ddrChannelGroupBaseId[groupID] < tg_NumKernels) \ - { \ - [unroll] for (tg_kId = groupID*8; tg_kId < 8*(groupID+1); ++tg_kId) \ - { \ - uint tg_kIdOfGroup = tg_kId % 4; \ - uint pIdOfGroup = readPixelId % BLOCK_SIZE; \ - uint ldsOffsetOfGroup = CACHE_WIDTH_X * (tg_kIdOfGroup * BLOCK_SIZE + pIdOfGroup); \ - uint tg_kIdInGroup = (tg_kId - tg_kIdOfGroup) / 4; \ - uint pIdInGroup = (readPixelId - pIdOfGroup) / BLOCK_SIZE; \ - uint ldsOffsetInGroup = pIdInGroup * BLOCK_SIZE + tg_kIdInGroup; \ - uint readIndex = ldsOffsetOfGroup + ldsOffsetInGroup; \ - uint writeChannelId = tg_KernelBaseId + tg_kId%4 + (tg_kId/4)*BLOCK_SIZE + tg_registerChannelOffset; \ - uint writeIndex = O.width * O.height * writeChannelId + writePixelId + tg_BatchWriteOffset; \ - O.FastSetWithActivation(writeIndex, LDS_[readIndex]); \ - } \ - } - - if (writePixelId < tg_NumOuputPixels) - { - #if LAX_KERNEL - uint tg_ddrChannelGroupBaseId[4]; - WRITE_8CHANNELS_IF_POSSIBLE(0); - WRITE_8CHANNELS_IF_POSSIBLE(1); - WRITE_8CHANNELS_IF_POSSIBLE(2); - WRITE_8CHANNELS_IF_POSSIBLE(3); - #else - [unroll] for (tg_kId = 0; tg_kId < 32; ++tg_kId) - { - //Find LDS group to read from - uint tg_kIdOfGroup = tg_kId % 4;//[0,3] kernelsGroups - uint pIdOfGroup = readPixelId % BLOCK_SIZE;//[0,7] pixelsGroups - uint ldsOffsetOfGroup = CACHE_WIDTH_X * (tg_kIdOfGroup * BLOCK_SIZE + pIdOfGroup);//CACHE_WIDTH_X * ([0,3]*8+[0,7]) = [0,1984] - //Find index inside that group - uint tg_kIdInGroup = (tg_kId - tg_kIdOfGroup) / 4;//[0,7] kernels - uint pIdInGroup = (readPixelId - pIdOfGroup) / BLOCK_SIZE;//[0,7] pixels - uint ldsOffsetInGroup = pIdInGroup * BLOCK_SIZE + tg_kIdInGroup;//[0,7]*8+[0,7] = [0,63] - //load from LDS and store to DDR - uint readIndex = ldsOffsetOfGroup + ldsOffsetInGroup;//[0,2047] - uint writeChannelId = tg_KernelBaseId + tg_kId%4 + (tg_kId/4)*BLOCK_SIZE + tg_registerChannelOffset; - uint writeIndex = O.width * O.height * writeChannelId + writePixelId + tg_BatchWriteOffset; - //TODO Still some bank conflict here, an option would be to pad LDS but need more loop then (as already have 8k LDS with two loop). - O.FastSetWithActivation(writeIndex, LDS_[readIndex]); - } - #endif - } - - GroupMemoryBarrierWithGroupSync(); - } - #else - //NHWC - for (uint tg_registerPixelOffset = 0; tg_registerPixelOffset < BLOCK_SIZE; tg_registerPixelOffset += 4) - { - //Store 4 pixels x 8 channels per threads to LDS. - uint ldsRowOffset = groupThreadID.y * 4; - uint ldsChannelOffset = groupThreadID.x * BLOCK_SIZE; - [unroll] for (tg_pId = 0; tg_pId < 4; ++tg_pId) - [unroll] for (tg_kId = 0; tg_kId < BLOCK_SIZE; ++tg_kId) - { - //TODO check for bank conflict here, probably need to swizzle the writes per thread - LDS_[CACHE_WIDTH_X * (ldsRowOffset + tg_pId) + ldsChannelOffset + tg_kId] = dstA[BLOCK_SIZE * (tg_registerPixelOffset + tg_pId) + tg_kId]; - } - - GroupMemoryBarrierWithGroupSync(); - - //We have a buffers of [32pixels,64channels] floats, each thread will store [32pixels,1channels] so a threadgroup is storing 64 kernels at a time to DDR in a linear fashion. - uint writeChannelId = tg_KernelBaseId + threadIndex; - uint tg_writeLoopBaseId = tg_OutputPixelBaseId + tg_registerPixelOffset; - uint tg_ddrPixelGroupBaseId[8]; - - #if LAX_KERNEL - bool canWriteChannel = (writeChannelId < tg_NumKernels); - #else - bool canWriteChannel = true; - #endif - - //Ok as we enforce W%4==0 thus W*H%4==0 also. - //Using a Macro as [unroll] on loop(groupID) won't unroll properly and thus introduce LDS/DDR sync points. - #define WRITE_4PIXELS_IF_POSSIBLE(groupID) \ - tg_ddrPixelGroupBaseId[groupID]= tg_writeLoopBaseId + BLOCK_SIZE * groupID; \ - if ((tg_ddrPixelGroupBaseId[groupID] < tg_NumOuputPixels) && canWriteChannel)\ - { \ - [unroll] for (tg_pId = 0; tg_pId < 4; ++tg_pId) \ - O.FastSetWithActivation(tg_BatchWriteOffset + tg_NumKernels * (tg_ddrPixelGroupBaseId[groupID]+tg_pId) + writeChannelId, LDS_[CACHE_WIDTH_X * (groupID * 4 + tg_pId) + threadIndex]); \ - } - WRITE_4PIXELS_IF_POSSIBLE(0); - WRITE_4PIXELS_IF_POSSIBLE(1); - WRITE_4PIXELS_IF_POSSIBLE(2); - WRITE_4PIXELS_IF_POSSIBLE(3); - WRITE_4PIXELS_IF_POSSIBLE(4); - WRITE_4PIXELS_IF_POSSIBLE(5); - WRITE_4PIXELS_IF_POSSIBLE(6); - WRITE_4PIXELS_IF_POSSIBLE(7); - #undef WRITE_PIXEL_GROUP_IF_POSSIBLE - - GroupMemoryBarrierWithGroupSync(); - } - #endif //CHANNELS_FIRST - #else - //------------------------------- - //Directly store registers to DDR - //------------------------------- - //B does not require an offset as size == 1 - //C from tg_KernelBaseId, groupThreadID.x and tg_kId - //HW from tg_OutputPixelBaseId, groupThreadID.y and tg_pId - [unroll] for (tg_kId = 0; tg_kId < BLOCK_SIZE; ++tg_kId) - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - { - uint writeChannelId = tg_KernelBaseId + groupThreadID.x * BLOCK_SIZE + tg_kId; - uint writePixelId = tg_OutputPixelBaseId + groupThreadID.y * BLOCK_SIZE + tg_pId; - float writeValue = dstA[tg_pId*BLOCK_SIZE+tg_kId]; - #if CHANNELS_FIRST - uint writeIndex = O.width * O.height * writeChannelId + writePixelId + tg_BatchWriteOffset; - #else - uint writeIndex = tg_NumKernels * writePixelId + writeChannelId + tg_BatchWriteOffset; - #endif - #if LAX_KERNEL - bool canWriteChannel = (writeChannelId < tg_NumKernels); - #else - bool canWriteChannel = true; - #endif - if ((writePixelId < tg_NumOuputPixels) && canWriteChannel) - O.FastSetWithActivation(writeIndex, writeValue); - } - #endif - - #undef X_OFFSET - #undef W_OFFSET - #undef LDS_ - #undef X_ - #undef W_ -} -#undef CACHE_DEPTH -#undef CACHE_WIDTH -#undef SHUFFLE_FOR_COALESCED_LOAD -#undef SHUFFLE_FOR_COALESCED_STORE -#endif //KERNEL_PER_TG == 64 - -#if KERNEL_PER_TG == 16 - -#define CACHE_DEPTH 4 // This kernel code supports only CACHE_DEPTH=4, this value can not be changed -#define PIXELS_PER_CACHE 256 // This kernel code supports only PIXELS_PER_CACHE=256, this value can not be changed -#define NUMTHREADS_PER_TG 64 // This kernel code supports only NUMTHREADS_PER_TG=64, this value can not be changed -#define PIXELS_READ_PER_THREAD_PER_CACHE PIXELS_PER_CACHE/NUMTHREADS_PER_TG - -#if CHANNELS_FIRST - //NCHW - #define PIXELS_CACHE_PAD 1 - #define SHUFFLE_FOR_COALESCED_LOAD 0 // Not needed for NCHW - #define SHUFFLE_FOR_COALESCED_STORE 1 -#else - //NHWC - #define PIXELS_CACHE_PAD 0 // TODO not implemented for NHWC - #define SHUFFLE_FOR_COALESCED_LOAD 1 - #define SHUFFLE_FOR_COALESCED_STORE 0 // Not implemented for NHWC, TODO (probably limited gain because of CACHE_DEPTH of 4) -#endif - -#define PIXELS_PER_CACHE_AND_PAD ((PIXELS_PER_CACHE/BLOCK_SIZE)*(BLOCK_SIZE+PIXELS_CACHE_PAD)) - -#if SHUFFLE_FOR_COALESCED_STORE - //A TG output [256pixels,16channels] = 4096 values, We will write two time 2048 values to DDR (8k LDS). - groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS)[2048]; -#else - groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS)[(KERNEL_PER_TG+PIXELS_PER_CACHE_AND_PAD)*CACHE_DEPTH]; -#endif -[numthreads(2,32,1)] -void FUNC_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE)(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex) -{ - //This kernel assume the following: - //Input: - // C % CACHE_DEPTH==0 <-- only if STRICT_CHANNELS==1 - //Kernel: - // K%16==0 <-- only if LAX_KERNEL=0 - //DISPATCH ARGS(K.kernelCount, O.width * O.height, O.batch); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - #define LDS_ CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS) - #define X_OFFSET 0 - #define W_OFFSET CACHE_DEPTH*PIXELS_PER_CACHE_AND_PAD - - //Per thread group (scalar registers) - uint tg_NumChannels = X.channels; - uint tg_WidthX = X.width; - uint tg_HeightX = X.height; - uint tg_WidthO = O.width; - uint tg_HeightO = O.height; - uint tg_NumKernels = K.channels; - uint tg_NumInputPixels = tg_WidthX*tg_HeightX; - uint tg_NumOuputPixels = tg_WidthO*tg_HeightO; - uint tg_KernelSpatialStride = tg_NumKernels*tg_NumChannels; - uint tg_KernelBaseId = groupID.x * KERNEL_PER_TG; - uint tg_OutputPixelBaseId = groupID.y * PIXELS_PER_CACHE; - uint tg_BatchReadOffset = groupID.z * tg_NumChannels * tg_HeightX * tg_WidthX; - uint tg_BatchWriteOffset = groupID.z * tg_NumKernels * tg_HeightO * tg_WidthO; - uint tg_kernelSpatialOffset = 0; - - //8x8 block, 8 kernels by 8 pixels - //********************************** - //* Kernel Ids * 0 1 2 3 ... - //********************************** - // * ThreadIds - // Pixel Ids 0 * 0 1 2 3 ... - // 1 * 8 9 10 11 ... - // 2 * 16 17 18 19 ... - // 3 * 32 33 34 35 ... - // ... ... - float dstA[BLOCK_SIZE*BLOCK_SIZE]; - - //Load Bias [K] int dstA [Kernels, Pixels] - uint tg_kId; - uint tg_pId; - uint maxBiasIndex = O.channels - 1; - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - [unroll] for (tg_kId = 0; tg_kId < BLOCK_SIZE; ++tg_kId) - dstA[tg_pId*BLOCK_SIZE+tg_kId] = B.FastGet(min(maxBiasIndex,tg_KernelBaseId + groupThreadID.x * BLOCK_SIZE + tg_kId)); - - //Loop spatialy on kernels - for (uint tg_Dy = 0; tg_Dy < K.GetKernelHeight(); tg_Dy++) - { - for (uint tg_Dx = 0; tg_Dx < K.GetKernelWidth(); tg_Dx++) - { - for (uint tg_ChannelOffset = 0; tg_ChannelOffset < tg_NumChannels; tg_ChannelOffset += CACHE_DEPTH) - { - //Load from DDR to LDS: (16*CACHE_DEPTH=64 weights + 256*CACHE_DEPTH=1024 pixels) => 4352Bytes * CACHE_DEPTH. - - //K stored as HWCK, threadgroup is loading 64 kernels at a time to LDS in a linear fashion (4x16 kernels). - //HW from tg_kernelSpatialOffset - //C from tg_ChannelOffset (for TG) + threadIndex ([0-63]->[0-3]) - //K from tg_KernelBaseId (for TG) + threadIndex ([0-63]) - uint kernelCacheLoadOffset = threadIndex / 16; - uint kernelLoadOffset = threadIndex % 16; - uint kernelReadOffset = tg_kernelSpatialOffset + tg_NumKernels*(tg_ChannelOffset+kernelCacheLoadOffset) + tg_KernelBaseId + kernelLoadOffset; - #if !STRICT_CHANNELS || LAX_KERNEL - kernelReadOffset = min(kernelReadOffset, K.GetLength()-1); - #endif - float tempW = K.FastGet(kernelReadOffset); - - #if SHUFFLE_FOR_COALESCED_LOAD - //Good for HWC - //TG is loading 256Pixels * CACHE_DEPTH to LDS in an attempt of linear fashion (16 pixels read per thread). - //would be better if CACHE_DEPTH would be bigger than 4 but LDS is the limiting factor here. - uint tg_PixelLoadIdx; - uint cacheLoadIdx = threadIndex % 4; - uint pixelLoadOffset = threadIndex / 4; - float tempX[CACHE_DEPTH*PIXELS_READ_PER_THREAD_PER_CACHE];//{channels*pixels} - [unroll] for (tg_PixelLoadIdx = 0; tg_PixelLoadIdx < PIXELS_READ_PER_THREAD_PER_CACHE*CACHE_DEPTH; ++tg_PixelLoadIdx) - { - //Compute input position and mask. - int outputPixelBaseId = tg_OutputPixelBaseId + PIXELS_READ_PER_THREAD_PER_CACHE*CACHE_DEPTH * tg_PixelLoadIdx + pixelLoadOffset; - int2 outputPixelCoords = int2(outputPixelBaseId % tg_WidthO, outputPixelBaseId / tg_WidthO); - int2 inputPixelCoords = outputPixelCoords * _Stride.xy - _Pad.xy + int2(tg_Dx, tg_Dy); - bool inputPixelMask = all( (inputPixelCoords >= 0) && (inputPixelCoords < float2(tg_WidthX, tg_HeightX)) ); - - int inputPixelId = inputPixelCoords.y * tg_WidthX + inputPixelCoords.x; - uint tg_InputChannelId = tg_ChannelOffset + cacheLoadIdx; - bool inputChannelMask = tg_InputChannelId < tg_NumChannels; - #if STRICT_CHANNELS - inputChannelMask = true; - #endif - #if CHANNELS_FIRST - uint pixelReadOffset = tg_NumInputPixels * tg_InputChannelId + inputPixelId + tg_BatchReadOffset; - #else - uint pixelReadOffset = tg_NumChannels * inputPixelId + tg_InputChannelId + tg_BatchReadOffset; - #endif - tempX[tg_PixelLoadIdx] = X.MaskedGet(inputPixelMask && inputChannelMask, pixelReadOffset); - } - - [unroll] for (tg_PixelLoadIdx = 0; tg_PixelLoadIdx < PIXELS_READ_PER_THREAD_PER_CACHE*CACHE_DEPTH; ++tg_PixelLoadIdx) - { - LDS_[ X_OFFSET + cacheLoadIdx*PIXELS_PER_CACHE_AND_PAD + tg_PixelLoadIdx*PIXELS_READ_PER_THREAD_PER_CACHE*CACHE_DEPTH + pixelLoadOffset] = tempX[tg_PixelLoadIdx]; - } - #else - //Good for CHW - //TG is loading 256Pixels * CACHE_DEPTH to LDS in a linear fashion (4 channels * 4 pixels read per thread). - //Explicit register declaration as [unroll] won't unroll properly otherwise and introduce sync points. - uint tg_CacheLoadIdx; - uint tg_PixelLoadIdx; - float tempX[CACHE_DEPTH][PIXELS_READ_PER_THREAD_PER_CACHE];//{channels,pixels} - [unroll] for (tg_CacheLoadIdx = 0; tg_CacheLoadIdx < CACHE_DEPTH; ++tg_CacheLoadIdx) - { - [unroll] for (tg_PixelLoadIdx = 0; tg_PixelLoadIdx < PIXELS_READ_PER_THREAD_PER_CACHE; ++tg_PixelLoadIdx) - { - //Compute input position and mask. - int outputPixelBaseId = tg_OutputPixelBaseId + NUMTHREADS_PER_TG * tg_PixelLoadIdx + threadIndex; - int2 outputPixelCoords = int2(outputPixelBaseId % tg_WidthO, outputPixelBaseId / tg_WidthO); - int2 inputPixelCoords = outputPixelCoords * _Stride.xy - _Pad.xy + int2(tg_Dx, tg_Dy); - bool inputPixelMask = all( (inputPixelCoords >= 0) && (inputPixelCoords < float2(tg_WidthX, tg_HeightX)) ); - - int inputPixelId = inputPixelCoords.y * tg_WidthX + inputPixelCoords.x; - uint tg_InputChannelId = tg_ChannelOffset + tg_CacheLoadIdx; - bool inputChannelMask = tg_InputChannelId < tg_NumChannels; - #if STRICT_CHANNELS - inputChannelMask = true; - #endif - #if CHANNELS_FIRST - uint pixelReadOffset = tg_NumInputPixels * tg_InputChannelId + inputPixelId + tg_BatchReadOffset; - #else - uint pixelReadOffset = tg_NumChannels * inputPixelId + tg_InputChannelId + tg_BatchReadOffset; - #endif - tempX[tg_CacheLoadIdx][tg_PixelLoadIdx] = X.MaskedGet(inputPixelMask && inputChannelMask, pixelReadOffset); - } - } - - [unroll] for (tg_CacheLoadIdx = 0; tg_CacheLoadIdx < CACHE_DEPTH; ++tg_CacheLoadIdx) - { - [unroll] for (tg_PixelLoadIdx = 0; tg_PixelLoadIdx < PIXELS_READ_PER_THREAD_PER_CACHE; ++tg_PixelLoadIdx) - { - uint ldsPixelCacheWriteIndex = tg_PixelLoadIdx*NUMTHREADS_PER_TG + threadIndex; - ldsPixelCacheWriteIndex += (ldsPixelCacheWriteIndex/BLOCK_SIZE) * PIXELS_CACHE_PAD; - LDS_[ X_OFFSET + tg_CacheLoadIdx*PIXELS_PER_CACHE_AND_PAD + ldsPixelCacheWriteIndex] = tempX[tg_CacheLoadIdx][tg_PixelLoadIdx]; - } - } - #endif - LDS_[ W_OFFSET + kernelCacheLoadOffset*KERNEL_PER_TG + kernelLoadOffset ] = tempW; - - GroupMemoryBarrierWithGroupSync(); - - //Inner loop - uint ptrX = groupThreadID.y*(BLOCK_SIZE+PIXELS_CACHE_PAD) + X_OFFSET; - uint ptrW = groupThreadID.x*BLOCK_SIZE + W_OFFSET; - for (uint tg_CacheExecuteIdx = 0; tg_CacheExecuteIdx < CACHE_DEPTH; ++tg_CacheExecuteIdx) - { - //Load LDS -> registers - float colOfX[BLOCK_SIZE]; - float rowOfW[BLOCK_SIZE]; - uint tg_q; - [unroll] for (tg_q = 0; tg_q < BLOCK_SIZE; ++tg_q) - colOfX[tg_q] = LDS_[ptrX + tg_q]; - [unroll] for (tg_q = 0; tg_q < BLOCK_SIZE; ++tg_q) - rowOfW[tg_q] = LDS_[ptrW + tg_q]; - - ptrX += PIXELS_PER_CACHE_AND_PAD; - ptrW += KERNEL_PER_TG; - - //Mads 8 pixels by 8 kernels matmul style --> 64 mads - [unroll] for (uint tg_X = 0; tg_X < BLOCK_SIZE; ++tg_X) - [unroll] for (uint tg_W = 0; tg_W < BLOCK_SIZE; ++tg_W) - dstA[tg_X*BLOCK_SIZE+tg_W] = ffma(colOfX[tg_X], rowOfW[tg_W], dstA[tg_X*BLOCK_SIZE+tg_W]); - } - - GroupMemoryBarrierWithGroupSync(); - } - - tg_kernelSpatialOffset += tg_KernelSpatialStride; - } - } - - #if SHUFFLE_FOR_COALESCED_STORE && !LAX_KERNEL - //----------------------------------------------------- - //Use LDS to shuffle TG registers into coalesced writes - //----------------------------------------------------- - //A TG output [256pixels,16channels] = 4096 values, We will process [256,8] values at a time per TG. - for (uint tg_registerChannelOffset = 0; tg_registerChannelOffset < BLOCK_SIZE; tg_registerChannelOffset += 4) - { - //Store 8 pixels x 4 channels per threads to LDS. - [unroll] for (tg_kId = 0; tg_kId < 4; ++tg_kId) - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - { - //To avoid bank conflict store in 32 groups [8pixelsGroups,4channelsGroups] each group contain 64 values [32pixels,2kernels] for a total of 2048 values [256pixels,8channels] - uint ldsOffsetOfGroup = NUMTHREADS_PER_TG * (tg_kId*BLOCK_SIZE+tg_pId);//64 * ([0,3]*8+[0,7]) = [0,1984] - LDS_[ldsOffsetOfGroup + threadIndex] = dstA[BLOCK_SIZE * tg_pId + (tg_registerChannelOffset + tg_kId)]; - } - - GroupMemoryBarrierWithGroupSync(); - - //We have a buffers of [256pixels,8channels] floats, each thread will store [4pixels,8channels] so a threadgroup is storing 64 pixels at a time to DDR in a linear fashion. - //Using a Macro as [unroll] on loop(groupID) won't unroll properly and thus introduce LDS/DDR sync points. - #define WRITE_8CHANNELS_IF_POSSIBLE(groupID) \ - {\ - uint readPixelId = groupID * NUMTHREADS_PER_TG + threadIndex; \ - uint writePixelId = tg_OutputPixelBaseId + groupID * NUMTHREADS_PER_TG + threadIndex; \ - if (writePixelId < tg_NumOuputPixels) \ - { \ - [unroll] for (tg_kId = 0; tg_kId < BLOCK_SIZE; ++tg_kId) \ - { \ - uint tg_kIdOfGroup = tg_kId % 4; \ - uint pIdOfGroup = readPixelId % BLOCK_SIZE; \ - uint ldsOffsetOfGroup = NUMTHREADS_PER_TG * (tg_kIdOfGroup * BLOCK_SIZE + pIdOfGroup); \ - uint tg_kIdInGroup = (tg_kId - tg_kIdOfGroup) / 4; \ - uint pIdInGroup = (readPixelId - pIdOfGroup) / BLOCK_SIZE; \ - uint ldsOffsetInGroup = pIdInGroup * 2 + tg_kIdInGroup; \ - uint readIndex = ldsOffsetOfGroup + ldsOffsetInGroup; \ - uint writeChannelId = tg_KernelBaseId + tg_kId%4 + (tg_kId/4)*BLOCK_SIZE + tg_registerChannelOffset; \ - uint writeIndex = O.width * O.height * writeChannelId + writePixelId + tg_BatchWriteOffset; \ - O.FastSetWithActivation(writeIndex, LDS_[readIndex]); \ - } \ - } \ - } - WRITE_8CHANNELS_IF_POSSIBLE(0) - WRITE_8CHANNELS_IF_POSSIBLE(1) - WRITE_8CHANNELS_IF_POSSIBLE(2) - WRITE_8CHANNELS_IF_POSSIBLE(3) - #undef WRITE_8CHANNELS_IF_POSSIBLE - - GroupMemoryBarrierWithGroupSync(); - } - #else - //------------------------------- - //Directly store registers to DDR - //------------------------------- - //B does not require an offset as size == 1 - //C from tg_KernelBaseId, groupThreadID.x and tg_kId - //HW from tg_OutputPixelBaseId, groupThreadID.y and tg_pId - [unroll] for (tg_kId = 0; tg_kId < BLOCK_SIZE; ++tg_kId) - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - { - uint writeChannelId = tg_KernelBaseId + groupThreadID.x * BLOCK_SIZE + tg_kId; - uint writePixelId = tg_OutputPixelBaseId + groupThreadID.y * BLOCK_SIZE + tg_pId; - float writeValue = dstA[tg_pId*BLOCK_SIZE+tg_kId]; - #if CHANNELS_FIRST - uint writeIndex = O.width * O.height * writeChannelId + writePixelId + tg_BatchWriteOffset; - #else - uint writeIndex = tg_NumKernels * writePixelId + writeChannelId + tg_BatchWriteOffset; - #endif - #if LAX_KERNEL - bool canWriteChannel = (writeChannelId < tg_NumKernels); - #else - bool canWriteChannel = true; - #endif - if ((writePixelId < tg_NumOuputPixels) && canWriteChannel) - O.FastSetWithActivation(writeIndex, writeValue); - } - #endif - - #undef X_OFFSET - #undef W_OFFSET - #undef LDS_ - #undef X_ - #undef W_ -} -#undef CACHE_DEPTH -#undef PIXELS_READ_PER_THREAD_PER_CACHE -#undef PIXELS_PER_CACHE -#undef NUMTHREADS_PER_TG -#undef SHUFFLE_FOR_COALESCED_LOAD -#undef SHUFFLE_FOR_COALESCED_STORE -#endif //KERNEL_PER_TG == 16 - -#endif //BLOCK_SIZE == 8 - -#if BLOCK_SIZE == 4 -#define BUF_OFFSET 0 -#define CACHE_DEPTH 16 // This kernel code supports only CACHE_DEPTH=16, this value can not be changed -#define SHUFFLE_FOR_COALESCED_STORE 1 // Only implemented in CHW path. -groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS)[2*CACHE_DEPTH*16*BLOCK_SIZE+(1-CHANNELS_FIRST)*CACHE_DEPTH]; -[numthreads(16,16,1)] -void FUNC_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex) -{ - //DISPATCH ARGS(K.kernelCount, O.width * O.height * O.batch, 1); // in NHWC - //DISPATCH ARGS(K.kernelCount, O.width * O.height, O.batch); // in NCHW - - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - // [W*H, Ky*Kx*In] * [Ky*Kx*In, Out] => [W*H, Out] - #define LDS_ CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS) - #define X_OFFSET 0 - #define W_OFFSET CACHE_DEPTH*16*BLOCK_SIZE+(1-CHANNELS_FIRST)*CACHE_DEPTH - - int x = (int)dispatchThreadID.x * BLOCK_SIZE; // output_channels - int y = (int)dispatchThreadID.y * BLOCK_SIZE; // batch*width*height (width*height in HWC) - int tx = (int)groupThreadID.x; - int ty = (int)groupThreadID.y; - int bx = ((int)dispatchThreadID.x - (int)groupThreadID.x) * BLOCK_SIZE; - int by = ((int)dispatchThreadID.y - (int)groupThreadID.y) * BLOCK_SIZE; - int ti = (int)threadIndex; - uint w = O.width; - uint h = O.height; - int batches = X.batch; - int channels = X.channels; - int widthX = X.width; - int heightX = X.height; - int strideX = X.channels; - int strideK = K.channels; - int strideO = O.channels; - int offsetX = BUF_OFFSET; - int offsetK = BUF_OFFSET; - int offsetO = BUF_OFFSET; - #if CHANNELS_FIRST - uint batchReadOffset = dispatchThreadID.z * channels * heightX * widthX; - uint batchWriteOffset = dispatchThreadID.z * strideO * h * w; - uint3 groupID = (dispatchThreadID - groupThreadID) / uint3(16,16,1); - uint kernelBaseId = groupID.x * 64; - uint outputPixelBaseId = groupID.y * 64; - uint numOuputPixels = w * h; - #endif - - float4 dstA[4]; - int maxBiasIndex = O.channels - 1; - dstA[0].x = B.FastGet(min(maxBiasIndex, x+0)); dstA[0].y = B.FastGet(min(maxBiasIndex, x+1)); dstA[0].z = B.FastGet(min(maxBiasIndex, x+2)); dstA[0].w = B.FastGet(min(maxBiasIndex,x+3)); - dstA[1].x = B.FastGet(min(maxBiasIndex, x+0)); dstA[1].y = B.FastGet(min(maxBiasIndex, x+1)); dstA[1].z = B.FastGet(min(maxBiasIndex, x+2)); dstA[1].w = B.FastGet(min(maxBiasIndex,x+3)); - dstA[2].x = B.FastGet(min(maxBiasIndex, x+0)); dstA[2].y = B.FastGet(min(maxBiasIndex, x+1)); dstA[2].z = B.FastGet(min(maxBiasIndex, x+2)); dstA[2].w = B.FastGet(min(maxBiasIndex,x+3)); - dstA[3].x = B.FastGet(min(maxBiasIndex, x+0)); dstA[3].y = B.FastGet(min(maxBiasIndex, x+1)); dstA[3].z = B.FastGet(min(maxBiasIndex, x+2)); dstA[3].w = B.FastGet(min(maxBiasIndex,x+3)); - - int readK = strideK * (ti>>6) + bx + (ti&63) + offsetK; - #if STRICT_CHANNELS - #else - bool maskK = (bx + (ti&63)) < strideK; - #endif - -#if CHANNELS_FIRST - uint centroidId = by + (ti&63); - #if KERNEL_1x1 - int readX = heightX * widthX * (ti>>6) + centroidId + batchReadOffset; - bool mask = centroidId < uint(widthX * heightX); - #else - int batch = 0;//not needed dispatched over batches. - int topY = (centroidId / w % h) * _Stride.y - _Pad.y; - int leftX = (centroidId % w) * _Stride.x - _Pad.x; - int cornerId = batch * heightX * widthX + topY * widthX + leftX; - int readX = heightX * widthX * (ti>>6) + cornerId + batchReadOffset; - bool mask; - #endif -#else - uint4 centroidId = uint4( - (by + (ti>>4) + 0), - (by + (ti>>4) + 16), - (by + (ti>>4) + 32), - (by + (ti>>4) + 48)); - #if KERNEL_1x1 - int4 readX = strideX * centroidId + (ti&15); - bool4 mask = centroidId < uint(batches * widthX * heightX); - #else - int4 batch = centroidId / w / h; - int4 topY = (centroidId / w % h) * _Stride.y - _Pad.y; - int4 leftX = (centroidId % w) * _Stride.x - _Pad.x; - int4 cornerId = batch * heightX * widthX + topY * widthX + leftX; - int4 readX = strideX * cornerId + (ti&15); - bool4 mask; - #endif -#endif - -#if KERNEL_1x1 - { - { -#else - for (int dy = 0; dy < (int)K.GetKernelHeight(); dy++) - { - for (int dx = 0; dx < (int)K.GetKernelWidth(); dx++) - { - #if CHANNELS_FIRST - int kernelOffsetX = (dy * widthX + dx); - #else - int kernelOffsetX = (dy * widthX + dx) * strideX; - #endif - mask = - batch < batches && - topY + dy >= 0 && - topY + dy < heightX && - leftX + dx >= 0 && - leftX + dx < widthX; - - // 256 threads (256=numthreads(16,16,1)=16*16*1) are communally loading - // blocks of 64pixels x 16channels from the global memory - // - // One block is read from X and one from K tensor - // 4 reads with 256 threads (4=64*16/256) are necessary for each block - -#endif // KERNEL_1x1 - for (int i = 0; i < channels; i += CACHE_DEPTH) - { - #if STRICT_CHANNELS - #else - if (i + CACHE_DEPTH > channels) - { - int channelRemainder = channels - i; - [unroll] for (int j = 0; j < 4; ++j) - { - bool maskChannelsK = ti < 64 * (channelRemainder - j * 4); - bool maskChannelsX = - #if CHANNELS_FIRST - maskChannelsK; - #else - (ti&15) < channelRemainder; - #endif - - LDS_[W_OFFSET + ((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2) + 256*j] = K.MaskedGet(maskK & maskChannelsK, readK); - readK += strideK * max(0, min(channelRemainder - j * 4, 4)); - - #if CHANNELS_FIRST - LDS_[X_OFFSET + ti + 256*j] = - #if KERNEL_1x1 - X.MaskedGet(mask && maskChannelsX, readX + heightX * widthX * (i + j * 4) + offsetX); - #else - X.MaskedGet(mask && maskChannelsX, readX + heightX * widthX * (i + j * 4) + kernelOffsetX + offsetX); - #endif - #else - LDS_[X_OFFSET + (ti>>4) + 65*(ti&15) + 16*j] = - #if KERNEL_1x1 - X.MaskedGet(mask[j] && maskChannelsX, readX[j] + i + offsetX); - #else - X.MaskedGet(mask[j] && maskChannelsX, readX[j] + i + kernelOffsetX + offsetX); - #endif - #endif - } - } - else - #endif - [unroll] for (int j = 0; j < 4; ++j) - { - LDS_[W_OFFSET + ((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2) + 256*j] = - #if STRICT_CHANNELS - K.data[readK]; - #else - K.MaskedGet(maskK, readK); - #endif - readK += strideK * 4; - - #if CHANNELS_FIRST - LDS_[X_OFFSET + ti + 256*j] = - #if KERNEL_1x1 - X.MaskedGet(mask, readX + heightX * widthX * (i + j * 4) + offsetX); - #else - X.MaskedGet(mask, readX + heightX * widthX * (i + j * 4) + kernelOffsetX + offsetX); - #endif - #else - LDS_[X_OFFSET + (ti>>4) + 65*(ti&15) + 16*j] = - #if KERNEL_1x1 - X.MaskedGet(mask[j], readX[j] + i + offsetX); - #else - X.MaskedGet(mask[j], readX[j] + i + kernelOffsetX + offsetX); - #endif - #endif - - #if DEBUG_CHECK_BOUNDS - if ( - #if KERNEL_1x1 - (readX[j] + i + offsetX < 0) || - (readX[j] + i + offsetX >= (int)X.GetLength()) - #else - (mask[j] && readX[j] + i + kernelOffsetX + offsetX < 0) || - (mask[j] && readX[j] + i + kernelOffsetX + offsetX >= (int)X.GetLength()) - #endif - ) - { - // swamp X cache with dummy values when reading out of buffer - // this way we can detect out of buffer reads by comparing results from this kernel - // with the the reference implementation results - for (int q = 0; q < CACHE_DEPTH*16*BLOCK_SIZE+(1-CHANNELS_FIRST)*CACHE_DEPTH; ++q) - LDS_[X_OFFSET + q] = -1.0; - } - #endif - } - - GroupMemoryBarrierWithGroupSync(); - - int4 idX = int4(0,1,2,3); - int4 idW = int4(0,16,32,48); - int incX = 64 + (1-CHANNELS_FIRST); - int incW = 64; - - for (int di = 0; di < CACHE_DEPTH; di++) - { - float4 srcX = float4( - LDS_[X_OFFSET + idX.x + ty*4], - LDS_[X_OFFSET + idX.y + ty*4], - LDS_[X_OFFSET + idX.z + ty*4], - LDS_[X_OFFSET + idX.w + ty*4]); - float4 srcW = float4( - LDS_[W_OFFSET + idW.x + tx], - LDS_[W_OFFSET + idW.y + tx], - LDS_[W_OFFSET + idW.z + tx], - LDS_[W_OFFSET + idW.w + tx] - ); - idX += incX; - idW += incW; - - dstA[0].x = ffma(srcX.x, srcW.x, dstA[0].x); - dstA[0].y = ffma(srcX.x, srcW.y, dstA[0].y); - dstA[0].z = ffma(srcX.x, srcW.z, dstA[0].z); - dstA[0].w = ffma(srcX.x, srcW.w, dstA[0].w); - - dstA[1].x = ffma(srcX.y, srcW.x, dstA[1].x); - dstA[1].y = ffma(srcX.y, srcW.y, dstA[1].y); - dstA[1].z = ffma(srcX.y, srcW.z, dstA[1].z); - dstA[1].w = ffma(srcX.y, srcW.w, dstA[1].w); - - dstA[2].x = ffma(srcX.z, srcW.x, dstA[2].x); - dstA[2].y = ffma(srcX.z, srcW.y, dstA[2].y); - dstA[2].z = ffma(srcX.z, srcW.z, dstA[2].z); - dstA[2].w = ffma(srcX.z, srcW.w, dstA[2].w); - - dstA[3].x = ffma(srcX.w, srcW.x, dstA[3].x); - dstA[3].y = ffma(srcX.w, srcW.y, dstA[3].y); - dstA[3].z = ffma(srcX.w, srcW.z, dstA[3].z); - dstA[3].w = ffma(srcX.w, srcW.w, dstA[3].w); - } - - GroupMemoryBarrierWithGroupSync(); - } - } - } - - #if SHUFFLE_FOR_COALESCED_STORE && CHANNELS_FIRST && STRICT_CHANNELS - //----------------------------------------------------- - //Use LDS to shuffle TG registers into coalesced writes - //----------------------------------------------------- - //A TG output [64pixels,64channels] = 4096 values. We will process [32,64] values at a time per TG. - for (uint tg_registerChannelOffset = 0; tg_registerChannelOffset < BLOCK_SIZE; tg_registerChannelOffset += 2) - { - uint tg_kId; - uint tg_pId; - //Store 4 pixels x 2 channels per threads to LDS. - uint ldsRowOffset = groupThreadID.x * 2; - uint ldsPixelOffset = groupThreadID.y * BLOCK_SIZE; - [unroll] for (tg_kId = 0; tg_kId < 2; ++tg_kId) - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - { - LDS_[64 * (groupThreadID.x * 2 + tg_kId) + ldsPixelOffset + tg_pId] = dstA[tg_pId][tg_registerChannelOffset + tg_kId]; - } - - GroupMemoryBarrierWithGroupSync(); - - //We have a buffers of [64pixels,32channels] floats, each thread will store [1pixels,8channels] so a threadgroup is storing 64 pixels and 4 channels at a time to DDR in a linear fashion. - uint readPixelId = threadIndex % 64; - uint writePixelId = outputPixelBaseId + readPixelId; - - if (writePixelId < numOuputPixels) - { - [unroll] for (tg_kId = 0; tg_kId < 32; tg_kId+=4) - { - uint readChannelId = tg_kId + threadIndex / 64; - uint readIndex = 64 * readChannelId + readPixelId; - uint writeChannelId = kernelBaseId + readChannelId%2 + (readChannelId/2)*BLOCK_SIZE + tg_registerChannelOffset; - O.FastSetWithActivation(h*w* writeChannelId + writePixelId + offsetO + batchWriteOffset, LDS_[readIndex]); - } - } - - GroupMemoryBarrierWithGroupSync(); - } - #else - #if CHANNELS_FIRST - [unroll] for (int sy = 0; sy < 4 && y+sy < (int)w * (int)h; ++sy) - [unroll] for (int sx = 0; sx < 4 && x+sx < strideO; ++sx) - O.FastSetWithActivation(h*w* (x+sx) + (y+sy) + offsetO + batchWriteOffset, dstA[sy][sx]); - #else - [unroll] for (int sy = 0; sy < 4 && y+sy < (int)w * (int)h * (int)O.batch; ++sy) - [unroll] for (int sx = 0; sx < 4 && x+sx < strideO; ++sx) - O.FastSetWithActivation(strideO * (y+sy) + x+sx + offsetO, dstA[sy][sx]); - #endif - #endif - - - #undef X_ - #undef W_ - #undef LDS_ - #undef X_OFFSET - #undef W_OFFSET -} -#undef CACHE_DEPTH -#undef BUF_OFFSET -#endif -#undef KERNEL_NAME - -NUMTHREADS((16,4,4), (8,4,4), (4,4,4)) -void KERNEL_FUNC(Conv2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint2 leftCorner = _Pad.xy; - uint2 rightCorner = uint2(X.width, X.height) + _Pad.xy; - for (uint n = 0; n < O.batch; ++n) - { - float acc = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - { - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos = uint2(x, y) * _Stride.xy + uint2(dx, dy); - - for (uint c = 0; c < X.channels; ++c) - { - float v = 0; - - // WARNING: Mali-G71 performance drops 4x if this branching includes storing accumulator - if (!any(pos < leftCorner) && !any(pos >= rightCorner)) - v = X.Get(n, pos.y - leftCorner.y, pos.x - leftCorner.x, c); - //acc = fastfma(v, K.Get(dy, dx, c, k), acc); - acc += v * K.Get(dy, dx, c, k); - } - } - } - - O.SetWithActivation(n, y, x, k, acc); - } -} - - -#define SIZE_W 4 -#define SIZE_H 2 -NUMTHREADS((64, 2, 2), (32, 2, 2), (16, 2, 2)) -void KERNEL_FUNC(Conv2D_RegisterBlock4x2)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x*SIZE_W >= O.width) return; - if (y*SIZE_H >= O.height) return; - - uint2 leftCorner = _Pad.xy; - uint2 rightCorner = uint2(X.width, X.height) + _Pad.xy; - for (uint n = 0; n < O.batch; ++n) - { - float acc[SIZE_H*SIZE_W]; - uint q; - [unroll] - for (q = 0; q < SIZE_H*SIZE_W; ++q) - acc[q] = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - { - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos[SIZE_H*SIZE_W]; - [unroll] - for (q = 0; q < SIZE_H*SIZE_W; ++q) - pos[q] = uint2(x*SIZE_W+(q%SIZE_W), y*SIZE_H+(q/SIZE_W)) * _Stride.xy + uint2(dx, dy); - - for (uint c = 0; c < X.channels; ++c) - [unroll] - for (q = 0; q < SIZE_H*SIZE_W; ++q) - if (all(pos[q] >= leftCorner) && all(pos[q] < rightCorner)) - acc[q] = fastfma(X.Get(n, pos[q] - leftCorner, c), K.Get(dy, dx, c, k), acc[q]); - } - } - - [unroll] - for (q = 0; q < SIZE_H*SIZE_W; ++q) - O.SetWithActivation(n, y*SIZE_H+(q/SIZE_W), x*SIZE_W+(q%SIZE_W), k, acc[q]); - } -} -#undef SIZE_W -#undef SIZE_H - -//DISPATCH ARGS(K.kernelCount, O.width, O.height); -#define CONV2D_L1CACHED(L1CACHESIZE, SIZE, FMA) \ -groupshared float Conv2D_L1Cached##L1CACHESIZE##_Reg_Loop_safe_X[SIZE*SIZE][L1CACHESIZE];\ -[numthreads(L1CACHESIZE, 1, 1)]\ -void KERNEL_FUNC(Conv2D_L1Cached##L1CACHESIZE##_RegisterBlock##SIZE##x##SIZE)(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID)\ -{\ - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O);\ -\ - uint k = L1CACHESIZE * groupID.x + groupThreadID.x;\ - uint x = groupID.y;\ - uint y = groupID.z;\ -\ - if (x*SIZE >= O.width) return;\ - if (y*SIZE >= O.height) return;\ -\ - for (uint n = 0; n < O.batch; ++n)\ - {\ - float acc[SIZE*SIZE];\ - uint q;\ - [unroll]\ - for (q = 0; q < SIZE*SIZE; ++q)\ - acc[q] = B.SafeGet(k);\ -\ - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy)\ - {\ - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx)\ - {\ - uint2 pos[SIZE*SIZE];\ - [unroll]\ - for (q = 0; q < SIZE*SIZE; ++q)\ - pos[q] = uint2(x*SIZE+(q%SIZE), y*SIZE+(q/SIZE)) * _Stride.xy + uint2(dx, dy);\ -\ - for (uint c = 0; c < X.channels; c += L1CACHESIZE)\ - {\ - uint dc = groupThreadID.x;\ - [unroll]\ - for (q = 0; q < SIZE*SIZE; ++q)\ - Conv2D_L1Cached##L1CACHESIZE##_Reg_Loop_safe_X[q][dc] = X.SafeGet(n, pos[q], c + dc, _Pad.xy);\ - GroupMemoryBarrierWithGroupSync();\ -\ - if (k < K.channels)\ - {\ - uint kIndex = K.IndexHWC(dy, dx, c, k);\ - for (dc = 0; dc < L1CACHESIZE; ++dc)\ - {\ - [unroll]\ - for (q = 0; q < SIZE*SIZE; ++q)\ - acc[q] = FMA(Conv2D_L1Cached##L1CACHESIZE##_Reg_Loop_safe_X[q][dc], K.data[kIndex], acc[q]);\ - kIndex += K.channels;\ - }\ - }\ - GroupMemoryBarrierWithGroupSync();\ - }\ - }\ - }\ -\ - uint remainderW = (O.width - x*SIZE);\ - uint remainderH = (O.height - y*SIZE);\ -\ - if (k < K.channels)\ - [unroll]\ - for (q = 0; q < SIZE*SIZE; ++q)\ - if (q/SIZE < remainderH && q%SIZE < remainderW)\ - O.SetWithActivation(n, y*SIZE+(q/SIZE), x*SIZE+(q%SIZE), k, acc[q]);\ - }\ -\ -} - -CONV2D_L1CACHED(64,4, fastfma) -CONV2D_L1CACHED(32,4, fastfma) - - -// IDEA: iterate over channels in the inner loop - needs channels first layout -NUMTHREADS((16,4,4), (8,4,4), (4,4,4)) -void KERNEL_FUNC(DepthwiseConv2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint2 leftCorner = _Pad.xy; - uint2 rightCorner = uint2(X.width, X.height) + _Pad.xy; - - uint2 leftKernelCorner = uint2(x, y) * _Stride.xy; - uint2 rightKernelCorner = leftKernelCorner + uint2(K.GetKernelWidth(), K.GetKernelHeight()); - - if (any(leftKernelCorner < leftCorner) || any(rightKernelCorner >= rightCorner)) - { - // path with edge-cases checks - for (uint n = 0; n < O.batch; ++n) - { - float acc = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos = leftKernelCorner + uint2(dx, dy); - if (any(pos < leftCorner)) continue; - if (any(pos >= rightCorner)) continue; - - acc = fastfma( - X.Get(n, pos.y - leftCorner.y, pos.x - leftCorner.x, k), - K.Get(dy, dx, 0, k), - acc); - } - - O.SetWithActivation(n, y, x, k, acc); - } - } - else - { - // kernel is guaranteed to be within X, - // no need to check against edge-cases - leftKernelCorner -= leftCorner; - for (uint n = 0; n < O.batch; ++n) - { - float acc = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos = leftKernelCorner + uint2(dx, dy); - - acc = fastfma( - X.Get(n, pos, k), - K.Get(dy, dx, 0, k), - acc); - } - - O.SetWithActivation(n, y, x, k, acc); - } - } -} - - -NUMTHREADS((16, 4, 4), (8, 4, 4), (4, 4, 4)) -void Conv2DTransFlipKernel(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_SHARED_MODEL(K, WBK); TENSOR_SHARED_MODEL(B, WBK); TENSOR_ARG_RW(O) - - uint k = dispatchThreadID.x; - uint c = dispatchThreadID.y; - uint z = dispatchThreadID.z; // x + KWidth * y - - uint x = z % K.GetKernelWidth(); - uint y = z / K.GetKernelWidth(); - - if (c >= K.GetKernelDepth()) return; - if (k >= K.GetKernelCount()) return; - if (z >= K.GetKernelHeight() * K.GetKernelWidth()) return; - - float v = K.Get(K.GetKernelHeight() - 1 - y, K.GetKernelWidth() - 1 - x, c, k); - O.Set(y, x, c, k, v); - O.FastSet(K.GetLength() + k, B.FastGet(k)); -} - -NUMTHREADS((16, 4, 4), (8, 4, 4), (4, 4, 4)) -void KERNEL_FUNC(Conv2DTransPadFill)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= X.channels) return; - if (x >= X.width) return; - if (y >= X.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - uint ox = x * _Stride.x; - uint oy = y * _Stride.y; - - uint strideX = x == (X.width - 1) ? _Pad.x + 1 : _Stride.x; - uint strideY = y == (X.height - 1) ? _Pad.y + 1 : _Stride.y; - - for (uint dx = 0; dx < strideX; dx++) - for (uint dy = 0; dy < strideY; dy++) - { - O.Set(n, oy + dy, ox + dx, c, 0.0f); - } - float v = X.Get(n, y, x, c); - O.Set(n, oy, ox, c, v); - } -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(Conv2DTrans)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint strideH = 1; - uint strideW = 1; - - for (uint n = 0; n < O.batch; ++n) - { - float acc = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); dy += strideH) - { - for (uint dx = 0; dx < K.GetKernelWidth(); dx += strideW) - { - uint readX = (x + dx - _Pad.x) / _Stride.x; - uint readY = (y + dy - _Pad.y) / _Stride.y; - - if (any(uint2(x + dx, y + dy) < _Pad.xy)) continue; - if (any(uint2(readX, readY) >= uint2(X.width, X.height))) continue; - if (any(uint2(x + dx - _Pad.x, y + dy - _Pad.y) % _Stride.xy != 0)) continue; - - for (uint c = 0; c < X.channels; ++c) - { - acc = fastfma( X.Get(n, readY, readX, c), - K.Get( K.GetKernelHeight() - 1 - dy, - K.GetKernelWidth() - 1 - dx, c, k), - acc); - } - } - } - - O.SetWithActivation(n, y, x, k, acc); - } -} - -#if defined(MAX_KERNEL_SIZE) && defined(GROUP_SIZE_X) && defined(GROUP_SIZE_Y) - -#if CHANNELS_FIRST - #define CONV2DTRANS_NAME_CALL(KERNEL,TGX,TGY) Conv2DTrans_KernelCached_K##KERNEL##x##KERNEL##_T##TGX##x##TGY##_NCHW -#else - #define CONV2DTRANS_NAME_CALL(KERNEL,TGX,TGY) Conv2DTrans_KernelCached_K##KERNEL##x##KERNEL##_T##TGX##x##TGY##_NHWC -#endif -#define CONV2DTRANS_NAME(KERNEL,TGX,TGY) CONV2DTRANS_NAME_CALL(KERNEL,TGX,TGY) -groupshared float Conv2DTrans_SharedKernel[MAX_KERNEL_SIZE][MAX_KERNEL_SIZE][GROUP_SIZE_X*GROUP_SIZE_Y]; -groupshared float Conv2DTrans_SharedBias; -[numthreads(1,GROUP_SIZE_X,GROUP_SIZE_Y)] -void CONV2DTRANS_NAME(MAX_KERNEL_SIZE, GROUP_SIZE_X,GROUP_SIZE_Y)(uint3 dispatchThreadID : SV_DispatchThreadID, uint groupIndex: SV_GroupIndex) -{ - //Constraints: - // C <= GROUP_SIZE_X*GROUP_SIZE_Y - // K <= MAX_KERNEL_SIZExMAX_KERNEL_SIZE - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - //Dispatch organisation: - // a thread = write to [:,y,x,k] ie all batch but a single 2d pos and feature. - // a thread group = handle 1 feature in a GROUP_SIZExGROUP_SIZE x,y region, it loop other all batch, input channel count need to be <= GROUP_SIZE*GROUP_SIZE - - //LDS allocation - // we have 1 feature and up to GROUP_SIZE_X*GROUP_SIZE_Y channels per thread group, batch all use the same kernels, - // thus LDS is [MAX_KERNEL_SIZE][MAX_KERNEL_SIZE][GROUP_SIZE_X*GROUP_SIZE_Y] - - //Loading to LDS - // Each threads load a 2D kernel for a different channel into LDS - for(uint dy = 0; dy < K.GetKernelWidth(); ++dy) - { - for(uint dx = 0; dx < K.GetKernelHeight(); ++dx) - { - uint channelToLoadIndex = groupIndex; - if((channelToLoadIndex < X.channels) && (k < K.channels)) - Conv2DTrans_SharedKernel[dy][dx][channelToLoadIndex] = K.Get(K.GetKernelHeight() - 1 - dy,K.GetKernelWidth() - 1 - dx, channelToLoadIndex, k); - } - } - // first thread also load bias to LDS - if (groupIndex == 0) - Conv2DTrans_SharedBias = B.FastGet(k); - - //Wait for all load to complete - GroupMemoryBarrierWithGroupSync(); - - // Outside of target tensor, nothing to write to or compute exit. - if (x >= O.width) return; - if (y >= O.height) return; - if (k >= K.channels) return; - - uint strideH = 1; - uint strideW = 1; - - // Apply kernels from LDS to all batches and write result out (per batch as input differ) - uint2 strideMask = _Stride.xy - 1; - for (uint n = 0; n < O.batch; ++n) - { - float acc = Conv2DTrans_SharedBias; - for (uint dy = 0; dy < K.GetKernelHeight(); dy += strideH) - { - for (uint dx = 0; dx < K.GetKernelWidth(); dx += strideW) - { - uint readX = (x + dx - _Pad.x) / _Stride.x; - uint readY = (y + dy - _Pad.y) / _Stride.y; - - if (any(uint2(x + dx, y + dy) < _Pad.xy)) continue; - if (any(uint2(readX, readY) >= uint2(X.width, X.height))) continue; - if (any(uint2(x + dx - _Pad.x, y + dy - _Pad.y) % _Stride.xy != 0)) continue; - - for (uint c = 0; c < X.channels; ++c) - { - acc = fastfma(X.Get(n, readY, readX, c), - Conv2DTrans_SharedKernel[dy][dx][c], - acc); - } - } - } - O.SetWithActivation(n, y, x, k, acc); - } -} -#undef CONV2DTRANS_NAME -#endif //defined(MAX_KERNEL_SIZE) && defined(GROUP_SIZE_X) && defined(GROUP_SIZE_Y) - - - - -// https://github.com/andravin/wincnn -// https://arxiv.org/pdf/1509.09308.pdf -// Winograd: 4x4 image, 3x3 kernel, 2x2 output -static const float4x3 Winograd_G = float4x3(float3(1, 0, 0), float3(0.5, 0.5, 0.5), float3(0.5, -0.5, 0.5), float3(0, 0, 1)); -static const float3x4 Winograd_GT = transpose(Winograd_G); - -NUMTHREADS((16, 4, 4), (8, 4, 4), (4, 4, 4)) -void KernelWinograd_3x3(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_SHARED_MODEL(K, WBK); TENSOR_SHARED_MODEL(B, WBK); TENSOR_ARG_RW(O) - - uint k = dispatchThreadID.x; - uint c = dispatchThreadID.y; - uint i = dispatchThreadID.z; - - if (c >= K.GetKernelDepth()) return; - if (k >= K.GetKernelCount()) return; - - float3x3 g; - g[0][0] = K.Get(0, 0, c, k); - g[0][1] = K.Get(0, 1, c, k); - g[0][2] = K.Get(0, 2, c, k); - g[1][0] = K.Get(1, 0, c, k); - g[1][1] = K.Get(1, 1, c, k); - g[1][2] = K.Get(1, 2, c, k); - g[2][0] = K.Get(2, 0, c, k); - g[2][1] = K.Get(2, 1, c, k); - g[2][2] = K.Get(2, 2, c, k); - - float4x4 v = mul(Winograd_G, mul(g, Winograd_GT)); - - O.Set(0, 0, c, k, v[0][0]); - O.Set(1, 0, c, k, v[1][0]); - O.Set(2, 0, c, k, v[2][0]); - O.Set(3, 0, c, k, v[3][0]); - O.Set(0, 1, c, k, v[0][1]); - O.Set(1, 1, c, k, v[1][1]); - O.Set(2, 1, c, k, v[2][1]); - O.Set(3, 1, c, k, v[3][1]); - O.Set(0, 2, c, k, v[0][2]); - O.Set(1, 2, c, k, v[1][2]); - O.Set(2, 2, c, k, v[2][2]); - O.Set(3, 2, c, k, v[3][2]); - O.Set(0, 3, c, k, v[0][3]); - O.Set(1, 3, c, k, v[1][3]); - O.Set(2, 3, c, k, v[2][3]); - O.Set(3, 3, c, k, v[3][3]); - - uint kLength = (K.GetKernelHeight() + 1) * (K.GetKernelWidth() + 1) * K.GetKernelDepth() * K.GetKernelCount(); - if (i < B.GetLength()) - O.FastSet(kLength + i, B.FastGet(i)); -} - -float4x4 ApplyWinnogradB(float4x4 d) -{ - // BT x u x B, used mathematica to express the operation using only +/- - //return float4x4(float4( d[0][0] - d[0][2] - d[2][0] + d[2][2], d[0][1] + d[0][2] - d[2][1] - d[2][2], -d[0][1] + d[0][2] + d[2][1] - d[2][2], -d[0][1] + d[0][3] + d[2][1] - d[2][3]), - // float4( d[1][0] - d[1][2] + d[2][0] - d[2][2], d[1][1] + d[1][2] + d[2][1] + d[2][2], -d[1][1] + d[1][2] - d[2][1] + d[2][2], -d[1][1] + d[1][3] - d[2][1] + d[2][3]), - // float4(-d[1][0] + d[1][2] + d[2][0] - d[2][2], -d[1][1] - d[1][2] + d[2][1] + d[2][2], d[1][1] - d[1][2] - d[2][1] + d[2][2], d[1][1] - d[1][3] - d[2][1] + d[2][3]), - // float4(-d[1][0] + d[1][2] + d[3][0] - d[3][2], -d[1][1] - d[1][2] + d[3][1] + d[3][2], d[1][1] - d[1][2] - d[3][1] + d[3][2], d[1][1] - d[1][3] - d[3][1] + d[3][3]) - // ); - // re-order operations to lower register pressure - float4x4 TU; - float4x4 U; - TU[0][0] = d[0][0] - d[2][0]; - TU[0][1] = d[0][1] - d[2][1]; - TU[0][2] = d[0][2] - d[2][2]; - TU[0][3] = d[0][3] - d[2][3]; - - TU[1][0] = d[1][0] + d[2][0]; - TU[1][1] = d[1][1] + d[2][1]; - TU[1][2] = d[1][2] + d[2][2]; - TU[1][3] = d[1][3] + d[2][3]; - - TU[2][0] = d[2][0] - d[1][0]; - TU[2][1] = d[2][1] - d[1][1]; - TU[2][2] = d[2][2] - d[1][2]; - TU[2][3] = d[2][3] - d[1][3]; - - TU[3][0] = d[3][0] - d[1][0]; - TU[3][1] = d[3][1] - d[1][1]; - TU[3][2] = d[3][2] - d[1][2]; - TU[3][3] = d[3][3] - d[1][3]; - - - U[0][0] = TU[0][0] - TU[0][2]; - U[0][1] = TU[0][1] + TU[0][2]; - U[0][2] = TU[0][2] - TU[0][1]; - U[0][3] = TU[0][3] - TU[0][1]; - - U[1][0] = TU[1][0] - TU[1][2]; - U[1][1] = TU[1][1] + TU[1][2]; - U[1][2] = TU[1][2] - TU[1][1]; - U[1][3] = TU[1][3] - TU[1][1]; - - U[2][0] = TU[2][0] - TU[2][2]; - U[2][1] = TU[2][1] + TU[2][2]; - U[2][2] = TU[2][2] - TU[2][1]; - U[2][3] = TU[2][3] - TU[2][1]; - - U[3][0] = TU[3][0] - TU[3][2]; - U[3][1] = TU[3][1] + TU[3][2]; - U[3][2] = TU[3][2] - TU[3][1]; - U[3][3] = TU[3][3] - TU[3][1]; - - return U; -} - -float2x2 ApplyWinnogradA(float4x4 uv) -{ - // A x u x A, used mathematica to express the operation using only +/- - // return float2x2(float2(uv[0][0] + uv[0][1] + uv[0][2] + uv[1][0] + uv[1][1] + uv[1][2] + uv[2][0] + uv[2][1] + uv[2][2], uv[0][1] - uv[0][2] + uv[0][3] + uv[1][1] - uv[1][2] + uv[1][3] + uv[2][1] - uv[2][2] + uv[2][3]), - // float2(uv[1][0] + uv[1][1] + uv[1][2] - uv[2][0] - uv[2][1] - uv[2][2] + uv[3][0] + uv[3][1] + uv[3][2], uv[1][1] - uv[1][2] + uv[1][3] - uv[2][1] + uv[2][2] - uv[2][3] + uv[3][1] - uv[3][2] + uv[3][3]) - // ); - // re-order operations to lower register pressure - float2x4 TY; - float2x2 Y; - TY[0][0] = uv[0][0] + uv[0][1] + uv[0][2]; - TY[0][1] = uv[1][0] + uv[1][1] + uv[1][2]; - TY[0][2] = uv[2][0] + uv[2][1] + uv[2][2]; - TY[0][3] = uv[3][0] + uv[3][1] + uv[3][2]; - - TY[1][0] = uv[0][1] - uv[0][2] + uv[0][3]; - TY[1][1] = uv[1][1] - uv[1][2] + uv[1][3]; - TY[1][2] = uv[2][1] - uv[2][2] + uv[2][3]; - TY[1][3] = uv[3][1] - uv[3][2] + uv[3][3]; - - - Y[0][0] = TY[0][0] + TY[0][1] + TY[0][2]; - Y[0][1] = TY[1][0] + TY[1][1] + TY[1][2]; - Y[1][0] = TY[0][1] - TY[0][2] + TY[0][3]; - Y[1][1] = TY[1][1] - TY[1][2] + TY[1][3]; - - return Y; -} - -#undef KERNEL_NAME -#undef FUNC_NAME_CALL -#undef CACHE_NAME_CALL -#undef FUNC_NAME -#undef CACHE_NAME - -#define KERNEL_NAME Conv2DWinograd_2x2_ -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE_K, SIZE_X) KERNEL##SUFFIX##SIZE_K##x##SIZE_X##_NCHW - #define CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE_K, SIZE_X, TENSOR) KERNEL##SUFFIX##SIZE_K##x##SIZE_X##_Cache_##TENSOR##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE_K, SIZE_X) KERNEL##SUFFIX##SIZE_K##x##SIZE_X##_NHWC - #define CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE_K, SIZE_X, TENSOR) KERNEL##SUFFIX##SIZE_K##x##SIZE_X##_Cache_##TENSOR##_NHWC -#endif -#define FUNC_NAME(KERNEL, SUFFIX, SIZE_K, SIZE_X) FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE_K, SIZE_X) -#define CACHE_NAME(KERNEL, SUFFIX, SIZE_K, SIZE_X, TENSOR) CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE_K, SIZE_X, TENSOR) - -#if BLOCK_SIZE == 4 -#if KERNEL_PER_TG == 16 -//NCHW -#define CACHE_DEPTH 8 - -#define CACHE_WIDTH_X 16 -#define CACHE_WIDTH_W 16 - - -groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, BLOCK_SIZE, LDS)[4576]; - - -[numthreads(256, 1, 1)] -void FUNC_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, BLOCK_SIZE)(uint3 groupID : SV_GroupID, uint threadIndexGlobal : SV_GroupIndex) -{ - //This kernel assume the following: - //Input: - //Ouput: - //Kernel: - //DISPATCH ARGS(K.kernelCount, O.width * O.height, O.batch); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); -#define LDS_ CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, BLOCK_SIZE, LDS) -#define X_OFFSET 0 -#define W_OFFSET 16*CACHE_DEPTH*CACHE_WIDTH_X - - //Per thread group (scalar registers) - uint tg_NumChannels = X.channels; - uint tg_WidthX = X.width; - uint tg_HeightX = X.height; - uint tg_WidthO = O.width; - uint tg_HeightO = O.height; - uint tg_WidthOHalf = (tg_WidthO + 1) / 2; - uint tg_NumKernels = K.channels; - uint tg_NumInputPixels = tg_WidthX * tg_HeightX; - uint tg_NumOuputPixels = tg_WidthO * tg_HeightO; - uint tg_KernelSpatialStride = tg_NumKernels * tg_NumChannels; - uint tg_KernelBaseId = groupID.x * CACHE_WIDTH_W; - uint tg_OutputPixelBaseId = groupID.y * CACHE_WIDTH_X; - uint tg_BatchReadOffset = groupID.z * tg_NumChannels * tg_HeightX * tg_WidthX; - uint tg_BatchWriteOffset = groupID.z * tg_NumKernels * tg_HeightO * tg_WidthO; - - // output per TG: 4 pixels x 4 features x 4x4 threads x (2x2 pixel blocks) => 64 pixels x 16 features - // LDS is 256 * 4x4 in order to hold 256 (8 * 4 * 4 x 2) patches of 4x4 for inverse winograd transform of X and W - // 16 (4x4 parallel matmuls) * 8 (cache_depth) * 2 (K and X) * 16 (4x4 block) - - // threadIndex4x4 = threadIndexGlobal/16 : 16 SGEM (4x4 patch of X) in parallel - // threadIndex = threadIndexGlobal%16 : 4x4 threads for one SGEM, this is divided into pixels and features (groupThreadIDY = threadIndex/4, groupThreadIDX = threadIndex%4) - uint threadIndex4x4 = (threadIndexGlobal >> 4); - uint threadIndex = (threadIndexGlobal & 0xf); - uint groupThreadIDY4 = (threadIndexGlobal & 0xc); // groupThreadIDY * 4 - uint groupThreadIDX4 = ((threadIndexGlobal & 0x3) << 2); // groupThreadIDX * 4 - - // 4x4 block, 4 kernels by 4 pixels - //********************************** - //* Kernel Ids * 0 1 2 3 ... - //********************************** - // * ThreadIds - // Pixel Ids 0 * 0 1 2 3 - // 1 * 8 9 10 11 - // 2 * 16 17 18 19 - // 3 * 32 33 34 35 - float dstA[BLOCK_SIZE*BLOCK_SIZE]; - - // Load Bias [K] int dstA [Kernels, Pixels] - dstA[0*BLOCK_SIZE + 0] = 0; - dstA[0*BLOCK_SIZE + 1] = 0; - dstA[0*BLOCK_SIZE + 2] = 0; - dstA[0*BLOCK_SIZE + 3] = 0; - dstA[1*BLOCK_SIZE + 0] = 0; - dstA[1*BLOCK_SIZE + 1] = 0; - dstA[1*BLOCK_SIZE + 2] = 0; - dstA[1*BLOCK_SIZE + 3] = 0; - dstA[2*BLOCK_SIZE + 0] = 0; - dstA[2*BLOCK_SIZE + 1] = 0; - dstA[2*BLOCK_SIZE + 2] = 0; - dstA[2*BLOCK_SIZE + 3] = 0; - dstA[3*BLOCK_SIZE + 0] = 0; - dstA[3*BLOCK_SIZE + 1] = 0; - dstA[3*BLOCK_SIZE + 2] = 0; - dstA[3*BLOCK_SIZE + 3] = 0; - - - for (uint tg_ChannelOffset = 0; tg_ChannelOffset < tg_NumChannels; tg_ChannelOffset += CACHE_DEPTH) - { - // Load from DDR to LDS: 1 SGEMM : (4*4 weight + 4*4 pixel) * CACHE_DEPTH => 1024 Bytes - // => x16 SGEMM = 16384 Bytes - // Storing in registers to avoid sync inside the loop. - // LOAD W and X in registers and perform Winograd transform - if (threadIndexGlobal < 128) // threadIndex4x4 < 8 - { - uint threadIndexHigh = threadIndex4x4; - - float4x4 tempX; - uint tg_Dy; - uint tg_Dx; - [unroll] for (tg_Dy = 0; tg_Dy < BLOCK_SIZE; tg_Dy++) - { - [unroll] for (tg_Dx = 0; tg_Dx < BLOCK_SIZE; tg_Dx++) - { - uint outputPixelBaseId = tg_OutputPixelBaseId + threadIndex; - uint2 outputPixelCoords = 2 * uint2(outputPixelBaseId % tg_WidthOHalf, outputPixelBaseId / tg_WidthOHalf); - - uint2 inputPixelCoords = outputPixelCoords - _Pad.xy + uint2(tg_Dx, tg_Dy); - - bool inputPixelMask = all(inputPixelCoords < uint2(tg_WidthX, tg_HeightX)); - - int inputPixelId = inputPixelCoords.y * tg_WidthX + inputPixelCoords.x; - uint inputChannelId = tg_ChannelOffset + threadIndexHigh; - - uint pixelReadOffset = tg_NumInputPixels * inputChannelId + inputPixelId + tg_BatchReadOffset; - - tempX[tg_Dy][tg_Dx] = X.MaskedGet(inputPixelMask, pixelReadOffset); - } - } - tempX = ApplyWinnogradB(tempX); - - // store tempX interleaved per thread: - // thread: 0 1 2 .... 128 0 1 2 .... 128 [16SGEMM x (8 values)] - // <- tempX[0] -> <- tempX[1] -> - // to avoid bank conflict in the inner loop, we shift every tempX by 18*8 instead of 256=16*8 - // LDS_[([0,15])*18*8 + (threadIndexGlobal/16)*16 + (threadIndexGlobal%16)] = tempX[[0,15]] - LDS_[((0 * 4 + 0) * 18 * 8) + threadIndexGlobal] = tempX[0][0]; - LDS_[((0 * 4 + 1) * 18 * 8) + threadIndexGlobal] = tempX[0][1]; - LDS_[((0 * 4 + 2) * 18 * 8) + threadIndexGlobal] = tempX[0][2]; - LDS_[((0 * 4 + 3) * 18 * 8) + threadIndexGlobal] = tempX[0][3]; - LDS_[((1 * 4 + 0) * 18 * 8) + threadIndexGlobal] = tempX[1][0]; - LDS_[((1 * 4 + 1) * 18 * 8) + threadIndexGlobal] = tempX[1][1]; - LDS_[((1 * 4 + 2) * 18 * 8) + threadIndexGlobal] = tempX[1][2]; - LDS_[((1 * 4 + 3) * 18 * 8) + threadIndexGlobal] = tempX[1][3]; - LDS_[((2 * 4 + 0) * 18 * 8) + threadIndexGlobal] = tempX[2][0]; - LDS_[((2 * 4 + 1) * 18 * 8) + threadIndexGlobal] = tempX[2][1]; - LDS_[((2 * 4 + 2) * 18 * 8) + threadIndexGlobal] = tempX[2][2]; - LDS_[((2 * 4 + 3) * 18 * 8) + threadIndexGlobal] = tempX[2][3]; - LDS_[((3 * 4 + 0) * 18 * 8) + threadIndexGlobal] = tempX[3][0]; - LDS_[((3 * 4 + 1) * 18 * 8) + threadIndexGlobal] = tempX[3][1]; - LDS_[((3 * 4 + 2) * 18 * 8) + threadIndexGlobal] = tempX[3][2]; - LDS_[((3 * 4 + 3) * 18 * 8) + threadIndexGlobal] = tempX[3][3]; - } - else // threadIndex4x4 >= 8 - { - uint threadIndexHigh = threadIndex4x4 & 7; // threadIndex4x4 - 8 - - float4x4 tempW; - uint tg_Dy; - uint tg_Dx; - [unroll] for (tg_Dy = 0; tg_Dy < BLOCK_SIZE; tg_Dy++) - { - [unroll] for (tg_Dx = 0; tg_Dx < BLOCK_SIZE; tg_Dx++) - { - uint tg_KernelReadOffset = (tg_Dy * 4 + tg_Dx)*tg_KernelSpatialStride + tg_NumKernels * (tg_ChannelOffset + threadIndexHigh); - uint kernelReadOffset = tg_KernelReadOffset + tg_KernelBaseId + threadIndex; - -#if LAX_KERNEL - kernelReadOffset = min(kernelReadOffset, K.GetLength() - 1); -#endif - - tempW[tg_Dy][tg_Dx] = K.FastGet(kernelReadOffset); - } - } - - // store tempX interleaved per thread: - // thread: 0 1 2 .... 128 0 1 2 .... 128 [16SGEMM x (8 values)] - // <- tempW[0] -> <- tempW[1] -> - // to avoid bank conflict in the inner loop, we shift every tempW by 18*8 instead of 256=16*8 - // LDS_[W_OFFSET + ([0,15])*18*8 + ((threadIndexGlobal/16)-8)*16 + (threadIndexGlobal%16)] = tempX[[0,15]] // -8 to get (threadIndexGlobal/16) between 0,8 - // W_OFFSET = 15*18*8+7*16+15 + 1 = 2288 - LDS_[(2288 - 8*16 + (0 * 4 + 0) * 18 * 8) + threadIndexGlobal] = tempW[0][0]; - LDS_[(2288 - 8*16 + (0 * 4 + 1) * 18 * 8) + threadIndexGlobal] = tempW[0][1]; - LDS_[(2288 - 8*16 + (0 * 4 + 2) * 18 * 8) + threadIndexGlobal] = tempW[0][2]; - LDS_[(2288 - 8*16 + (0 * 4 + 3) * 18 * 8) + threadIndexGlobal] = tempW[0][3]; - LDS_[(2288 - 8*16 + (1 * 4 + 0) * 18 * 8) + threadIndexGlobal] = tempW[1][0]; - LDS_[(2288 - 8*16 + (1 * 4 + 1) * 18 * 8) + threadIndexGlobal] = tempW[1][1]; - LDS_[(2288 - 8*16 + (1 * 4 + 2) * 18 * 8) + threadIndexGlobal] = tempW[1][2]; - LDS_[(2288 - 8*16 + (1 * 4 + 3) * 18 * 8) + threadIndexGlobal] = tempW[1][3]; - LDS_[(2288 - 8*16 + (2 * 4 + 0) * 18 * 8) + threadIndexGlobal] = tempW[2][0]; - LDS_[(2288 - 8*16 + (2 * 4 + 1) * 18 * 8) + threadIndexGlobal] = tempW[2][1]; - LDS_[(2288 - 8*16 + (2 * 4 + 2) * 18 * 8) + threadIndexGlobal] = tempW[2][2]; - LDS_[(2288 - 8*16 + (2 * 4 + 3) * 18 * 8) + threadIndexGlobal] = tempW[2][3]; - LDS_[(2288 - 8*16 + (3 * 4 + 0) * 18 * 8) + threadIndexGlobal] = tempW[3][0]; - LDS_[(2288 - 8*16 + (3 * 4 + 1) * 18 * 8) + threadIndexGlobal] = tempW[3][1]; - LDS_[(2288 - 8*16 + (3 * 4 + 2) * 18 * 8) + threadIndexGlobal] = tempW[3][2]; - LDS_[(2288 - 8*16 + (3 * 4 + 3) * 18 * 8) + threadIndexGlobal] = tempW[3][3]; - } - - GroupMemoryBarrierWithGroupSync(); - - // Inner loop - // uint ptrX = ((threadIndexGlobal%16)/4)*4 + (threadIndexGlobal/16) * 18 * 8; - // uint ptrW = 2288 + ((threadIndexGlobal%16)%4)*4 + (threadIndexGlobal/16) * 18 * 8; - uint ptrX = (groupThreadIDY4 + (threadIndex4x4 * 18 * 8)); - uint ptrW = 2288 + (groupThreadIDX4 + (threadIndex4x4 * 18 * 8)); - - float colOfX[BLOCK_SIZE]; - float rowOfW[BLOCK_SIZE]; - - [loop] for (uint tg_CacheExecuteIdx = 0; tg_CacheExecuteIdx < 8; ++tg_CacheExecuteIdx) - { - //Load LDS -> registers - colOfX[0] = LDS_[ptrX | 0]; - colOfX[1] = LDS_[ptrX | 1]; - colOfX[2] = LDS_[ptrX | 2]; - colOfX[3] = LDS_[ptrX | 3]; - - rowOfW[0] = LDS_[ptrW | 0]; - rowOfW[1] = LDS_[ptrW | 1]; - rowOfW[2] = LDS_[ptrW | 2]; - rowOfW[3] = LDS_[ptrW | 3]; - - ptrX += 16; - ptrW += 16; - - // Mads 4 pixels by 4 kernels matmul style --> 16 mads - dstA[0*BLOCK_SIZE + 0] = ffma(colOfX[0], rowOfW[0], dstA[0*BLOCK_SIZE + 0]); - dstA[0*BLOCK_SIZE + 1] = ffma(colOfX[0], rowOfW[1], dstA[0*BLOCK_SIZE + 1]); - dstA[0*BLOCK_SIZE + 2] = ffma(colOfX[0], rowOfW[2], dstA[0*BLOCK_SIZE + 2]); - dstA[0*BLOCK_SIZE + 3] = ffma(colOfX[0], rowOfW[3], dstA[0*BLOCK_SIZE + 3]); - dstA[1*BLOCK_SIZE + 0] = ffma(colOfX[1], rowOfW[0], dstA[1*BLOCK_SIZE + 0]); - dstA[1*BLOCK_SIZE + 1] = ffma(colOfX[1], rowOfW[1], dstA[1*BLOCK_SIZE + 1]); - dstA[1*BLOCK_SIZE + 2] = ffma(colOfX[1], rowOfW[2], dstA[1*BLOCK_SIZE + 2]); - dstA[1*BLOCK_SIZE + 3] = ffma(colOfX[1], rowOfW[3], dstA[1*BLOCK_SIZE + 3]); - dstA[2*BLOCK_SIZE + 0] = ffma(colOfX[2], rowOfW[0], dstA[2*BLOCK_SIZE + 0]); - dstA[2*BLOCK_SIZE + 1] = ffma(colOfX[2], rowOfW[1], dstA[2*BLOCK_SIZE + 1]); - dstA[2*BLOCK_SIZE + 2] = ffma(colOfX[2], rowOfW[2], dstA[2*BLOCK_SIZE + 2]); - dstA[2*BLOCK_SIZE + 3] = ffma(colOfX[2], rowOfW[3], dstA[2*BLOCK_SIZE + 3]); - dstA[3*BLOCK_SIZE + 0] = ffma(colOfX[3], rowOfW[0], dstA[3*BLOCK_SIZE + 0]); - dstA[3*BLOCK_SIZE + 1] = ffma(colOfX[3], rowOfW[1], dstA[3*BLOCK_SIZE + 1]); - dstA[3*BLOCK_SIZE + 2] = ffma(colOfX[3], rowOfW[2], dstA[3*BLOCK_SIZE + 2]); - dstA[3*BLOCK_SIZE + 3] = ffma(colOfX[3], rowOfW[3], dstA[3*BLOCK_SIZE + 3]); - } - - GroupMemoryBarrierWithGroupSync(); - } - - // store 16 SGEMM results to LDS - // LDS_[(threadIndexGlobal/16)*16*17 + [0,15]*16 + threadIndexGlobal%16] = dstA[0,15]; 17 instead of 16 to avoid bank conflicts - LDS_[threadIndex4x4 * 16 * 17 + 0 + threadIndex] = dstA[0]; - LDS_[threadIndex4x4 * 16 * 17 + 16 + threadIndex] = dstA[1]; - LDS_[threadIndex4x4 * 16 * 17 + 32 + threadIndex] = dstA[2]; - LDS_[threadIndex4x4 * 16 * 17 + 48 + threadIndex] = dstA[3]; - LDS_[threadIndex4x4 * 16 * 17 + 64 + threadIndex] = dstA[4]; - LDS_[threadIndex4x4 * 16 * 17 + 80 + threadIndex] = dstA[5]; - LDS_[threadIndex4x4 * 16 * 17 + 96 + threadIndex] = dstA[6]; - LDS_[threadIndex4x4 * 16 * 17 + 112 + threadIndex] = dstA[7]; - LDS_[threadIndex4x4 * 16 * 17 + 128 + threadIndex] = dstA[8]; - LDS_[threadIndex4x4 * 16 * 17 + 144 + threadIndex] = dstA[9]; - LDS_[threadIndex4x4 * 16 * 17 + 160 + threadIndex] = dstA[10]; - LDS_[threadIndex4x4 * 16 * 17 + 176 + threadIndex] = dstA[11]; - LDS_[threadIndex4x4 * 16 * 17 + 192 + threadIndex] = dstA[12]; - LDS_[threadIndex4x4 * 16 * 17 + 208 + threadIndex] = dstA[13]; - LDS_[threadIndex4x4 * 16 * 17 + 224 + threadIndex] = dstA[14]; - LDS_[threadIndex4x4 * 16 * 17 + 240 + threadIndex] = dstA[15]; - - GroupMemoryBarrierWithGroupSync(); - - // Load 4x4 accumulated result and perfom inverse winograd to get 2x2 output patch - float4x4 tempY; - // tempY[0,15] = LDS_[[0,15]*16*17 + (threadIndexGlobal/16) * 16 + threadIndex]; - tempY[0][0] = LDS_[ 0 * 16 * 17 + threadIndexGlobal]; - tempY[0][1] = LDS_[ 1 * 16 * 17 + threadIndexGlobal]; - tempY[0][2] = LDS_[ 2 * 16 * 17 + threadIndexGlobal]; - tempY[0][3] = LDS_[ 3 * 16 * 17 + threadIndexGlobal]; - tempY[1][0] = LDS_[ 4 * 16 * 17 + threadIndexGlobal]; - tempY[1][1] = LDS_[ 5 * 16 * 17 + threadIndexGlobal]; - tempY[1][2] = LDS_[ 6 * 16 * 17 + threadIndexGlobal]; - tempY[1][3] = LDS_[ 7 * 16 * 17 + threadIndexGlobal]; - tempY[2][0] = LDS_[ 8 * 16 * 17 + threadIndexGlobal]; - tempY[2][1] = LDS_[ 9 * 16 * 17 + threadIndexGlobal]; - tempY[2][2] = LDS_[10 * 16 * 17 + threadIndexGlobal]; - tempY[2][3] = LDS_[11 * 16 * 17 + threadIndexGlobal]; - tempY[3][0] = LDS_[12 * 16 * 17 + threadIndexGlobal]; - tempY[3][1] = LDS_[13 * 16 * 17 + threadIndexGlobal]; - tempY[3][2] = LDS_[14 * 16 * 17 + threadIndexGlobal]; - tempY[3][3] = LDS_[15 * 16 * 17 + threadIndexGlobal]; - - float2x2 writeValue = ApplyWinnogradA(tempY); - - // store 2x2 patch to have coalesced writes - GroupMemoryBarrierWithGroupSync(); - - // LDS_[[0,3]*(3*77+3*16+3*4+3+1) + ((threadIndexGlobal/16)/4)*77 + ((threadIndexGlobal/16)%4)*16 + ((threadIndexGlobal%16)/4)*4 + ((threadIndexGlobal%16)%4)] = writeValue[0,3]; // 77 instead of 64 to avoid bank conflicts - LDS_[0*(295) + (threadIndex4x4 >> 2)*77 + (((threadIndex4x4 & 0x3) << 4) | threadIndex)] = writeValue[0][0]; - LDS_[1*(295) + (threadIndex4x4 >> 2)*77 + (((threadIndex4x4 & 0x3) << 4) | threadIndex)] = writeValue[0][1]; - LDS_[2*(295) + (threadIndex4x4 >> 2)*77 + (((threadIndex4x4 & 0x3) << 4) | threadIndex)] = writeValue[1][0]; - LDS_[3*(295) + (threadIndex4x4 >> 2)*77 + (((threadIndex4x4 & 0x3) << 4) | threadIndex)] = writeValue[1][1]; - GroupMemoryBarrierWithGroupSync(); - - // writeValue[[0,3]] = LDS_[[0,3]*(3*77+3*16+3*4+3+1) + ((threadIndexGlobal%16)%4)*77 + ((threadIndexGlobal/16)%4)*16 + ((threadIndexGlobal%16)/4)*4 + ((threadIndexGlobal/16)/4)]; - writeValue[0][0] = LDS_[0*(295) + (threadIndex & 0x3)*77 + (((threadIndex4x4 & 0x3) << 4) | groupThreadIDY4 | (threadIndex4x4 >> 2))]; - writeValue[0][1] = LDS_[1*(295) + (threadIndex & 0x3)*77 + (((threadIndex4x4 & 0x3) << 4) | groupThreadIDY4 | (threadIndex4x4 >> 2))]; - writeValue[1][0] = LDS_[2*(295) + (threadIndex & 0x3)*77 + (((threadIndex4x4 & 0x3) << 4) | groupThreadIDY4 | (threadIndex4x4 >> 2))]; - writeValue[1][1] = LDS_[3*(295) + (threadIndex & 0x3)*77 + (((threadIndex4x4 & 0x3) << 4) | groupThreadIDY4 | (threadIndex4x4 >> 2))]; - - - uint writeChannelId = tg_KernelBaseId + threadIndex4x4; - uint writePixelId = tg_OutputPixelBaseId + threadIndex; - - writeValue += B.FastGet(min(tg_NumKernels-1, writeChannelId)); - - uint2 writePixelCoords = 2 * int2(writePixelId % tg_WidthOHalf, writePixelId / tg_WidthOHalf); - -#if LAX_KERNEL - bool canWriteChannel = (writeChannelId < tg_NumKernels); -#else - bool canWriteChannel = true; -#endif - - uint writeIndex = O.width * O.height * writeChannelId + tg_BatchWriteOffset; - - if (canWriteChannel && writePixelCoords.y < tg_HeightO && writePixelCoords.x < tg_WidthO) - O.FastSetWithActivation(writeIndex + (writePixelCoords.y) * tg_WidthO + (writePixelCoords.x), writeValue[0][0]); - if (canWriteChannel && writePixelCoords.y < tg_HeightO && (writePixelCoords.x + 1) < tg_WidthO) - O.FastSetWithActivation(writeIndex + (writePixelCoords.y) * tg_WidthO + (writePixelCoords.x + 1), writeValue[0][1]); - if (canWriteChannel && (writePixelCoords.y + 1) < tg_HeightO && writePixelCoords.x < tg_WidthO) - O.FastSetWithActivation(writeIndex + (writePixelCoords.y + 1) * tg_WidthO + (writePixelCoords.x), writeValue[1][0]); - if (canWriteChannel && (writePixelCoords.y + 1) < tg_HeightO && (writePixelCoords.x + 1) < tg_WidthO) - O.FastSetWithActivation(writeIndex + (writePixelCoords.y + 1) * tg_WidthO + (writePixelCoords.x + 1), writeValue[1][1]); - - -#undef X_OFFSET -#undef W_OFFSET -#undef LDS_ -#undef X_ -#undef W_ -} -#undef CACHE_DEPTH -#undef CACHE_WIDTH -#undef SHUFFLE_FOR_COALESCED_LOAD -#undef SHUFFLE_FOR_COALESCED_STORE -#undef _PAD -#undef CACHE_DEPTH -#undef PIXELS_PER_CACHE -#undef NUMTHREADS_PER_TG -#undef SHUFFLE_FOR_COALESCED_LOAD -#undef SHUFFLE_FOR_COALESCED_STORE -#endif //KERNEL_PER_TG == 16 -#endif //BLOCK_SIZE == 4 diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2d.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2d.cginc.meta deleted file mode 100644 index 1667221..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2d.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 8211ebc2a8cd04e49a086347aebe8ee6 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NCHW.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NCHW.compute deleted file mode 100644 index fcf6731..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NCHW.compute +++ /dev/null @@ -1,17 +0,0 @@ -// Most often used kernels - -#pragma kernel Conv2D_NCHW CHANNELS_FIRST=1 -#pragma kernel Conv2D_RegisterBlock4x2_NCHW CHANNELS_FIRST=1 - -#pragma kernel DepthwiseConv2D_NCHW CHANNELS_FIRST=1 - -//R4x4_64k -#pragma kernel Conv2DKernelKxK_StrictC16K64_T16x16_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 STRICT_CHANNELS=1 SUFFIX=KernelKxK_StrictC16K64_T16x16_R - -#pragma kernel Conv2DKernelKxK_T16x16_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 SUFFIX=KernelKxK_T16x16_R - -#pragma kernel Conv2DKernel1x1_StrictC16K64_T16x16_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 KERNEL_1x1=1 STRICT_CHANNELS=1 SUFFIX=Kernel1x1_StrictC16K64_T16x16_R - - - -#include "Conv2d.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NCHW.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NCHW.compute.meta deleted file mode 100644 index a1799d5..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NCHW.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9d6406345bbd8482bab46e622092abcb -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NHWC.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NHWC.compute deleted file mode 100644 index 4b792c8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NHWC.compute +++ /dev/null @@ -1,16 +0,0 @@ -// Most often used kernels - -#pragma kernel Conv2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Conv2D_RegisterBlock4x2_NHWC CHANNELS_FIRST=0 - -#pragma kernel DepthwiseConv2D_NHWC CHANNELS_FIRST=0 - -//R4x4_64k -#pragma kernel Conv2DKernelKxK_StrictC16K64_T16x16_R4x4_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=4 STRICT_CHANNELS=1 SUFFIX=KernelKxK_StrictC16K64_T16x16_R - -#pragma kernel Conv2DKernelKxK_T16x16_R4x4_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=4 SUFFIX=KernelKxK_T16x16_R - -#pragma kernel Conv2DKernel1x1_StrictC16K64_T16x16_R4x4_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=4 KERNEL_1x1=1 STRICT_CHANNELS=1 SUFFIX=Kernel1x1_StrictC16K64_T16x16_R - - -#include "Conv2d.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NHWC.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NHWC.compute.meta deleted file mode 100644 index 72bd4a4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dA_NHWC.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 60d69d385fb8141349f401ede7d4d5c7 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dBase.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dBase.compute deleted file mode 100644 index f20fa38..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dBase.compute +++ /dev/null @@ -1,34 +0,0 @@ -//R8x8_64k -#pragma kernel Conv2DKernelKxK_StrictC16StrictK64_T8x8_R8x8_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=8 KERNEL_PER_TG=64 STRICT_CHANNELS=1 SUFFIX=KernelKxK_StrictC16StrictK64_T8x8_R -#pragma kernel Conv2DKernelKxK_StrictC16StrictK64_T8x8_R8x8_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=8 KERNEL_PER_TG=64 STRICT_CHANNELS=1 SUFFIX=KernelKxK_StrictC16StrictK64_T8x8_R -#pragma kernel Conv2DKernelKxK_StrictC16LaxK64_T8x8_R8x8_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=8 KERNEL_PER_TG=64 STRICT_CHANNELS=1 LAX_KERNEL=1 SUFFIX=KernelKxK_StrictC16LaxK64_T8x8_R -#pragma kernel Conv2DKernelKxK_StrictC16LaxK64_T8x8_R8x8_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=8 KERNEL_PER_TG=64 STRICT_CHANNELS=1 LAX_KERNEL=1 SUFFIX=KernelKxK_StrictC16LaxK64_T8x8_R -//R8x8_16k -#pragma kernel Conv2DKernelKxK_StrictC4StrictK16_T2x32_R8x8_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=8 KERNEL_PER_TG=16 STRICT_CHANNELS=1 SUFFIX=KernelKxK_StrictC4StrictK16_T2x32_R -#pragma kernel Conv2DKernelKxK_StrictC4StrictK16_T2x32_R8x8_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=8 KERNEL_PER_TG=16 STRICT_CHANNELS=1 SUFFIX=KernelKxK_StrictC4StrictK16_T2x32_R -#pragma kernel Conv2DKernelKxK_LaxC4StrictK16_T2x32_R8x8_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=8 KERNEL_PER_TG=16 SUFFIX=KernelKxK_LaxC4StrictK16_T2x32_R -#pragma kernel Conv2DKernelKxK_LaxC4StrictK16_T2x32_R8x8_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=8 KERNEL_PER_TG=16 SUFFIX=KernelKxK_LaxC4StrictK16_T2x32_R -#pragma kernel Conv2DKernelKxK_StrictC4LaxK16_T2x32_R8x8_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=8 KERNEL_PER_TG=16 STRICT_CHANNELS=1 LAX_KERNEL=1 SUFFIX=KernelKxK_StrictC4LaxK16_T2x32_R -#pragma kernel Conv2DKernelKxK_StrictC4LaxK16_T2x32_R8x8_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=8 KERNEL_PER_TG=16 STRICT_CHANNELS=1 LAX_KERNEL=1 SUFFIX=KernelKxK_StrictC4LaxK16_T2x32_R - -#pragma kernel Conv2DTrans_NHWC CHANNELS_FIRST=0 -#pragma kernel Conv2DTrans_NCHW CHANNELS_FIRST=1 - -//Tested 2x2, 3x3 and 5x5 kernels with groupsize [8,8], [8,16], [16,16] and [16,32] (this one not in 5x5 as it does not fit in 32k) -//k=5x5 t=[16,16] fast consistently faster or equal to other configuration both on AMDVega and RTX2080 (tested with kernel size 2x2x32x32, input size 128x128x32) -//however this configuration is quite LDS bound performance profile might be very different on hardware without on chip LDS. This is especially true for smaller kernel -//as a lot of LDS will be reserved but not used, reducing the amount of cache used. -#pragma kernel Conv2DTrans_KernelCached_K5x5_T16x16_NHWC CHANNELS_FIRST=0 MAX_KERNEL_SIZE=5 GROUP_SIZE_X=16 GROUP_SIZE_Y=16 -#pragma kernel Conv2DTrans_KernelCached_K5x5_T16x16_NCHW CHANNELS_FIRST=1 MAX_KERNEL_SIZE=5 GROUP_SIZE_X=16 GROUP_SIZE_Y=16 - -#pragma kernel Conv2DTransFlipKernel -#pragma kernel Conv2DTransPadFill_NHWC CHANNELS_FIRST=0 -#pragma kernel Conv2DTransPadFill_NCHW CHANNELS_FIRST=1 - -#pragma kernel KernelWinograd_3x3 - -#pragma kernel Conv2DWinograd_2x2_Kernel3x3_StrictC8StrictK16_T16x16_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 KERNEL_PER_TG=16 STRICT_CHANNELS=1 SUFFIX=Kernel3x3_StrictC8StrictK16_T16x16_R -#pragma kernel Conv2DWinograd_2x2_Kernel3x3_StrictC8LaxK16_T16x16_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 KERNEL_PER_TG=16 STRICT_CHANNELS=1 LAX_KERNEL=1 SUFFIX=Kernel3x3_StrictC8LaxK16_T16x16_R - - -#include "Conv2d.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dBase.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dBase.compute.meta deleted file mode 100644 index 71f7c91..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dBase.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1279e283ef61d47309a96431ea81d6bb -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dMobile.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dMobile.compute deleted file mode 100644 index bcd93b4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dMobile.compute +++ /dev/null @@ -1,1546 +0,0 @@ -//Winograd -#pragma kernel DepthwiseConv2D_Winograd_2x2_Kernel3x3_NHWC CHANNELS_FIRST=0 OUTPUT_SHAPE=2 KERNEL_SHAPE=3 -#pragma kernel DepthwiseConv2D_Winograd_2x2_Kernel3x3_NCHW CHANNELS_FIRST=1 OUTPUT_SHAPE=2 KERNEL_SHAPE=3 -#pragma kernel DepthwiseConv2D_Winograd_2x2_Kernel5x5_NHWC CHANNELS_FIRST=0 OUTPUT_SHAPE=2 KERNEL_SHAPE=5 -#pragma kernel DepthwiseConv2D_Winograd_2x2_Kernel5x5_NCHW CHANNELS_FIRST=1 OUTPUT_SHAPE=2 KERNEL_SHAPE=5 -//#pragma kernel KernelWinograd_3x3 KERNEL_SHAPE=3 -#pragma kernel KernelWinograd_5x5 KERNEL_SHAPE=5 -//Default -#pragma kernel DepthwiseConv2D_Default_NHWC CHANNELS_FIRST=0 KERNEL_SHAPE=1 -#pragma kernel DepthwiseConv2D_Default_NCHW CHANNELS_FIRST=1 KERNEL_SHAPE=1 - -// Conv -#pragma kernel Conv2D_Kernel1x1_1x4x4_NHWC CHANNELS_FIRST=0 KERNEL_SHAPE=1 IBLOCK=1 KBLOCK=4 JBLOCK=4 -#pragma kernel Conv2D_Kernel1x1_1x4x4_NCHW CHANNELS_FIRST=1 KERNEL_SHAPE=1 IBLOCK=1 KBLOCK=4 JBLOCK=4 -// Winograd -#pragma kernel Conv2D_Winograd_2x2_Kernel3x3_LDS_NHWC CHANNELS_FIRST=0 OUTPUT_SHAPE=2 KERNEL_SHAPE=3 USELDS=1 -#pragma kernel Conv2D_Winograd_2x2_Kernel3x3_LDS_NCHW CHANNELS_FIRST=1 OUTPUT_SHAPE=2 KERNEL_SHAPE=3 USELDS=1 -#pragma kernel Conv2D_Winograd_2x2_Kernel3x3_NHWC CHANNELS_FIRST=0 OUTPUT_SHAPE=2 KERNEL_SHAPE=3 USELDS=0 -#pragma kernel Conv2D_Winograd_2x2_Kernel3x3_NCHW CHANNELS_FIRST=1 OUTPUT_SHAPE=2 KERNEL_SHAPE=3 USELDS=0 -// 4x4 -#pragma kernel Conv2D_KernelKxK_T16x16_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 KERNEL_PER_TG=256 SUFFIX=KernelKxK_T16x16_R -#pragma kernel Conv2D_KernelKxK_T16x16_R4x4_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=4 KERNEL_PER_TG=256 SUFFIX=KernelKxK_T16x16_R - -#pragma kernel Conv2D_Kernel1x1_T16x16_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 KERNEL_PER_TG=256 SUFFIX=Kernel1x1_T16x16_R KERNEL_1x1=1 -#pragma kernel Conv2D_Kernel1x1_T16x16_R4x4_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=4 KERNEL_PER_TG=256 SUFFIX=Kernel1x1_T16x16_R KERNEL_1x1=1 - -#pragma kernel Conv2D_KernelKxK_T8x8_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 KERNEL_PER_TG=64 SUFFIX=KernelKxK_T8x8_R -#pragma kernel Conv2D_KernelKxK_T8x8_R4x4_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=4 KERNEL_PER_TG=64 SUFFIX=KernelKxK_T8x8_R - -#pragma kernel Conv2D_Kernel1x1_T8x8_R4x4_NCHW CHANNELS_FIRST=1 BLOCK_SIZE=4 KERNEL_PER_TG=64 SUFFIX=Kernel1x1_T8x8_R KERNEL_1x1=1 -#pragma kernel Conv2D_Kernel1x1_T8x8_R4x4_NHWC CHANNELS_FIRST=0 BLOCK_SIZE=4 KERNEL_PER_TG=64 SUFFIX=Kernel1x1_T8x8_R KERNEL_1x1=1 - -//Default -#pragma kernel Conv2D_Default_T8x8_R4x4_NCHW CHANNELS_FIRST=1 -#pragma kernel Conv2D_Default_T8x8_R4x4_NHWC CHANNELS_FIRST=0 - - -#include "Tensor.cginc" -#define UNITY_SHADER_NO_UPGRADE 1 - -TENSOR_DECL(X) -TENSOR_DECL(K) -TENSOR_DECL(B) -TENSOR_DECL(WBK) -TENSOR_DECL_RW(O) - -uint4 _Pad; -uint4 _Stride; - -float ffma(float a, float b, float c) { return dot(float2(a, c), float2(b, 1)); } - - -#define CACHE_DEPTH 8 - -[numthreads(8, 8, 1)] -void KERNEL_FUNC(Conv2D_Default_T8x8_R4x4)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - uint w = O.width; - uint h = O.height; - uint maxBiasIndex = O.channels - 1; - - uint k = dispatchThreadID.x; - - uint4 xxyy = 4 * dispatchThreadID.y + uint4(0,1,2,3); - uint4 xx = (xxyy % w); - uint4 yy = (xxyy / w); - - - - for (uint n = 0; n < O.batch; ++n) - { - float4 acc0 = float4(B.FastGet(min(4 * k + 0, maxBiasIndex)), B.FastGet(min(4 * k + 1, maxBiasIndex)), B.FastGet(min(4 * k + 2, maxBiasIndex)), B.FastGet(min(4 * k + 3, maxBiasIndex))); - float4 acc1 = acc0; - float4 acc2 = acc0; - float4 acc3 = acc0; - - - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - { - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint kernelOffset = dy * X.channels * K.GetKernelWidth() + dx * X.channels; - - bool4 maskX = - yy * _Stride.y - _Pad.y + dy >= 0 && - yy * _Stride.y - _Pad.y + dy < X.height && - xx * _Stride.x - _Pad.x + dx >= 0 && - xx * _Stride.x - _Pad.x + dx < X.width; - - uint4 readX = n * X.height * X.width * X.channels + ((yy * _Stride.y - _Pad.y + dy) * X.width + (xx * _Stride.x - _Pad.x + dx)) * X.channels; - - for (uint c = 0; c < X.channels; c += CACHE_DEPTH) - { - for (uint cc = 0; cc < CACHE_DEPTH; ++cc) - { - float4 v; - - bool maskC = c + cc < X.channels; - v.x = X.MaskedGet(maskX.x && maskC, readX.x + c + cc); - v.y = X.MaskedGet(maskX.y && maskC, readX.y + c + cc); - v.z = X.MaskedGet(maskX.z && maskC, readX.z + c + cc); - v.w = X.MaskedGet(maskX.w && maskC, readX.w + c + cc); - - uint readK = (kernelOffset + c + cc) * O.channels; - float4 w = float4(K.MaskedGet(4*k+0 < O.channels,readK + 4*k+0), - K.MaskedGet(4*k+1 < O.channels,readK + 4*k+1), - K.MaskedGet(4*k+2 < O.channels,readK + 4*k+2), - K.MaskedGet(4*k+3 < O.channels,readK + 4*k+3)); - - - acc0 += v.x * w; - acc1 += v.y * w; - acc2 += v.z * w; - acc3 += v.w * w; - } - GroupMemoryBarrierWithGroupSync(); - } - } - } - - if (xxyy.x < h * w && 4 * k + 0 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.x * O.channels + 4 * k + 0, acc0.x); - if (xxyy.x < h * w && 4 * k + 1 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.x * O.channels + 4 * k + 1, acc0.y); - if (xxyy.x < h * w && 4 * k + 2 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.x * O.channels + 4 * k + 2, acc0.z); - if (xxyy.x < h * w && 4 * k + 3 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.x * O.channels + 4 * k + 3, acc0.w); - - if (xxyy.y < h * w && 4 * k + 0 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.y * O.channels + 4 * k + 0, acc1.x); - if (xxyy.y < h * w && 4 * k + 1 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.y * O.channels + 4 * k + 1, acc1.y); - if (xxyy.y < h * w && 4 * k + 2 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.y * O.channels + 4 * k + 2, acc1.z); - if (xxyy.y < h * w && 4 * k + 3 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.y * O.channels + 4 * k + 3, acc1.w); - - if (xxyy.z < h * w && 4 * k + 0 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.z * O.channels + 4 * k + 0, acc2.x); - if (xxyy.z < h * w && 4 * k + 1 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.z * O.channels + 4 * k + 1, acc2.y); - if (xxyy.z < h * w && 4 * k + 2 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.z * O.channels + 4 * k + 2, acc2.z); - if (xxyy.z < h * w && 4 * k + 3 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.z * O.channels + 4 * k + 3, acc2.w); - - if (xxyy.w < h * w && 4 * k + 0 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.w * O.channels + 4 * k + 0, acc3.x); - if (xxyy.w < h * w && 4 * k + 1 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.w * O.channels + 4 * k + 1, acc3.y); - if (xxyy.w < h * w && 4 * k + 2 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.w * O.channels + 4 * k + 2, acc3.z); - if (xxyy.w < h * w && 4 * k + 3 < O.channels) - O.FastSetWithActivation(n * h * w * O.channels + xxyy.w * O.channels + 4 * k + 3, acc3.w); - } -} - -#undef CACHE_DEPTH - -[numthreads(32, 2, 2)] -void KERNEL_FUNC(DepthwiseConv2D_Default)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float acc = B.FastGet(k); - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos = uint2(x, y) * _Stride.xy + uint2(dx, dy); - float v = X.SafeGet(n, pos, k, _Pad.xy); - acc += v * K.Get(dy, dx, 0, k); - } - - O.SetWithActivation(n, y, x, k, acc); - } -} - -#if USELDS - #if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE) KERNEL##_##OUTPUT_SHAPE##x##OUTPUT_SHAPE##_Kernel##KERNEL_SHAPE##x##KERNEL_SHAPE##_LDS_NCHW - #define CACHE_NAME_CALL(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE, TENSOR) KERNEL##_##OUTPUT_SHAPE##x##OUTPUT_SHAPE##_Kernel##KERNEL_SHAPE##x##KERNEL_SHAPE_Cache_##TENSOR##_NCHW - #else - #define FUNC_NAME_CALL(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE) KERNEL##_##OUTPUT_SHAPE##x##OUTPUT_SHAPE##_Kernel##KERNEL_SHAPE##x##KERNEL_SHAPE##_LDS_NHWC - #define CACHE_NAME_CALL(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE, TENSOR) KERNEL##_##OUTPUT_SHAPE##x##OUTPUT_SHAPE##_Kernel##KERNEL_SHAPE##x##KERNEL_SHAPE_Cache_##TENSOR##_NHWC - #endif -#else - #if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE) KERNEL##_##OUTPUT_SHAPE##x##OUTPUT_SHAPE##_Kernel##KERNEL_SHAPE##x##KERNEL_SHAPE##_NCHW - #else - #define FUNC_NAME_CALL(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE) KERNEL##_##OUTPUT_SHAPE##x##OUTPUT_SHAPE##_Kernel##KERNEL_SHAPE##x##KERNEL_SHAPE##_NHWC - #endif -#endif -#define FUNC_NAME(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE) FUNC_NAME_CALL(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE) -#define CACHE_NAME(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE, TENSOR) CACHE_NAME_CALL(KERNEL, OUTPUT_SHAPE, KERNEL_SHAPE, TENSOR) - -// https://github.com/andravin/wincnn -// https://arxiv.org/pdf/1509.09308.pdf -#if KERNEL_SHAPE == 3 -// Winograd: 4x4 image, 3x3 kernel, 2x2 output -inline float4x4 ApplyWinnogradB(float4x4 d) -{ - // BT x u x B, used mathematica to express the operation using only +/- - //return float4x4(float4( d[0][0] - d[0][2] - d[2][0] + d[2][2], d[0][1] + d[0][2] - d[2][1] - d[2][2], -d[0][1] + d[0][2] + d[2][1] - d[2][2], -d[0][1] + d[0][3] + d[2][1] - d[2][3]), - // float4( d[1][0] - d[1][2] + d[2][0] - d[2][2], d[1][1] + d[1][2] + d[2][1] + d[2][2], -d[1][1] + d[1][2] - d[2][1] + d[2][2], -d[1][1] + d[1][3] - d[2][1] + d[2][3]), - // float4(-d[1][0] + d[1][2] + d[2][0] - d[2][2], -d[1][1] - d[1][2] + d[2][1] + d[2][2], d[1][1] - d[1][2] - d[2][1] + d[2][2], d[1][1] - d[1][3] - d[2][1] + d[2][3]), - // float4(-d[1][0] + d[1][2] + d[3][0] - d[3][2], -d[1][1] - d[1][2] + d[3][1] + d[3][2], d[1][1] - d[1][2] - d[3][1] + d[3][2], d[1][1] - d[1][3] - d[3][1] + d[3][3]) - // ); - // re-order operations to lower register pressure - float4x4 TU; - float4x4 U; - TU[0][0] = d[0][0] - d[2][0]; - TU[0][1] = d[0][1] - d[2][1]; - TU[0][2] = d[0][2] - d[2][2]; - TU[0][3] = d[0][3] - d[2][3]; - - TU[1][0] = d[1][0] + d[2][0]; - TU[1][1] = d[1][1] + d[2][1]; - TU[1][2] = d[1][2] + d[2][2]; - TU[1][3] = d[1][3] + d[2][3]; - - TU[2][0] = d[2][0] - d[1][0]; - TU[2][1] = d[2][1] - d[1][1]; - TU[2][2] = d[2][2] - d[1][2]; - TU[2][3] = d[2][3] - d[1][3]; - - TU[3][0] = d[3][0] - d[1][0]; - TU[3][1] = d[3][1] - d[1][1]; - TU[3][2] = d[3][2] - d[1][2]; - TU[3][3] = d[3][3] - d[1][3]; - - - U[0][0] = TU[0][0] - TU[0][2]; - U[0][1] = TU[0][1] + TU[0][2]; - U[0][2] = TU[0][2] - TU[0][1]; - U[0][3] = TU[0][3] - TU[0][1]; - - U[1][0] = TU[1][0] - TU[1][2]; - U[1][1] = TU[1][1] + TU[1][2]; - U[1][2] = TU[1][2] - TU[1][1]; - U[1][3] = TU[1][3] - TU[1][1]; - - U[2][0] = TU[2][0] - TU[2][2]; - U[2][1] = TU[2][1] + TU[2][2]; - U[2][2] = TU[2][2] - TU[2][1]; - U[2][3] = TU[2][3] - TU[2][1]; - - U[3][0] = TU[3][0] - TU[3][2]; - U[3][1] = TU[3][1] + TU[3][2]; - U[3][2] = TU[3][2] - TU[3][1]; - U[3][3] = TU[3][3] - TU[3][1]; - - return U; -} - -inline float2x2 ApplyWinnogradA(float4x4 uv) -{ - // A x u x A, used mathematica to express the operation using only +/- - // return float2x2(float2(uv[0][0] + uv[0][1] + uv[0][2] + uv[1][0] + uv[1][1] + uv[1][2] + uv[2][0] + uv[2][1] + uv[2][2], uv[0][1] - uv[0][2] + uv[0][3] + uv[1][1] - uv[1][2] + uv[1][3] + uv[2][1] - uv[2][2] + uv[2][3]), - // float2(uv[1][0] + uv[1][1] + uv[1][2] - uv[2][0] - uv[2][1] - uv[2][2] + uv[3][0] + uv[3][1] + uv[3][2], uv[1][1] - uv[1][2] + uv[1][3] - uv[2][1] + uv[2][2] - uv[2][3] + uv[3][1] - uv[3][2] + uv[3][3]) - // ); - // re-order operations to lower register pressure - float2x4 TY; - float2x2 Y; - TY[0][0] = uv[0][0] + uv[0][1] + uv[0][2]; - TY[0][1] = uv[1][0] + uv[1][1] + uv[1][2]; - TY[0][2] = uv[2][0] + uv[2][1] + uv[2][2]; - TY[0][3] = uv[3][0] + uv[3][1] + uv[3][2]; - - TY[1][0] = uv[0][1] - uv[0][2] + uv[0][3]; - TY[1][1] = uv[1][1] - uv[1][2] + uv[1][3]; - TY[1][2] = uv[2][1] - uv[2][2] + uv[2][3]; - TY[1][3] = uv[3][1] - uv[3][2] + uv[3][3]; - - - Y[0][0] = TY[0][0] + TY[0][1] + TY[0][2]; - Y[0][1] = TY[1][0] + TY[1][1] + TY[1][2]; - Y[1][0] = TY[0][1] - TY[0][2] + TY[0][3]; - Y[1][1] = TY[1][1] - TY[1][2] + TY[1][3]; - - return Y; -} - -#elif KERNEL_SHAPE == 5 -// Winograd: 4x4 image, 3x3 kernel, 2x2 output -inline float2x2 ApplyWinnogradA(float4 u0, float4 u1, float4 u2, float4 u3, float4 u4, float4 u5, float4 u6, float4 u7, float4 u8) -{ - // mul(Winograd_AT, mul(v*u, Winograd_A)); - //static const float2x6 Winograd_AT = {{1, 1, 1, 1, 1, 0}, {0, 1, -1, 2, -2, 1}} - //static const float6x2 Winograd_A = {{1, 0}, {1, 1}, {1, -1}, {1, 2}, {1, -2}, {0, 1}} - - float2x2 Y; - Y[0][0] = dot(u0, float4(1, 1, 1, 1)) + dot(u1, float4( 1, 0, 1, 1)) + dot(u2, float4( 1, 1, 1, 0)) + dot(u3, float4( 1, 1, 1, 1)) + dot(u4, float4( 1, 0, 1, 1)) + dot(u5, float4( 1, 1, 1, 0)) + dot(u6, float4( 1, 1, 1, 1)) + dot(u7, float4( 1, 0, 0, 0)); - Y[0][1] = dot(u0, float4(0, 1, -1, 2)) + dot(u1, float4(-2, 1, 0, 1)) + dot(u2, float4(-1, 2, -2, 1)) + dot(u3, float4( 0, 1, -1, 2)) + dot(u4, float4(-2, 1, 0, 1)) + dot(u5, float4(-1, 2, -2, 1)) + dot(u6, float4( 0, 1, -1, 2)) + dot(u7, float4(-2, 1, 0, 0)); - Y[1][0] = dot(u1, float4(0, 0, 1, 1)) + dot(u2, float4( 1, 1, 1, 0)) + dot(u3, float4(-1, -1, -1, -1)) + dot(u4, float4(-1, 0, 2, 2)) + dot(u5, float4( 2, 2, 2, 0)) + dot(u6, float4(-2, -2, -2, -2)) + dot(u7, float4(-2, 0, 1, 1)) + dot(u8, float4( 1, 1, 1, 0)); - Y[1][1] = dot(u1, float4(0, 0, 0, 1)) + dot(u2, float4(-1, 2, -2, 1)) + dot(u3, float4( 0, -1, 1, -2)) + dot(u4, float4( 2, -1, 0, 2)) + dot(u5, float4(-2, 4, -4, 2)) + dot(u6, float4( 0, -2, 2, -4)) + dot(u7, float4( 4, -2, 0, 1)) + dot(u8, float4(-1, 2, -2, 1)); - - return Y; -} - -inline void ApplyWinnogradB(float3x3 d00, float3x3 d01, float3x3 d10, float3x3 d11, - in out float4 u0, in out float4 u1, in out float4 u2, in out float4 u3, in out float4 u4, in out float4 u5, in out float4 u6, in out float4 u7, in out float4 u8) -{ - // mul(Winograd_BT, mul(d, Winograd_B)); - //static const float6x6 Winograd_BT = {{4, 0, -5, 0, 1, 0}, - // {0, -4, -4, 1, 1, 0}, - // {0, 4, -4, -1, 1, 0}, - // {0, -2, -1, 2, 1, 0}, - // {0, 2, -1, -2, 1, 0}, - // {0, 4, 0, -5, 0, 1}} - //static const float6x6 Winograd_B = {{ 4, 0, 0, 0, 0, 0}, - // { 0, -4, 4, -2, 2, 4}, - // {-5, -4, -4, -1, -1, 0}, - // { 0, 1, -1, 2, -2, -5}, - // { 1, 1, 1, 1, 1, 0}, - // { 0, 0, 0, 0, 0, 1}} - float3x3 a00 = mul(float3x3(float3(4, 0, -5), float3(0, -4, -4), float3(0, 4, -4)), d00) + mul(float3x3(float3(0, 1, 0), float3( 1, 1, 0), float3(-1, 1, 0)), d10); - float3x3 a01 = mul(float3x3(float3(4, 0, -5), float3(0, -4, -4), float3(0, 4, -4)), d01) + mul(float3x3(float3(0, 1, 0), float3( 1, 1, 0), float3(-1, 1, 0)), d11); - float3x3 a10 = mul(float3x3(float3(0, -2, -1), float3(0, 2, -1), float3(0, 4, 0)), d00) + mul(float3x3(float3(2, 1, 0), float3(-2, 1, 0), float3(-5, 0, 1)), d10); - float3x3 a11 = mul(float3x3(float3(0, -2, -1), float3(0, 2, -1), float3(0, 4, 0)), d01) + mul(float3x3(float3(2, 1, 0), float3(-2, 1, 0), float3(-5, 0, 1)), d11); - - float3x3 y00 = mul(a00, float3x3(float3(4, 0, 0), float3( 0, -4, 4), float3(-5, -4, -4))) + mul(a01, float3x3(float3(0, 1, -1), float3(1, 1, 1), float3(0, 0, 0))); - float3x3 y01 = mul(a00, float3x3(float3(0, 0, 0), float3(-2, 2, 4), float3(-1, -1, 0))) + mul(a01, float3x3(float3( 2, -2, -5), float3(1, 1, 0), float3(0, 0, 1))); - float3x3 y10 = mul(a10, float3x3(float3(4, 0, 0), float3( 0, -4, 4), float3(-5, -4, -4))) + mul(a11, float3x3(float3(0, 1, -1), float3(1, 1, 1), float3(0, 0, 0))); - float3x3 y11 = mul(a10, float3x3(float3(0, 0, 0), float3(-2, 2, 4), float3(-1, -1, 0))) + mul(a11, float3x3(float3( 2, -2, -5), float3(1, 1, 0), float3(0, 0, 1))); - - u0.x *= y00[0][0]; - u0.y *= y00[0][1]; - u0.z *= y00[0][2]; - u0.w *= y01[0][0]; - - u1.x *= y01[0][1]; - u1.y *= y01[0][2]; - u1.z *= y00[1][0]; - u1.w *= y00[1][1]; - - u2.x *= y00[1][2]; - u2.y *= y01[1][0]; - u2.z *= y01[1][1]; - u2.w *= y01[1][2]; - - u3.x *= y00[2][0]; - u3.y *= y00[2][1]; - u3.z *= y00[2][2]; - u3.w *= y01[2][0]; - - u4.x *= y01[2][1]; - u4.y *= y01[2][2]; - u4.z *= y10[0][0]; - u4.w *= y10[0][1]; - - u5.x *= y10[0][2]; - u5.y *= y11[0][0]; - u5.z *= y11[0][1]; - u5.w *= y11[0][2]; - - u6.x *= y10[1][0]; - u6.y *= y10[1][1]; - u6.z *= y10[1][2]; - u6.w *= y11[1][0]; - - u7.x *= y11[1][1]; - u7.y *= y11[1][2]; - u7.z *= y10[2][0]; - u7.w *= y10[2][1]; - - u8.x *= y10[2][2]; - u8.y *= y11[2][0]; - u8.z *= y11[2][1]; - u8.w *= y11[2][2]; -} -#endif - -#if KERNEL_SHAPE == 3 -[numthreads(16, 4, 4)] -#elif KERNEL_SHAPE == 5 -[numthreads(32, 2, 2)] -#endif -void FUNC_NAME(DepthwiseConv2D_Winograd, OUTPUT_SHAPE, KERNEL_SHAPE)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex, uint3 groupID : SV_GroupID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - - uint k = dispatchThreadID.x; - uint x = 2*dispatchThreadID.y; - uint y = 2*dispatchThreadID.z; - - if (k >= K.channels) return; - - for (uint n = 0; n < O.batch; ++n) - { - float2x2 acc = B.FastGet(k); - - #if KERNEL_SHAPE == 3 - // 16 loads per thread - float4x4 d; - d[0][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 0), k, _Pad.xy); - d[0][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 0), k, _Pad.xy); - d[0][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 0), k, _Pad.xy); - d[0][3] = X.SafeGet(n, uint2(x, y) + uint2(3, 0), k, _Pad.xy); - - d[1][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 1), k, _Pad.xy); - d[1][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 1), k, _Pad.xy); - d[1][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 1), k, _Pad.xy); - d[1][3] = X.SafeGet(n, uint2(x, y) + uint2(3, 1), k, _Pad.xy); - - d[2][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 2), k, _Pad.xy); - d[2][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 2), k, _Pad.xy); - d[2][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 2), k, _Pad.xy); - d[2][3] = X.SafeGet(n, uint2(x, y) + uint2(3, 2), k, _Pad.xy); - - d[3][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 3), k, _Pad.xy); - d[3][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 3), k, _Pad.xy); - d[3][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 3), k, _Pad.xy); - d[3][3] = X.SafeGet(n, uint2(x, y) + uint2(3, 3), k, _Pad.xy); - - - float4x4 v; - v[0][0] = K.Get(0, 0, 0, k); - v[0][1] = K.Get(0, 1, 0, k); - v[0][2] = K.Get(0, 2, 0, k); - v[0][3] = K.Get(0, 3, 0, k); - - v[1][0] = K.Get(1, 0, 0, k); - v[1][1] = K.Get(1, 1, 0, k); - v[1][2] = K.Get(1, 2, 0, k); - v[1][3] = K.Get(1, 3, 0, k); - - v[2][0] = K.Get(2, 0, 0, k); - v[2][1] = K.Get(2, 1, 0, k); - v[2][2] = K.Get(2, 2, 0, k); - v[2][3] = K.Get(2, 3, 0, k); - - v[3][0] = K.Get(3, 0, 0, k); - v[3][1] = K.Get(3, 1, 0, k); - v[3][2] = K.Get(3, 2, 0, k); - v[3][3] = K.Get(3, 3, 0, k); - - float4x4 u = ApplyWinnogradB(d); - - acc += ApplyWinnogradA(v*u); - - #elif KERNEL_SHAPE == 5 - //float v[6][6]; - float4 v0, v1, v2, v3, v4, v5, v6, v7, v8; - v0.x = K.Get(0, 0, 0, k); - v0.y = K.Get(0, 1, 0, k); - v0.z = K.Get(0, 2, 0, k); - v0.w = K.Get(0, 3, 0, k); - - v1.x = K.Get(0, 4, 0, k); - v1.y = K.Get(0, 5, 0, k); - v1.z = K.Get(1, 0, 0, k); - v1.w = K.Get(1, 1, 0, k); - - v2.x = K.Get(1, 2, 0, k); - v2.y = K.Get(1, 3, 0, k); - v2.z = K.Get(1, 4, 0, k); - v2.w = K.Get(1, 5, 0, k); - - v3.x = K.Get(2, 0, 0, k); - v3.y = K.Get(2, 1, 0, k); - v3.z = K.Get(2, 2, 0, k); - v3.w = K.Get(2, 3, 0, k); - - v4.x = K.Get(2, 4, 0, k); - v4.y = K.Get(2, 5, 0, k); - v4.z = K.Get(3, 0, 0, k); - v4.w = K.Get(3, 1, 0, k); - - v5.x = K.Get(3, 2, 0, k); - v5.y = K.Get(3, 3, 0, k); - v5.z = K.Get(3, 4, 0, k); - v5.w = K.Get(3, 5, 0, k); - - v6.x = K.Get(4, 0, 0, k); - v6.y = K.Get(4, 1, 0, k); - v6.z = K.Get(4, 2, 0, k); - v6.w = K.Get(4, 3, 0, k); - - v7.x = K.Get(4, 4, 0, k); - v7.y = K.Get(4, 5, 0, k); - v7.z = K.Get(5, 0, 0, k); - v7.w = K.Get(5, 1, 0, k); - - v8.x = K.Get(5, 2, 0, k); - v8.y = K.Get(5, 3, 0, k); - v8.z = K.Get(5, 4, 0, k); - v8.w = K.Get(5, 5, 0, k); - - float3x3 d00, d01, d10, d11; - d00[0][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 0), k, _Pad.xy); - d00[0][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 0), k, _Pad.xy); - d00[0][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 0), k, _Pad.xy); - d01[0][0] = X.SafeGet(n, uint2(x, y) + uint2(3, 0), k, _Pad.xy); - d01[0][1] = X.SafeGet(n, uint2(x, y) + uint2(4, 0), k, _Pad.xy); - d01[0][2] = X.SafeGet(n, uint2(x, y) + uint2(5, 0), k, _Pad.xy); - - d00[1][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 1), k, _Pad.xy); - d00[1][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 1), k, _Pad.xy); - d00[1][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 1), k, _Pad.xy); - d01[1][0] = X.SafeGet(n, uint2(x, y) + uint2(3, 1), k, _Pad.xy); - d01[1][1] = X.SafeGet(n, uint2(x, y) + uint2(4, 1), k, _Pad.xy); - d01[1][2] = X.SafeGet(n, uint2(x, y) + uint2(5, 1), k, _Pad.xy); - - d00[2][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 2), k, _Pad.xy); - d00[2][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 2), k, _Pad.xy); - d00[2][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 2), k, _Pad.xy); - d01[2][0] = X.SafeGet(n, uint2(x, y) + uint2(3, 2), k, _Pad.xy); - d01[2][1] = X.SafeGet(n, uint2(x, y) + uint2(4, 2), k, _Pad.xy); - d01[2][2] = X.SafeGet(n, uint2(x, y) + uint2(5, 2), k, _Pad.xy); - - d10[0][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 3), k, _Pad.xy); - d10[0][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 3), k, _Pad.xy); - d10[0][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 3), k, _Pad.xy); - d11[0][0] = X.SafeGet(n, uint2(x, y) + uint2(3, 3), k, _Pad.xy); - d11[0][1] = X.SafeGet(n, uint2(x, y) + uint2(4, 3), k, _Pad.xy); - d11[0][2] = X.SafeGet(n, uint2(x, y) + uint2(5, 3), k, _Pad.xy); - - d10[1][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 4), k, _Pad.xy); - d10[1][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 4), k, _Pad.xy); - d10[1][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 4), k, _Pad.xy); - d11[1][0] = X.SafeGet(n, uint2(x, y) + uint2(3, 4), k, _Pad.xy); - d11[1][1] = X.SafeGet(n, uint2(x, y) + uint2(4, 4), k, _Pad.xy); - d11[1][2] = X.SafeGet(n, uint2(x, y) + uint2(5, 4), k, _Pad.xy); - - d10[2][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 5), k, _Pad.xy); - d10[2][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 5), k, _Pad.xy); - d10[2][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 5), k, _Pad.xy); - d11[2][0] = X.SafeGet(n, uint2(x, y) + uint2(3, 5), k, _Pad.xy); - d11[2][1] = X.SafeGet(n, uint2(x, y) + uint2(4, 5), k, _Pad.xy); - d11[2][2] = X.SafeGet(n, uint2(x, y) + uint2(5, 5), k, _Pad.xy); - - - //float u[6][6]; - //float4 u0, u1, u2, u3, u4, u5, u6, u7, u8; - ApplyWinnogradB(d00, d01, d10, d11, v0, v1, v2, v3, v4, v5, v6, v7, v8); - - //u[0][0] *= v[0][0]; u[0][1] *= v[0][1]; u[0][2] *= v[0][2]; u[0][3] *= v[0][3]; u[0][4] *= v[0][4]; u[0][5] *= v[0][5]; - //u[1][0] *= v[1][0]; u[1][1] *= v[1][1]; u[1][2] *= v[1][2]; u[1][3] *= v[1][3]; u[1][4] *= v[1][4]; u[1][5] *= v[1][5]; - //u[2][0] *= v[2][0]; u[2][1] *= v[2][1]; u[2][2] *= v[2][2]; u[2][3] *= v[2][3]; u[2][4] *= v[2][4]; u[2][5] *= v[2][5]; - //u[3][0] *= v[3][0]; u[3][1] *= v[3][1]; u[3][2] *= v[3][2]; u[3][3] *= v[3][3]; u[3][4] *= v[3][4]; u[3][5] *= v[3][5]; - //u[4][0] *= v[4][0]; u[4][1] *= v[4][1]; u[4][2] *= v[4][2]; u[4][3] *= v[4][3]; u[4][4] *= v[4][4]; u[4][5] *= v[4][5]; - //u[5][0] *= v[5][0]; u[5][1] *= v[5][1]; u[5][2] *= v[5][2]; u[5][3] *= v[5][3]; u[5][4] *= v[5][4]; u[5][5] *= v[5][5]; - - //u0 *= v0; - //u1 *= v1; - //u2 *= v2; - //u3 *= v3; - //u4 *= v4; - //u5 *= v5; - //u6 *= v6; - //u7 *= v7; - //u8 *= v8; - - acc += ApplyWinnogradA(v0, v1, v2, v3, v4, v5, v6, v7, v8); - #endif - - #if KERNEL_SHAPE == 3 - if (y + 0 < O.height && x + 0 < O.width) - O.SetWithActivation(n, y + 0, x + 0, k, acc[0][0]); - if (y + 0 < O.height && x + 1 < O.width) - O.SetWithActivation(n, y + 0, x + 1, k, acc[0][1]); - if (y + 1 < O.height && x + 0 < O.width) - O.SetWithActivation(n, y + 1, x + 0, k, acc[1][0]); - if (y + 1 < O.height && x + 1 < O.width) - O.SetWithActivation(n, y + 1, x + 1, k, acc[1][1]); - #elif KERNEL_SHAPE == 5 - if (y + 0 < O.height && x + 0 < O.width) - O.SetWithActivation(n, y + 0, x + 0, k, acc[0][0]); - if (y + 0 < O.height && x + 1 < O.width) - O.SetWithActivation(n, y + 0, x + 1, k, acc[0][1]); - if (y + 1 < O.height && x + 0 < O.width) - O.SetWithActivation(n, y + 1, x + 0, k, acc[1][0]); - if (y + 1 < O.height && x + 1 < O.width) - O.SetWithActivation(n, y + 1, x + 1, k, acc[1][1]); - #endif - } -} - -#define CACHEBLOCK 32 - -#if USELDS -groupshared float CACHE_NAME(Conv2D_Winograd, OUTPUT_SHAPE, KERNEL_SHAPE, LDS)[2175]; -#endif - -[numthreads(32, 2, 2)] -void FUNC_NAME(Conv2D_Winograd, OUTPUT_SHAPE, KERNEL_SHAPE)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex, uint3 groupID : SV_GroupID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - -#if USELDS - #define LDS_ CACHE_NAME(Conv2D_Winograd, OUTPUT_SHAPE, KERNEL_SHAPE, LDS) -#endif - - uint k = dispatchThreadID.x; - uint x = 2 * dispatchThreadID.y; - uint y = 2 * dispatchThreadID.z; - - //if (k >= K.channels) return; - - for (uint n = 0; n < O.batch; ++n) - { - - float4x4 acc4 = 0.0; - for (uint c = 0; c < X.channels; c += CACHEBLOCK) - { - #if USELDS - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 0 + 0)] = X.SafeGet(n, uint2(x, y) + uint2(0, 0), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 0 + 1)] = X.SafeGet(n, uint2(x, y) + uint2(1, 0), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 0 + 2)] = X.SafeGet(n, uint2(x, y) + uint2(2, 0), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 0 + 3)] = X.SafeGet(n, uint2(x, y) + uint2(3, 0), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 1 + 0)] = X.SafeGet(n, uint2(x, y) + uint2(0, 1), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 1 + 1)] = X.SafeGet(n, uint2(x, y) + uint2(1, 1), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 1 + 2)] = X.SafeGet(n, uint2(x, y) + uint2(2, 1), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 1 + 3)] = X.SafeGet(n, uint2(x, y) + uint2(3, 1), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 2 + 0)] = X.SafeGet(n, uint2(x, y) + uint2(0, 2), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 2 + 1)] = X.SafeGet(n, uint2(x, y) + uint2(1, 2), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 2 + 2)] = X.SafeGet(n, uint2(x, y) + uint2(2, 2), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 2 + 3)] = X.SafeGet(n, uint2(x, y) + uint2(3, 2), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 3 + 0)] = X.SafeGet(n, uint2(x, y) + uint2(0, 3), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 3 + 1)] = X.SafeGet(n, uint2(x, y) + uint2(1, 3), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 3 + 2)] = X.SafeGet(n, uint2(x, y) + uint2(2, 3), c + (groupThreadID.x), _Pad.xy); - LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + (groupThreadID.x) * 17 + (4 * 3 + 3)] = X.SafeGet(n, uint2(x, y) + uint2(3, 3), c + (groupThreadID.x), _Pad.xy); - - GroupMemoryBarrierWithGroupSync(); - #endif - - for (uint cc = 0; cc < CACHEBLOCK; cc++) - { - -#if KERNEL_SHAPE == 3 - // 16 loads per thread - float4x4 d; - #if USELDS - d[0][0] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 0 + 0)]; - d[0][1] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 0 + 1)]; - d[0][2] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 0 + 2)]; - d[0][3] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 0 + 3)]; - d[1][0] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 1 + 0)]; - d[1][1] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 1 + 1)]; - d[1][2] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 1 + 2)]; - d[1][3] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 1 + 3)]; - d[2][0] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 2 + 0)]; - d[2][1] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 2 + 1)]; - d[2][2] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 2 + 2)]; - d[2][3] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 2 + 3)]; - d[3][0] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 3 + 0)]; - d[3][1] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 3 + 1)]; - d[3][2] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 3 + 2)]; - d[3][3] = LDS_[17*32*(groupThreadID.y*2+groupThreadID.z) + 17*cc + (4 * 3 + 3)]; - #else - d[0][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 0), c + cc, _Pad.xy); - d[0][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 0), c + cc, _Pad.xy); - d[0][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 0), c + cc, _Pad.xy); - d[0][3] = X.SafeGet(n, uint2(x, y) + uint2(3, 0), c + cc, _Pad.xy); - d[1][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 1), c + cc, _Pad.xy); - d[1][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 1), c + cc, _Pad.xy); - d[1][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 1), c + cc, _Pad.xy); - d[1][3] = X.SafeGet(n, uint2(x, y) + uint2(3, 1), c + cc, _Pad.xy); - d[2][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 2), c + cc, _Pad.xy); - d[2][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 2), c + cc, _Pad.xy); - d[2][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 2), c + cc, _Pad.xy); - d[2][3] = X.SafeGet(n, uint2(x, y) + uint2(3, 2), c + cc, _Pad.xy); - d[3][0] = X.SafeGet(n, uint2(x, y) + uint2(0, 3), c + cc, _Pad.xy); - d[3][1] = X.SafeGet(n, uint2(x, y) + uint2(1, 3), c + cc, _Pad.xy); - d[3][2] = X.SafeGet(n, uint2(x, y) + uint2(2, 3), c + cc, _Pad.xy); - d[3][3] = X.SafeGet(n, uint2(x, y) + uint2(3, 3), c + cc, _Pad.xy); - #endif - - float4x4 v; - v[0][0] = K.Get(0, 0, c + cc, min(k, K.channels-1)); - v[0][1] = K.Get(0, 1, c + cc, min(k, K.channels-1)); - v[0][2] = K.Get(0, 2, c + cc, min(k, K.channels-1)); - v[0][3] = K.Get(0, 3, c + cc, min(k, K.channels-1)); - v[1][0] = K.Get(1, 0, c + cc, min(k, K.channels-1)); - v[1][1] = K.Get(1, 1, c + cc, min(k, K.channels-1)); - v[1][2] = K.Get(1, 2, c + cc, min(k, K.channels-1)); - v[1][3] = K.Get(1, 3, c + cc, min(k, K.channels-1)); - v[2][0] = K.Get(2, 0, c + cc, min(k, K.channels-1)); - v[2][1] = K.Get(2, 1, c + cc, min(k, K.channels-1)); - v[2][2] = K.Get(2, 2, c + cc, min(k, K.channels-1)); - v[2][3] = K.Get(2, 3, c + cc, min(k, K.channels-1)); - v[3][0] = K.Get(3, 0, c + cc, min(k, K.channels-1)); - v[3][1] = K.Get(3, 1, c + cc, min(k, K.channels-1)); - v[3][2] = K.Get(3, 2, c + cc, min(k, K.channels-1)); - v[3][3] = K.Get(3, 3, c + cc, min(k, K.channels-1)); - - - float4x4 u = ApplyWinnogradB(d); - - acc4 += v * u; -#endif - } - } - - float2x2 acc = (k < K.channels) ? B.FastGet(k) : 0.0f; -#if KERNEL_SHAPE == 3 - acc += ApplyWinnogradA(acc4); -#endif - - if (y + 0 < O.height && x + 0 < O.width && k < K.channels) - O.SetWithActivation(n, y + 0, x + 0, k, acc[0][0]); - if (y + 0 < O.height && x + 1 < O.width && k < K.channels) - O.SetWithActivation(n, y + 0, x + 1, k, acc[0][1]); - if (y + 1 < O.height && x + 0 < O.width && k < K.channels) - O.SetWithActivation(n, y + 1, x + 0, k, acc[1][0]); - if (y + 1 < O.height && x + 1 < O.width && k < K.channels) - O.SetWithActivation(n, y + 1, x + 1, k, acc[1][1]); - } -} - -#undef CACHEBLOCK -#undef FUNC_NAME_CALL -#undef FUNC_NAME - -#define FUNC_NAME_CALL(KERNEL, KERNEL_SHAPE) KERNEL##_##KERNEL_SHAPE##x##KERNEL_SHAPE -#define FUNC_NAME(KERNEL, KERNEL_SHAPE) FUNC_NAME_CALL(KERNEL, KERNEL_SHAPE) - -#if KERNEL_SHAPE == 5 -void ApplyWinnogradG(float g[5][5], out float V[6][6]) -{ - // mul(Winograd_G, mul(g, Winograd_GT)); - //static const float5x6 Winograd_G = 1/24 * {{6, 0, 0, 0, 0}, {-4, -4, -4, -4, -4}, {-4, 4, -4, 4, -4⎥}, {1, 2, 4, 8, 16}, {1, -2, 4, -8, 16}, {0, 0, 0, 0, 24}} - //static const float6x5 Winograd_GT = 1/24 * {{6, -4, -4, 1, 1, 0}, {0, -4, 4, 2, -2, 0}, {0, -4, -4, 4, 4, 0}, {0, -4, 4, 8, -8, 0}, {0, -4, -4, 16, 16, 24}} - - float a00 = 6 * g[0][0] / 24; - float a10 = 6 * g[1][0] / 24; - float a20 = 6 * g[2][0] / 24; - float a30 = 6 * g[3][0] / 24; - float a40 = 6 * g[4][0] / 24; - - float a01 = (-4 * g[0][0] - 4 * g[0][1] - 4 * g[0][2] - 4 * g[0][3] - 4 * g[0][4]) / 24; - float a11 = (-4 * g[1][0] - 4 * g[1][1] - 4 * g[1][2] - 4 * g[1][3] - 4 * g[1][4]) / 24; - float a21 = (-4 * g[2][0] - 4 * g[2][1] - 4 * g[2][2] - 4 * g[2][3] - 4 * g[2][4]) / 24; - float a31 = (-4 * g[3][0] - 4 * g[3][1] - 4 * g[3][2] - 4 * g[3][3] - 4 * g[3][4]) / 24; - float a41 = (-4 * g[4][0] - 4 * g[4][1] - 4 * g[4][2] - 4 * g[4][3] - 4 * g[4][4]) / 24; - - float a02 = (-4 * g[0][0] + 4 * g[0][1] - 4 * g[0][2] + 4 * g[0][3] - 4 * g[0][4]) / 24; - float a12 = (-4 * g[1][0] + 4 * g[1][1] - 4 * g[1][2] + 4 * g[1][3] - 4 * g[1][4]) / 24; - float a22 = (-4 * g[2][0] + 4 * g[2][1] - 4 * g[2][2] + 4 * g[2][3] - 4 * g[2][4]) / 24; - float a32 = (-4 * g[3][0] + 4 * g[3][1] - 4 * g[3][2] + 4 * g[3][3] - 4 * g[3][4]) / 24; - float a42 = (-4 * g[4][0] + 4 * g[4][1] - 4 * g[4][2] + 4 * g[4][3] - 4 * g[4][4]) / 24; - - float a03 = (g[0][0] + 2 * g[0][1] + 4 * g[0][2] + 8 * g[0][3] + 16 * g[0][4]) / 24; - float a13 = (g[1][0] + 2 * g[1][1] + 4 * g[1][2] + 8 * g[1][3] + 16 * g[1][4]) / 24; - float a23 = (g[2][0] + 2 * g[2][1] + 4 * g[2][2] + 8 * g[2][3] + 16 * g[2][4]) / 24; - float a33 = (g[3][0] + 2 * g[3][1] + 4 * g[3][2] + 8 * g[3][3] + 16 * g[3][4]) / 24; - float a43 = (g[4][0] + 2 * g[4][1] + 4 * g[4][2] + 8 * g[4][3] + 16 * g[4][4]) / 24; - - float a04 = (g[0][0] - 2 * g[0][1] + 4 * g[0][2] - 8 * g[0][3] + 16 * g[0][4]) / 24; - float a14 = (g[1][0] - 2 * g[1][1] + 4 * g[1][2] - 8 * g[1][3] + 16 * g[1][4]) / 24; - float a24 = (g[2][0] - 2 * g[2][1] + 4 * g[2][2] - 8 * g[2][3] + 16 * g[2][4]) / 24; - float a34 = (g[3][0] - 2 * g[3][1] + 4 * g[3][2] - 8 * g[3][3] + 16 * g[3][4]) / 24; - float a44 = (g[4][0] - 2 * g[4][1] + 4 * g[4][2] - 8 * g[4][3] + 16 * g[4][4]) / 24; - - float a05 = g[0][4]; - float a15 = g[1][4]; - float a25 = g[2][4]; - float a35 = g[3][4]; - float a45 = g[4][4]; - - V[0][0] = 6 * a00 / 24; - V[0][1] = 6 * a01 / 24; - V[0][2] = 6 * a02 / 24; - V[0][3] = 6 * a03 / 24; - V[0][4] = 6 * a04 / 24; - V[0][5] = 6 * a05 / 24; - - V[1][0] = (-4 * a00 - 4 * a10 - 4 * a20 - 4 * a30 - 4 * a40) / 24; - V[1][1] = (-4 * a01 - 4 * a11 - 4 * a21 - 4 * a31 - 4 * a41) / 24; - V[1][2] = (-4 * a02 - 4 * a12 - 4 * a22 - 4 * a32 - 4 * a42) / 24; - V[1][3] = (-4 * a03 - 4 * a13 - 4 * a23 - 4 * a33 - 4 * a43) / 24; - V[1][4] = (-4 * a04 - 4 * a14 - 4 * a24 - 4 * a34 - 4 * a44) / 24; - V[1][5] = (-4 * a05 - 4 * a15 - 4 * a25 - 4 * a35 - 4 * a45) / 24; - - V[2][0] = (-4 * a00 + 4 * a10 - 4 * a20 + 4 * a30 - 4 * a40) / 24; - V[2][1] = (-4 * a01 + 4 * a11 - 4 * a21 + 4 * a31 - 4 * a41) / 24; - V[2][2] = (-4 * a02 + 4 * a12 - 4 * a22 + 4 * a32 - 4 * a42) / 24; - V[2][3] = (-4 * a03 + 4 * a13 - 4 * a23 + 4 * a33 - 4 * a43) / 24; - V[2][4] = (-4 * a04 + 4 * a14 - 4 * a24 + 4 * a34 - 4 * a44) / 24; - V[2][5] = (-4 * a05 + 4 * a15 - 4 * a25 + 4 * a35 - 4 * a45) / 24; - - V[3][0] = (a00 + 2 * a10 + 4 * a20 + 8 * a30 + 16 * a40) / 24; - V[3][1] = (a01 + 2 * a11 + 4 * a21 + 8 * a31 + 16 * a41) / 24; - V[3][2] = (a02 + 2 * a12 + 4 * a22 + 8 * a32 + 16 * a42) / 24; - V[3][3] = (a03 + 2 * a13 + 4 * a23 + 8 * a33 + 16 * a43) / 24; - V[3][4] = (a04 + 2 * a14 + 4 * a24 + 8 * a34 + 16 * a44) / 24; - V[3][5] = (a05 + 2 * a15 + 4 * a25 + 8 * a35 + 16 * a45) / 24; - - V[4][0] = (a00 - 2 * a10 + 4 * a20 - 8 * a30 + 16 * a40) / 24; - V[4][1] = (a01 - 2 * a11 + 4 * a21 - 8 * a31 + 16 * a41) / 24; - V[4][2] = (a02 - 2 * a12 + 4 * a22 - 8 * a32 + 16 * a42) / 24; - V[4][3] = (a03 - 2 * a13 + 4 * a23 - 8 * a33 + 16 * a43) / 24; - V[4][4] = (a04 - 2 * a14 + 4 * a24 - 8 * a34 + 16 * a44) / 24; - V[4][5] = (a05 - 2 * a15 + 4 * a25 - 8 * a35 + 16 * a45) / 24; - - V[5][0] = a40; - V[5][1] = a41; - V[5][2] = a42; - V[5][3] = a43; - V[5][4] = a44; - V[5][5] = a45; -} -#endif - -[numthreads(4, 4, 4)] -void FUNC_NAME(KernelWinograd, KERNEL_SHAPE)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_SHARED_MODEL(K, WBK); TENSOR_SHARED_MODEL(B, WBK); TENSOR_ARG_RW(O) - - uint k = dispatchThreadID.x; - uint c = dispatchThreadID.y; - uint i = dispatchThreadID.z; - - if (c >= K.GetKernelDepth()) return; - if (k >= K.GetKernelCount()) return; - - #if KERNEL_SHAPE == 5 - float g[5][5]; - g[0][0] = K.Get(0, 0, 0, k); - g[0][1] = K.Get(0, 1, 0, k); - g[0][2] = K.Get(0, 2, 0, k); - g[0][3] = K.Get(0, 3, 0, k); - g[0][4] = K.Get(0, 4, 0, k); - - g[1][0] = K.Get(1, 0, 0, k); - g[1][1] = K.Get(1, 1, 0, k); - g[1][2] = K.Get(1, 2, 0, k); - g[1][3] = K.Get(1, 3, 0, k); - g[1][4] = K.Get(1, 4, 0, k); - - g[2][0] = K.Get(2, 0, 0, k); - g[2][1] = K.Get(2, 1, 0, k); - g[2][2] = K.Get(2, 2, 0, k); - g[2][3] = K.Get(2, 3, 0, k); - g[2][4] = K.Get(2, 4, 0, k); - - g[3][0] = K.Get(3, 0, 0, k); - g[3][1] = K.Get(3, 1, 0, k); - g[3][2] = K.Get(3, 2, 0, k); - g[3][3] = K.Get(3, 3, 0, k); - g[3][4] = K.Get(3, 4, 0, k); - - g[4][0] = K.Get(4, 0, 0, k); - g[4][1] = K.Get(4, 1, 0, k); - g[4][2] = K.Get(4, 2, 0, k); - g[4][3] = K.Get(4, 3, 0, k); - g[4][4] = K.Get(4, 4, 0, k); - - float v[6][6]; - ApplyWinnogradG(g, v); - - O.Set(0, 0, c, k, v[0][0]); - O.Set(1, 0, c, k, v[1][0]); - O.Set(2, 0, c, k, v[2][0]); - O.Set(3, 0, c, k, v[3][0]); - O.Set(4, 0, c, k, v[4][0]); - O.Set(5, 0, c, k, v[5][0]); - - O.Set(0, 1, c, k, v[0][1]); - O.Set(1, 1, c, k, v[1][1]); - O.Set(2, 1, c, k, v[2][1]); - O.Set(3, 1, c, k, v[3][1]); - O.Set(4, 1, c, k, v[4][1]); - O.Set(5, 1, c, k, v[5][1]); - - O.Set(0, 2, c, k, v[0][2]); - O.Set(1, 2, c, k, v[1][2]); - O.Set(2, 2, c, k, v[2][2]); - O.Set(3, 2, c, k, v[3][2]); - O.Set(4, 2, c, k, v[4][2]); - O.Set(5, 2, c, k, v[5][2]); - - O.Set(0, 3, c, k, v[0][3]); - O.Set(1, 3, c, k, v[1][3]); - O.Set(2, 3, c, k, v[2][3]); - O.Set(3, 3, c, k, v[3][3]); - O.Set(4, 3, c, k, v[4][3]); - O.Set(5, 3, c, k, v[5][3]); - - O.Set(0, 4, c, k, v[0][4]); - O.Set(1, 4, c, k, v[1][4]); - O.Set(2, 4, c, k, v[2][4]); - O.Set(3, 4, c, k, v[3][4]); - O.Set(4, 4, c, k, v[4][4]); - O.Set(5, 4, c, k, v[5][4]); - - O.Set(0, 5, c, k, v[0][5]); - O.Set(1, 5, c, k, v[1][5]); - O.Set(2, 5, c, k, v[2][5]); - O.Set(3, 5, c, k, v[3][5]); - O.Set(4, 5, c, k, v[4][5]); - O.Set(5, 5, c, k, v[5][5]); - #endif - - uint kLength = (K.GetKernelHeight() + 1) * (K.GetKernelWidth() + 1) * K.GetKernelDepth() * K.GetKernelCount(); - if (i < B.GetLength()) - O.FastSet(kLength + i, B.FastGet(i)); -} - -#undef FUNC_NAME_CALL -#undef FUNC_NAME - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, KERNEL_SHAPE, IBLOCK, KBLOCK, JBLOCK) KERNEL##_Kernel##KERNEL_SHAPE##x##KERNEL_SHAPE##_##IBLOCK##x##KBLOCK##x##JBLOCK##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, KERNEL_SHAPE, IBLOCK, KBLOCK, JBLOCK) KERNEL##_Kernel##KERNEL_SHAPE##x##KERNEL_SHAPE##_##IBLOCK##x##KBLOCK##x##JBLOCK##_NHWC -#endif -#define FUNC_NAME(KERNEL, KERNEL_SHAPE, IBLOCK, KBLOCK, JBLOCK) FUNC_NAME_CALL(KERNEL, KERNEL_SHAPE, IBLOCK, KBLOCK, JBLOCK) - -// GPU_Pro_5_Advanced_Rendering_Techniques -// Cache-blocked implementation: 1x4x4 gemm with ^K_cache = 32 - -#define CACHEBLOCK 2 - -[numthreads(16, 4, 4)] -void FUNC_NAME(Conv2D, KERNEL_SHAPE, IBLOCK, KBLOCK, JBLOCK)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - uint width = O.width; - uint height = O.height; - uint batches = O.batch; - uint channels = (X.channels + 4 - 1) / 4; - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - for (uint n = 0; n < O.batch; ++n) - { - float4 acc = float4(B.FastGet(min(4 * k + 0, K.channels - 1)), B.FastGet(min(4 * k + 1, K.channels - 1)), B.FastGet(min(4 * k + 2, K.channels - 1)), B.FastGet(min(4 * k + 3, K.channels - 1))); - - for (uint c = 0; c < channels; c += CACHEBLOCK) - { - for (uint cc = 0; cc < CACHEBLOCK; ++cc) - { - float w00 = K.Get(0, 0, 4 * (c + cc) + 0, min(4 * k + 0, K.channels - 1)); - float w01 = K.Get(0, 0, 4 * (c + cc) + 1, min(4 * k + 0, K.channels - 1)); - float w02 = K.Get(0, 0, 4 * (c + cc) + 2, min(4 * k + 0, K.channels - 1)); - float w03 = K.Get(0, 0, 4 * (c + cc) + 3, min(4 * k + 0, K.channels - 1)); - - float w10 = K.Get(0, 0, 4 * (c + cc) + 0, min(4 * k + 1, K.channels - 1)); - float w11 = K.Get(0, 0, 4 * (c + cc) + 1, min(4 * k + 1, K.channels - 1)); - float w12 = K.Get(0, 0, 4 * (c + cc) + 2, min(4 * k + 1, K.channels - 1)); - float w13 = K.Get(0, 0, 4 * (c + cc) + 3, min(4 * k + 1, K.channels - 1)); - - float w20 = K.Get(0, 0, 4 * (c + cc) + 0, min(4 * k + 2, K.channels - 1)); - float w21 = K.Get(0, 0, 4 * (c + cc) + 1, min(4 * k + 2, K.channels - 1)); - float w22 = K.Get(0, 0, 4 * (c + cc) + 2, min(4 * k + 2, K.channels - 1)); - float w23 = K.Get(0, 0, 4 * (c + cc) + 3, min(4 * k + 2, K.channels - 1)); - - float w30 = K.Get(0, 0, 4 * (c + cc) + 0, min(4 * k + 3, K.channels - 1)); - float w31 = K.Get(0, 0, 4 * (c + cc) + 1, min(4 * k + 3, K.channels - 1)); - float w32 = K.Get(0, 0, 4 * (c + cc) + 2, min(4 * k + 3, K.channels - 1)); - float w33 = K.Get(0, 0, 4 * (c + cc) + 3, min(4 * k + 3, K.channels - 1)); - - - - float v0 = X.SafeGet(n, uint2(x, y) * _Stride.xy, 4 * (c + cc) + 0, _Pad.xy); - float v1 = X.SafeGet(n, uint2(x, y) * _Stride.xy, 4 * (c + cc) + 1, _Pad.xy); - float v2 = X.SafeGet(n, uint2(x, y) * _Stride.xy, 4 * (c + cc) + 2, _Pad.xy); - float v3 = X.SafeGet(n, uint2(x, y) * _Stride.xy, 4 * (c + cc) + 3, _Pad.xy); - - acc.x += dot(float4(v0, v1, v2, v3), float4(w00, w01, w02, w03)); - acc.y += dot(float4(v0, v1, v2, v3), float4(w10, w11, w12, w13)); - acc.z += dot(float4(v0, v1, v2, v3), float4(w20, w21, w22, w23)); - acc.w += dot(float4(v0, v1, v2, v3), float4(w30, w31, w32, w33)); - } - - DeviceMemoryBarrierWithGroupSync(); - } - - if (y < height && x < width && 4 * k + 0 < K.channels) - O.SetWithActivation(n, y, x, 4 * k + 0, acc.x); - if (y < height && x < width && 4 * k + 1 < K.channels) - O.SetWithActivation(n, y, x, 4 * k + 1, acc.y); - if (y < height && x < width && 4 * k + 2 < K.channels) - O.SetWithActivation(n, y, x, 4 * k + 2, acc.z); - if (y < height && x < width && 4 * k + 3 < K.channels) - O.SetWithActivation(n, y, x, 4 * k + 3, acc.w); - } -} - -#if BLOCK_SIZE == 4 - -#undef FUNC_NAME_CALL -#undef CACHE_NAME_CALL -#undef FUNC_NAME -#undef CACHE_NAME - -#define KERNEL_NAME Conv2D - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) KERNEL##_##SUFFIX##SIZE##x##SIZE##_NCHW - #define CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) KERNEL##_##SUFFIX##SIZE##x##SIZE##_Cache_##TENSOR##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) KERNEL##_##SUFFIX##SIZE##x##SIZE##_NHWC - #define CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) KERNEL##_##SUFFIX##SIZE##x##SIZE##_Cache_##TENSOR##_NHWC -#endif -#define FUNC_NAME(KERNEL, SUFFIX, SIZE) FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) -#define CACHE_NAME(KERNEL, SUFFIX, SIZE, TENSOR) CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) - -#if KERNEL_PER_TG == 256 -#define CACHE_DEPTH 16 // This kernel code supports only CACHE_DEPTH=16, this value can not be changed -#if CHANNELS_FIRST -groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS)[CACHE_DEPTH * 16 * BLOCK_SIZE + CACHE_DEPTH * 64]; -#else -groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS)[CACHE_DEPTH * 16 * BLOCK_SIZE + CACHE_DEPTH * 66]; -#endif -[numthreads(16, 16, 1)] -void FUNC_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex, uint3 groupID : SV_GroupID) -{ - //DISPATCH ARGS(K.kernelCount, O.width * O.height, O.batch); // in NCHW - - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - // [W*H, Ky*Kx*In] * [Ky*Kx*In, Out] => [W*H, Out] -#define LDS_ CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS) -#define X_OFFSET 0 -#if CHANNELS_FIRST -#define W_OFFSET CACHE_DEPTH*64 -#else -#define W_OFFSET CACHE_DEPTH*66 -#endif - - uint x = dispatchThreadID.x * BLOCK_SIZE; // output_channels - uint y = dispatchThreadID.y * BLOCK_SIZE; // batch*width*height (width*height in HWC) - uint tx = groupThreadID.x; - uint ty = groupThreadID.y; - uint bx = (16 * groupID.x) * BLOCK_SIZE; - uint by = (16 * groupID.y) * BLOCK_SIZE; - uint ti = threadIndex; - uint w = O.width; - uint h = O.height; - uint batches = X.batch; - uint channels = X.channels; - uint widthX = X.width; - uint heightX = X.height; - uint strideX = X.channels; - uint strideK = K.channels; - uint strideO = O.channels; - uint batchReadOffset = dispatchThreadID.z * channels * heightX * widthX; - uint batchWriteOffset = dispatchThreadID.z * strideO * h * w; -#if CHANNELS_FIRST - uint kernelBaseId = groupID.x * 64; - uint outputPixelBaseId = groupID.y * 64; - uint numOuputPixels = w * h; -#endif - - - float4 dstA0; - float4 dstA1; - float4 dstA2; - float4 dstA3; - - uint maxBiasIndex = O.channels - 1; - dstA0.x = B.FastGet(min(maxBiasIndex, x + 0)); dstA0.y = B.FastGet(min(maxBiasIndex, x + 1)); dstA0.z = B.FastGet(min(maxBiasIndex, x + 2)); dstA0.w = B.FastGet(min(maxBiasIndex, x + 3)); - dstA1 = dstA0; - dstA2 = dstA0; - dstA3 = dstA0; - - - uint readK = strideK * (ti >> 6) + (bx | (ti & 63)); - bool maskK = (bx + (ti & 63)) < strideK; - -#if CHANNELS_FIRST - uint centroidId = by | (ti & 63); -#if KERNEL_1x1 - uint topY = (centroidId / w % h) * _Stride.y; - uint leftX = (centroidId % w) * _Stride.x; -#else - uint topY = (centroidId / w % h) * _Stride.y - _Pad.y; - uint leftX = (centroidId % w) * _Stride.x - _Pad.x; -#endif - uint cornerId = topY * widthX + leftX; - uint readX = heightX * widthX * (ti >> 6) + cornerId + batchReadOffset; - bool mask; -#else - uint4 centroidId = uint4( - (by | 16 * 0 | (ti >> 4)), - (by | 16 * 1 | (ti >> 4)), - (by | 16 * 2 | (ti >> 4)), - (by | 16 * 3 | (ti >> 4))); - -#if KERNEL_1x1 - uint4 topY = (centroidId / w % h) * _Stride.y; - uint4 leftX = (centroidId % w) * _Stride.x; -#else - uint4 topY = (centroidId / w % h) * _Stride.y - _Pad.y; - uint4 leftX = (centroidId % w) * _Stride.x - _Pad.x; -#endif - uint4 cornerId = topY * widthX + leftX; - uint4 readX = strideX * cornerId + (ti & 15) + batchReadOffset; - bool4 mask; -#endif - -#if KERNEL_1x1 - uint kernelOffsetX = 0; - mask = (centroidId / w % h) * _Stride.y < heightX && - (centroidId % w) * _Stride.x < widthX; -#else - for (uint dy = 0; dy < K.GetKernelHeight(); dy++) - { - for (uint dx = 0; dx < K.GetKernelWidth(); dx++) - { - #if CHANNELS_FIRST - uint kernelOffsetX = (dy * widthX + dx); - #else - uint kernelOffsetX = (dy * widthX + dx) * strideX; - #endif - - mask = - ((centroidId / w % h) * _Stride.y + dy) >= _Pad.y && - ((centroidId / w % h) * _Stride.y + dy) < (heightX + _Pad.y) && - ((centroidId % w) * _Stride.x + dx) >= _Pad.x && - ((centroidId % w) * _Stride.x + dx) < (widthX + _Pad.x); -#endif - for (uint i = 0; i < channels; i += CACHE_DEPTH) - { - bool4 maskChannelsK = ti + 64 * (i + uint4(0, 1, 2, 3) * 4) < 64 * channels; - - #if CHANNELS_FIRST - bool4 maskChannelsX = maskChannelsK; - #else - bool maskChannelsX = (ti % 16) + i < channels; - #endif - - - LDS_[W_OFFSET + (0 << 8) + (ti & 0x1C0) + ((ti & 3) << 4) | ((ti & 63) >> 2)] = K.MaskedGet(maskK & maskChannelsK.x, readK); - readK += strideK * (channels <= (i + 0 * 4) ? 0 : min(channels - (i + 0 * 4), 4)); - LDS_[W_OFFSET + (1 << 8) + (ti & 0x1C0) + ((ti & 3) << 4) | ((ti & 63) >> 2)] = K.MaskedGet(maskK & maskChannelsK.y, readK); - readK += strideK * (channels <= (i + 1 * 4) ? 0 : min(channels - (i + 1 * 4), 4)); - LDS_[W_OFFSET + (2 << 8) + (ti & 0x1C0) + ((ti & 3) << 4) | ((ti & 63) >> 2)] = K.MaskedGet(maskK & maskChannelsK.z, readK); - readK += strideK * (channels <= (i + 2 * 4) ? 0 : min(channels - (i + 2 * 4), 4)); - LDS_[W_OFFSET + (3 << 8) + (ti & 0x1C0) + ((ti & 3) << 4) | ((ti & 63) >> 2)] = K.MaskedGet(maskK & maskChannelsK.w, readK); - readK += strideK * (channels <= (i + 3 * 4) ? 0 : min(channels - (i + 3 * 4), 4)); - - - #if CHANNELS_FIRST - LDS_[X_OFFSET + ti + 256 * 0] = X.MaskedGet(mask && maskChannelsX.x, readX + heightX * widthX * (i + 0 * 4) + kernelOffsetX); - LDS_[X_OFFSET + ti + 256 * 1] = X.MaskedGet(mask && maskChannelsX.y, readX + heightX * widthX * (i + 1 * 4) + kernelOffsetX); - LDS_[X_OFFSET + ti + 256 * 2] = X.MaskedGet(mask && maskChannelsX.z, readX + heightX * widthX * (i + 2 * 4) + kernelOffsetX); - LDS_[X_OFFSET + ti + 256 * 3] = X.MaskedGet(mask && maskChannelsX.w, readX + heightX * widthX * (i + 3 * 4) + kernelOffsetX); - #else - LDS_[X_OFFSET + 66 * (ti & 15) + (16 * 0 | (ti >> 4))] = X.MaskedGet(mask.x && maskChannelsX, readX.x + i + kernelOffsetX); - LDS_[X_OFFSET + 66 * (ti & 15) + (16 * 1 | (ti >> 4))] = X.MaskedGet(mask.y && maskChannelsX, readX.y + i + kernelOffsetX); - LDS_[X_OFFSET + 66 * (ti & 15) + (16 * 2 | (ti >> 4))] = X.MaskedGet(mask.z && maskChannelsX, readX.z + i + kernelOffsetX); - LDS_[X_OFFSET + 66 * (ti & 15) + (16 * 3 | (ti >> 4))] = X.MaskedGet(mask.w && maskChannelsX, readX.w + i + kernelOffsetX); - #endif - GroupMemoryBarrierWithGroupSync(); - - - for (uint di = 0; di < CACHE_DEPTH; di++) - { - // [0..15]*64 + [0..3]*16 + [0..15] - float4 srcW = float4( - LDS_[W_OFFSET + di * 64 + (0 * 16 | tx)], - LDS_[W_OFFSET + di * 64 + (1 * 16 | tx)], - LDS_[W_OFFSET + di * 64 + (2 * 16 | tx)], - LDS_[W_OFFSET + di * 64 + (3 * 16 | tx)] - ); - - #if CHANNELS_FIRST - // [0..15]*64 + [0..15]*4 + [0..3] - float4 srcX = float4( - LDS_[X_OFFSET + di * 64 + ((ty << 2) | 0)], - LDS_[X_OFFSET + di * 64 + ((ty << 2) | 1)], - LDS_[X_OFFSET + di * 64 + ((ty << 2) | 2)], - LDS_[X_OFFSET + di * 64 + ((ty << 2) | 3)]); - #else - // [0..15]*64 + [0..15]*4 + [0..3] - float4 srcX = float4( - LDS_[X_OFFSET + di * 66 + ((ty << 2) | 0)], - LDS_[X_OFFSET + di * 66 + ((ty << 2) | 1)], - LDS_[X_OFFSET + di * 66 + ((ty << 2) | 2)], - LDS_[X_OFFSET + di * 66 + ((ty << 2) | 3)]); - #endif - - dstA0 += srcX.x * srcW; - dstA1 += srcX.y * srcW; - dstA2 += srcX.z * srcW; - dstA3 += srcX.w * srcW; - } - - GroupMemoryBarrierWithGroupSync(); - } -#if KERNEL_1x1 -#else - } - } -#endif - -#if CHANNELS_FIRST - if (((y + 0) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation((y + 0) + (x + 0)*h*w + batchWriteOffset, dstA0.x); - if (((y + 0) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation((y + 0) + (x + 1)*h*w + batchWriteOffset, dstA0.y); - if (((y + 0) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation((y + 0) + (x + 2)*h*w + batchWriteOffset, dstA0.z); - if (((y + 0) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation((y + 0) + (x + 3)*h*w + batchWriteOffset, dstA0.w); - - if (((y + 1) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation( (y + 1) + (x + 0)*h*w + batchWriteOffset, dstA1.x); - if (((y + 1) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation( (y + 1) + (x + 1)*h*w + batchWriteOffset, dstA1.y); - if (((y + 1) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation( (y + 1) + (x + 2)*h*w + batchWriteOffset, dstA1.z); - if (((y + 1) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation( (y + 1) + (x + 3)*h*w + batchWriteOffset, dstA1.w); - - if (((y + 2) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation((y + 2) + (x + 0)*h*w + batchWriteOffset, dstA2.x); - if (((y + 2) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation((y + 2) + (x + 1)*h*w + batchWriteOffset, dstA2.y); - if (((y + 2) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation((y + 2) + (x + 2)*h*w + batchWriteOffset, dstA2.z); - if (((y + 2) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation((y + 2) + (x + 3)*h*w + batchWriteOffset, dstA2.w); - - if (((y + 3) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation((y + 3) + (x + 0)*h*w + batchWriteOffset, dstA3.x); - if (((y + 3) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation((y + 3) + (x + 1)*h*w + batchWriteOffset, dstA3.y); - if (((y + 3) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation((y + 3) + (x + 2)*h*w + batchWriteOffset, dstA3.z); - if (((y + 3) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation((y + 3) + (x + 3)*h*w + batchWriteOffset, dstA3.w); -#else - if (((y + 0) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 0) + x + 0, dstA0.x); - if (((y + 0) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 0) + x + 1, dstA0.y); - if (((y + 0) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 0) + x + 2, dstA0.z); - if (((y + 0) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 0) + x + 3, dstA0.w); - - if (((y + 1) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 1) + x + 0, dstA1.x); - if (((y + 1) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 1) + x + 1, dstA1.y); - if (((y + 1) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 1) + x + 2, dstA1.z); - if (((y + 1) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 1) + x + 3, dstA1.w); - - if (((y + 2) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 2) + x + 0, dstA2.x); - if (((y + 2) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 2) + x + 1, dstA2.y); - if (((y + 2) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 2) + x + 2, dstA2.z); - if (((y + 2) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 2) + x + 3, dstA2.w); - - if (((y + 3) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 3) + x + 0, dstA3.x); - if (((y + 3) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 3) + x + 1, dstA3.y); - if (((y + 3) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 3) + x + 2, dstA3.z); - if (((y + 3) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 3) + x + 3, dstA3.w); -#endif - - -#undef X_ -#undef W_ -#undef LDS_ -#undef X_OFFSET -#undef W_OFFSET -} -#undef CACHE_DEPTH -#undef BUF_OFFSET -#elif KERNEL_PER_TG == 64 -#define CACHE_DEPTH 8 -groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS)[2 * CACHE_DEPTH * 8 * BLOCK_SIZE]; -[numthreads(8, 8, 1)] -void FUNC_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex, uint3 groupID : SV_GroupID) -{ - //DISPATCH ARGS(K.kernelCount, O.width * O.height * O.batch, 1); // in NHWC - //DISPATCH ARGS(K.kernelCount, O.width * O.height, O.batch); // in NCHW - - TENSOR_SHARED2_ARGS4(X, K, B, WBK, O); - - // [W*H, Ky*Kx*In] * [Ky*Kx*In, Out] => [W*H, Out] -#define LDS_ CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS) -#define X_OFFSET 0 -#define W_OFFSET CACHE_DEPTH*32 - - uint x = dispatchThreadID.x * BLOCK_SIZE; // output_channels - uint y = dispatchThreadID.y * BLOCK_SIZE; // batch*width*height (width*height in HWC) - uint tx = groupThreadID.x; - uint ty = groupThreadID.y; - uint bx = (8 * groupID.x) * BLOCK_SIZE; - uint by = (8 * groupID.y) * BLOCK_SIZE; - uint ti = threadIndex; - uint w = O.width; - uint h = O.height; - uint batches = X.batch; - uint channels = X.channels; - uint widthX = X.width; - uint heightX = X.height; - uint strideX = X.channels; - uint strideK = K.channels; - uint strideO = O.channels; - uint batchReadOffset = dispatchThreadID.z * channels * heightX * widthX; - uint batchWriteOffset = dispatchThreadID.z * strideO * h * w; -#if CHANNELS_FIRST - uint kernelBaseId = groupID.x * 32; - uint outputPixelBaseId = groupID.y * 32; - uint numOuputPixels = w * h; -#endif - - float4 dstA0; - float4 dstA1; - float4 dstA2; - float4 dstA3; - - uint maxBiasIndex = O.channels - 1; - dstA0.x = B.FastGet(min(maxBiasIndex, x + 0)); dstA0.y = B.FastGet(min(maxBiasIndex, x + 1)); dstA0.z = B.FastGet(min(maxBiasIndex, x + 2)); dstA0.w = B.FastGet(min(maxBiasIndex, x + 3)); - dstA1 = dstA0; - dstA2 = dstA0; - dstA3 = dstA0; - - uint readK = strideK * (ti >> 5) + (bx | (ti & 31)); - bool maskK = (bx | (ti & 31)) < strideK; - - -#if CHANNELS_FIRST - uint centroidId = by | (ti & 31); -#if KERNEL_1x1 - uint topY = (centroidId / w % h) * _Stride.y; - uint leftX = (centroidId % w) * _Stride.x; -#else - uint topY = (centroidId / w % h) * _Stride.y - _Pad.y; - uint leftX = (centroidId % w) * _Stride.x - _Pad.x; -#endif - uint cornerId = topY * widthX + leftX; - uint readX = heightX * widthX * (ti >> 5) + cornerId + batchReadOffset; - bool mask; -#else - uint4 centroidId = uint4( - (by | (ti >> 3) | 0 * 8), - (by | (ti >> 3) | 1 * 8), - (by | (ti >> 3) | 2 * 8), - (by | (ti >> 3) | 3 * 8)); - -#if KERNEL_1x1 - uint4 topY = (centroidId / w % h) * _Stride.y; - uint4 leftX = (centroidId % w) * _Stride.x; - -#else - uint4 topY = (centroidId / w % h) * _Stride.y - _Pad.y; - uint4 leftX = (centroidId % w) * _Stride.x - _Pad.x; -#endif - uint4 cornerId = topY * widthX + leftX; - uint4 readX = batchReadOffset + strideX * cornerId + (ti & 7); - bool4 mask; -#endif - -#if KERNEL_1x1 - uint kernelOffsetX = 0; - mask = (centroidId / w % h) * _Stride.y < heightX && - (centroidId % w) * _Stride.x < widthX; -#else - for (uint dy = 0; dy < K.GetKernelHeight(); dy++) - { - for (uint dx = 0; dx < K.GetKernelWidth(); dx++) - { - #if CHANNELS_FIRST - uint kernelOffsetX = (dy * widthX + dx); - #else - uint kernelOffsetX = (dy * widthX + dx) * strideX; - #endif - mask = - ((centroidId / w % h) * _Stride.y + dy) >= _Pad.y && - ((centroidId / w % h) * _Stride.y + dy) < (heightX + _Pad.y) && - ((centroidId % w) * _Stride.x + dx) >= _Pad.x && - ((centroidId % w) * _Stride.x + dx) < (widthX + _Pad.x); -#endif - for (uint i = 0; i < channels; i += CACHE_DEPTH) - { - bool4 maskChannelsK = (ti/32) + (i + uint4(0, 1, 2, 3) * 2) < channels; - - #if CHANNELS_FIRST - bool4 maskChannelsX = maskChannelsK; - #else - bool maskChannelsX = (ti % 8) + i < channels; - #endif - - LDS_[(0 * 64 + W_OFFSET) | (8 * (ti & 3) + (ti & 0x20)) | ((ti & 31) >> 2)] = K.MaskedGet(maskK & maskChannelsK.x, readK); - readK += strideK * (channels <= (i + 0 * 2) ? 0 : min(channels - (i + 0 * 2), 2)); - LDS_[(1 * 64 + W_OFFSET) | (8 * (ti & 3) + (ti & 0x20)) | ((ti & 31) >> 2)] = K.MaskedGet(maskK & maskChannelsK.y, readK); - readK += strideK * (channels <= (i + 1 * 2) ? 0 : min(channels - (i + 1 * 2), 2)); - LDS_[(2 * 64 + W_OFFSET) | (8 * (ti & 3) + (ti & 0x20)) | ((ti & 31) >> 2)] = K.MaskedGet(maskK & maskChannelsK.z, readK); - readK += strideK * (channels <= (i + 2 * 2) ? 0 : min(channels - (i + 2 * 2), 2)); - LDS_[(3 * 64 + W_OFFSET) | (8 * (ti & 3) + (ti & 0x20)) | ((ti & 31) >> 2)] = K.MaskedGet(maskK & maskChannelsK.w, readK); - readK += strideK * (channels <= (i + 3 * 2) ? 0 : min(channels - (i + 3 * 2), 2)); - - - #if CHANNELS_FIRST - LDS_[X_OFFSET + ti + 64 * 0] = X.MaskedGet(mask && maskChannelsX.x, readX + heightX * widthX * (i + 0 * 2) + kernelOffsetX); - LDS_[X_OFFSET + ti + 64 * 1] = X.MaskedGet(mask && maskChannelsX.y, readX + heightX * widthX * (i + 1 * 2) + kernelOffsetX); - LDS_[X_OFFSET + ti + 64 * 2] = X.MaskedGet(mask && maskChannelsX.z, readX + heightX * widthX * (i + 2 * 2) + kernelOffsetX); - LDS_[X_OFFSET + ti + 64 * 3] = X.MaskedGet(mask && maskChannelsX.w, readX + heightX * widthX * (i + 3 * 2) + kernelOffsetX); - #else - LDS_[(32 * (ti & 7) + (ti >> 3)) | (8 * 0 + X_OFFSET)] = X.MaskedGet(mask.x && maskChannelsX, readX.x + i + kernelOffsetX); - LDS_[(32 * (ti & 7) + (ti >> 3)) | (8 * 1 + X_OFFSET)] = X.MaskedGet(mask.y && maskChannelsX, readX.y + i + kernelOffsetX); - LDS_[(32 * (ti & 7) + (ti >> 3)) | (8 * 2 + X_OFFSET)] = X.MaskedGet(mask.z && maskChannelsX, readX.z + i + kernelOffsetX); - LDS_[(32 * (ti & 7) + (ti >> 3)) | (8 * 3 + X_OFFSET)] = X.MaskedGet(mask.w && maskChannelsX, readX.w + i + kernelOffsetX); - #endif - - GroupMemoryBarrierWithGroupSync(); - - for (uint di = 0; di < CACHE_DEPTH; di++) - { - float4 srcX = float4( - LDS_[X_OFFSET + di * 32 + ty * 4 + 0], - LDS_[X_OFFSET + di * 32 + ty * 4 + 1], - LDS_[X_OFFSET + di * 32 + ty * 4 + 2], - LDS_[X_OFFSET + di * 32 + ty * 4 + 3]); - float4 srcW = float4( - LDS_[W_OFFSET + di * 32 + 0 * 8 + tx], - LDS_[W_OFFSET + di * 32 + 1 * 8 + tx], - LDS_[W_OFFSET + di * 32 + 2 * 8 + tx], - LDS_[W_OFFSET + di * 32 + 3 * 8 + tx]); - - dstA0 += srcX.x * srcW; - dstA1 += srcX.y * srcW; - dstA2 += srcX.z * srcW; - dstA3 += srcX.w * srcW; - } - - GroupMemoryBarrierWithGroupSync(); - } -#if KERNEL_1x1 -#else - } - } -#endif - -#if CHANNELS_FIRST - if (((y + 0) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation((y + 0) + (x + 0)*h*w + batchWriteOffset, dstA0.x); - if (((y + 0) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation((y + 0) + (x + 1)*h*w + batchWriteOffset, dstA0.y); - if (((y + 0) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation((y + 0) + (x + 2)*h*w + batchWriteOffset, dstA0.z); - if (((y + 0) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation((y + 0) + (x + 3)*h*w + batchWriteOffset, dstA0.w); - - if (((y + 1) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation((y + 1) + (x + 0)*h*w + batchWriteOffset, dstA1.x); - if (((y + 1) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation((y + 1) + (x + 1)*h*w + batchWriteOffset, dstA1.y); - if (((y + 1) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation((y + 1) + (x + 2)*h*w + batchWriteOffset, dstA1.z); - if (((y + 1) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation((y + 1) + (x + 3)*h*w + batchWriteOffset, dstA1.w); - - if (((y + 2) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation((y + 2) + (x + 0)*h*w + batchWriteOffset, dstA2.x); - if (((y + 2) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation((y + 2) + (x + 1)*h*w + batchWriteOffset, dstA2.y); - if (((y + 2) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation((y + 2) + (x + 2)*h*w + batchWriteOffset, dstA2.z); - if (((y + 2) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation((y + 2) + (x + 3)*h*w + batchWriteOffset, dstA2.w); - - if (((y + 3) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation((y + 3) + (x + 0)*h*w + batchWriteOffset, dstA3.x); - if (((y + 3) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation((y + 3) + (x + 1)*h*w + batchWriteOffset, dstA3.y); - if (((y + 3) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation((y + 3) + (x + 2)*h*w + batchWriteOffset, dstA3.z); - if (((y + 3) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation((y + 3) + (x + 3)*h*w + batchWriteOffset, dstA3.w); -#else - if (((y + 0) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 0) + x + 0, dstA0.x); - if (((y + 0) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 0) + x + 1, dstA0.y); - if (((y + 0) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 0) + x + 2, dstA0.z); - if (((y + 0) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 0) + x + 3, dstA0.w); - - if (((y + 1) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 1) + x + 0, dstA1.x); - if (((y + 1) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 1) + x + 1, dstA1.y); - if (((y + 1) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 1) + x + 2, dstA1.z); - if (((y + 1) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 1) + x + 3, dstA1.w); - - if (((y + 2) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 2) + x + 0, dstA2.x); - if (((y + 2) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 2) + x + 1, dstA2.y); - if (((y + 2) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 2) + x + 2, dstA2.z); - if (((y + 2) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 2) + x + 3, dstA2.w); - - if (((y + 3) < w * h) && ((x + 0) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 3) + x + 0, dstA3.x); - if (((y + 3) < w * h) && ((x + 1) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 3) + x + 1, dstA3.y); - if (((y + 3) < w * h) && ((x + 2) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 3) + x + 2, dstA3.z); - if (((y + 3) < w * h) && ((x + 3) < strideO)) - O.FastSetWithActivation(batchWriteOffset + strideO * (y + 3) + x + 3, dstA3.w); -#endif - -#undef X_ -#undef W_ -#undef LDS_ -#undef X_OFFSET -#undef W_OFFSET -} -#undef CACHE_DEPTH -#endif -#endif -#undef KERNEL_NAME diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dMobile.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dMobile.compute.meta deleted file mode 100644 index 722e05f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv2dMobile.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 37f7d6dfde4c7c141ae5b12a1bf7b18d -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2097156 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv3d.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv3d.compute deleted file mode 100644 index e25ffbb..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv3d.compute +++ /dev/null @@ -1,263 +0,0 @@ -#pragma kernel Conv3D_NHWC CHANNELS_FIRST=0 -#pragma kernel Conv3D_NCHW CHANNELS_FIRST=1 -#pragma kernel Conv3DKernelKxK_LaxC8LaxK32_T8x16_R4x4_NHWC CHANNELS_FIRST=0 LAX_KERNEL=1 SUFFIX=KernelKxK_LaxC8LaxK32_T8x16_R -#pragma kernel Conv3DKernelKxK_LaxC8LaxK32_T8x16_R4x4_NCHW CHANNELS_FIRST=1 LAX_KERNEL=1 SUFFIX=KernelKxK_LaxC8LaxK32_T8x16_R -#pragma kernel Conv3DKernelKxK_StrictC8LaxK32_T8x16_R4x4_NHWC CHANNELS_FIRST=0 STRICT_CHANNELS=1 LAX_KERNEL=1 SUFFIX=KernelKxK_StrictC8LaxK32_T8x16_R -#pragma kernel Conv3DKernelKxK_StrictC8LaxK32_T8x16_R4x4_NCHW CHANNELS_FIRST=1 STRICT_CHANNELS=1 LAX_KERNEL=1 SUFFIX=KernelKxK_StrictC8LaxK32_T8x16_R -#pragma kernel Conv3DKernelKxK_StrictC8StrictK32_T8x16_R4x4_NHWC CHANNELS_FIRST=0 STRICT_CHANNELS=1 SUFFIX=KernelKxK_StrictC8StrictK32_T8x16_R -#pragma kernel Conv3DKernelKxK_StrictC8StrictK32_T8x16_R4x4_NCHW CHANNELS_FIRST=1 STRICT_CHANNELS=1 SUFFIX=KernelKxK_StrictC8StrictK32_T8x16_R - -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL(K) -TENSOR_DECL(B) -TENSOR_DECL(WBK) -TENSOR_DECL_RW(O) - -uint4 _Pad; -uint4 _Stride; - -float ffma(float a, float b, float c) { return dot(float2(a,c), float2(b,1)); } - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) KERNEL##SUFFIX##SIZE##x##SIZE##_NCHW - #define CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) KERNEL##SUFFIX##SIZE##x##SIZE##_Cache_##TENSOR##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) KERNEL##SUFFIX##SIZE##x##SIZE##_NHWC - #define CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) KERNEL##SUFFIX##SIZE##x##SIZE##_Cache_##TENSOR##_NHWC -#endif -#define FUNC_NAME(KERNEL, SUFFIX, SIZE) FUNC_NAME_CALL(KERNEL, SUFFIX, SIZE) -#define CACHE_NAME(KERNEL, SUFFIX, SIZE, TENSOR) CACHE_NAME_CALL(KERNEL, SUFFIX, SIZE, TENSOR) - -#define KERNEL_NAME Conv3D - -NUMTHREADS((16,4,4), (8,4,4), (4,4,4)) -void KERNEL_FUNC(Conv3D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(K.kernelCount, O.width, O.height); - TENSOR_SHARED2_ARGS4_8D(X, K, B, WBK, O); - - uint k = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (k >= K.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - uint3 leftCorner = _Pad.xyz; - uint3 rightCorner = uint3(X.width, X.height, X.depth) + _Pad.xyz; - - for (uint n = 0; n < O.batch; ++n) - for (uint d = 0; d < O.depth; ++d) - { - float acc = B.FastGet(k); - for (uint dd = 0; dd < K.GetKernelSpatialDepth(); ++dd) - { - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - { - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint3 pos3d = uint3(x, y, d) * _Stride.xyz + uint3(dx, dy, dd); - - for (uint c = 0; c < X.channels; ++c) - { - float v = 0; - - // WARNING: Mali-G71 performance drops 4x if this branching includes storing accumulator (comment copied from Conv2D kernel) - if (!any(pos3d < leftCorner) && !any(pos3d >= rightCorner)) - v = X.Get5D(n, pos3d.z - leftCorner.z, pos3d.y - leftCorner.y, pos3d.x - leftCorner.x, c); - //acc = fastfma(v, K.Get(dy, dx, c, k), acc); - acc += v * K.GetKernel5D(dd, dy, dx, c, k); - } - } - } - } - - O.Set5DWithActivation(n, d, y, x, k, acc); - } -} - -#define PIXEL_PER_TG 64 //only supported value -#define KERNEL_PER_TG 32 //only supported value -#define BLOCK_SIZE 4 //only supported value -#define CACHE_DEPTH 8 //only support modulo of 4 values. - -//Each thread handle = 4 kernels * 4 pixels (in registers) and all channels -//A threadgroup (8,16,1) handle = 32 kernels x 64 pixels and all channels (looping on CACHE_DEPTH channel at a time) -groupshared float CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS) [(32+64) * CACHE_DEPTH]; //(32+64)*CACHE_DEPTH == 96*CACHE_DEPTH floats (CACHE_DEPTH == 8 --> 768 floats) - -[numthreads(8,16,1)] -void FUNC_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE)(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex) -{ - //This kernel assume the following: - //Input: - // C % CACHE_DEPTH==0 <-- only if STRICT_CHANNELS==1 - //Kernel: - // K%32==0 <-- only if LAX_KERNEL=0 - //DISPATCH ARGS(K.kernelCount, O.width * O.height * O.depth, O.batch); - TENSOR_SHARED2_ARGS4_8D(X, K, B, WBK, O); - - #define LDS_ CACHE_NAME(KERNEL_NAME, SUFFIX, BLOCK_SIZE, LDS) - #define X_OFFSET 0 - #define W_OFFSET CACHE_DEPTH*PIXEL_PER_TG - - //Per thread group (scalar registers) - uint tg_NumChannels = X.channels; - uint tg_DepthX = X.depth; - uint tg_WidthX = X.width; - uint tg_HeightX = X.height; - uint tg_DepthO = O.depth; - uint tg_WidthO = O.width; - uint tg_HeightO = O.height; - - uint tg_NumKernels = K.channels; - uint tg_NumInputPixels = tg_DepthX*tg_WidthX*tg_HeightX; - uint tg_NumOuputPixels = tg_DepthO*tg_WidthO*tg_HeightO; - - uint tg_KernelSpatialStride = tg_NumKernels*tg_NumChannels; - uint tg_KernelBaseId = groupID.x * KERNEL_PER_TG; - uint tg_OutputPixelBaseId = groupID.y * PIXEL_PER_TG; - uint tg_BatchReadOffset = groupID.z * tg_NumChannels * tg_NumInputPixels; - uint tg_BatchWriteOffset = groupID.z * tg_NumKernels * tg_NumOuputPixels; - uint tg_kernelSpatialOffset = 0; - - //4x4 block, 4 kernels by 4 pixels - float dstA[BLOCK_SIZE*BLOCK_SIZE]; - - //Load Bias [K] into dstA [Kernels, Pixels] - uint tg_kId; - uint tg_pId; - uint maxBiasIndex = O.channels - 1; - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - [unroll] for (tg_kId = 0; tg_kId < BLOCK_SIZE; ++tg_kId) - dstA[tg_pId*BLOCK_SIZE+tg_kId] = B.FastGet(min(maxBiasIndex,tg_KernelBaseId + groupThreadID.x * BLOCK_SIZE + tg_kId)); - - //Looping over kernel spatially - for (uint tg_Dd = 0; tg_Dd < K.GetKernelSpatialDepth(); ++tg_Dd) - for (uint tg_Dy = 0; tg_Dy < K.GetKernelHeight(); ++tg_Dy) - for (uint tg_Dx = 0; tg_Dx < K.GetKernelWidth(); ++tg_Dx) - { - //Looping over channels, convolving CACHE_DEPTH of them at a time. - for (uint tg_ChannelOffset = 0; tg_ChannelOffset < tg_NumChannels; tg_ChannelOffset += CACHE_DEPTH) - { - //Load from DDR to LDS: Threadgroup need 32 weight + 64 pixels per CACHE_DEPTH = 96 float, but we have 128 threads. - //--> Load 4 channels at a time (3 loads per threads, 1 kernel and 2 pixels) consequence is CHANNEL_DEPTH must be a modulo of 4. - //A threadgroup (128 Threads) contains 4 half-warps of 32 threads. - // half-warps 0 - threadId [00-31] --> load Kernels [00-31] channel 0 + Pixels [00,31] channel 0 and 2 - // half-warps 1 - threadId [32-63] --> load Kernels [00-31] channel 1 + Pixels [32,64] channel 1 and 3 - // half-warps 2 - threadId [65-95] --> load Kernels [00-31] channel 2 + Pixels [00,31] channel 0 and 2 - // half-warps 3 - threadId [96-127] --> load Kernels [00-31] channel 3 + Pixels [32,64] channel 1 and 3 - uint warpThreadId = threadIndex % 64; - uint warpId = threadIndex / 64; - uint halfWarpThreadId = threadIndex % 32; - uint halfWarpId = threadIndex / 32; - [unroll] for (uint tg_CacheLoadIdx = 0; tg_CacheLoadIdx < CACHE_DEPTH; tg_CacheLoadIdx+=4)//TODO verify unrolling actually happens - { - //Kernels (1 per thread) - //K stored as DHWCK, threadgroup is loading 4*32 kernels at a time to LDS. - //DHW from tg_kernelSpatialOffset, - //C from tg_ChannelOffset+tg_CacheLoadIdx+halfWarpId([0,3]) - //K from tg_KernelBaseId+halfWarpThreadId([0,31]) - uint kernelReadOffset = tg_kernelSpatialOffset + tg_NumKernels*(tg_ChannelOffset+tg_CacheLoadIdx+halfWarpId) + tg_KernelBaseId + halfWarpThreadId; - #if !STRICT_CHANNELS || LAX_KERNEL - kernelReadOffset = min(kernelReadOffset, K.GetLength5D()-1); - #endif - LDS_[W_OFFSET+tg_CacheLoadIdx*KERNEL_PER_TG+threadIndex] = K.FastGet(kernelReadOffset); - - //Pixels (two of them per thread) - //threadgroup is loading 4*64 kernels at a time to LDS. - int outputPixelBaseId = tg_OutputPixelBaseId + warpThreadId; - int3 outputPixelCoords; - outputPixelCoords.x = outputPixelBaseId % tg_WidthO;//width - outputPixelCoords.y = (outputPixelBaseId / tg_WidthO) % tg_HeightO;//height - outputPixelCoords.z = outputPixelBaseId / (tg_WidthO * tg_HeightO);//depth - int3 inputPixelCoords = outputPixelCoords * _Stride.xyz - _Pad.xyz + int3(tg_Dx, tg_Dy, tg_Dd); - bool inputPixelMask = all( (inputPixelCoords >= 0) && (inputPixelCoords < float3(tg_WidthX, tg_HeightX, tg_DepthX)) ); - int inputPixelId = inputPixelCoords.z * (tg_WidthX*tg_HeightX) + inputPixelCoords.y * tg_WidthX + inputPixelCoords.x; - uint inputChannelId1 = tg_ChannelOffset + tg_CacheLoadIdx + warpId; - uint inputChannelId2 = inputChannelId1 + 2; - bool inputChannelMask1 = inputChannelId1 < tg_NumChannels; - bool inputChannelMask2 = inputChannelId2 < tg_NumChannels; - #if STRICT_CHANNELS - inputChannelMask1 = true; - inputChannelMask2 = true; - #endif - #if CHANNELS_FIRST - uint pixelReadOffset1 = tg_NumInputPixels * inputChannelId1 + inputPixelId + tg_BatchReadOffset; - uint pixelReadOffset2 = tg_NumInputPixels * inputChannelId2 + inputPixelId + tg_BatchReadOffset; - #else - uint pixelReadOffset1 = tg_NumChannels * inputPixelId + inputChannelId1 + tg_BatchReadOffset; - uint pixelReadOffset2 = tg_NumChannels * inputPixelId + inputChannelId2 + tg_BatchReadOffset; - #endif - LDS_[X_OFFSET+tg_CacheLoadIdx*PIXEL_PER_TG+threadIndex] = X.MaskedGet(inputPixelMask && inputChannelMask1, pixelReadOffset1); - LDS_[X_OFFSET+tg_CacheLoadIdx*PIXEL_PER_TG+128+threadIndex] = X.MaskedGet(inputPixelMask && inputChannelMask2, pixelReadOffset2); - } - - GroupMemoryBarrierWithGroupSync(); - - //Inner loop - //TODO get rid of bank conflicts. - uint ptrX = groupThreadID.y*BLOCK_SIZE + X_OFFSET; - uint ptrW = groupThreadID.x*BLOCK_SIZE + W_OFFSET; - for (uint tg_CacheExecuteIdx = 0; tg_CacheExecuteIdx < CACHE_DEPTH; ++tg_CacheExecuteIdx) - { - //Load LDS -> registers - float colOfX[BLOCK_SIZE]; - float rowOfW[BLOCK_SIZE]; - uint tg_q; - [unroll] for (tg_q = 0; tg_q < BLOCK_SIZE; ++tg_q) - colOfX[tg_q] = LDS_[ptrX + tg_q]; - [unroll] for (tg_q = 0; tg_q < BLOCK_SIZE; ++tg_q) - rowOfW[tg_q] = LDS_[ptrW + tg_q]; - - ptrX += PIXEL_PER_TG; - ptrW += KERNEL_PER_TG; - - //Mads 4 pixels by 4 kernels matmul style --> 16 mads - [unroll] for (uint tg_X = 0; tg_X < BLOCK_SIZE; ++tg_X) - [unroll] for (uint tg_W = 0; tg_W < BLOCK_SIZE; ++tg_W) - dstA[tg_X*BLOCK_SIZE+tg_W] = ffma(colOfX[tg_X], rowOfW[tg_W], dstA[tg_X*BLOCK_SIZE+tg_W]); - } - - GroupMemoryBarrierWithGroupSync(); - } - - tg_kernelSpatialOffset += tg_KernelSpatialStride; - } - - //------------------------------- - //store registers to DDR - //------------------------------- - //B does not require an offset as size == 1 - //C from tg_KernelBaseId, groupThreadID.x and tg_kId - //HW from tg_OutputPixelBaseId, groupThreadID.y and tg_pId - [unroll] for (tg_kId = 0; tg_kId < BLOCK_SIZE; ++tg_kId) - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - { - uint writeChannelId = tg_KernelBaseId + groupThreadID.x * BLOCK_SIZE + tg_kId; - uint writePixelId = tg_OutputPixelBaseId + groupThreadID.y * BLOCK_SIZE + tg_pId; - float writeValue = dstA[tg_pId*BLOCK_SIZE+tg_kId]; - #if CHANNELS_FIRST - uint writeIndex = O.depth * O.width * O.height * writeChannelId + writePixelId + tg_BatchWriteOffset; - #else - uint writeIndex = tg_NumKernels * writePixelId + writeChannelId + tg_BatchWriteOffset; - #endif - #if LAX_KERNEL - bool canWriteChannel = (writeChannelId < tg_NumKernels); - #else - bool canWriteChannel = true; - #endif - if ((writePixelId < tg_NumOuputPixels) && canWriteChannel) - O.FastSetWithActivation(writeIndex, writeValue); - } - - #undef X_OFFSET - #undef W_OFFSET - #undef LDS_ -} -#undef CACHE_DEPTH -#undef BLOCK_SIZE -#undef KERNEL_PER_TG -#undef PIXEL_PER_TG diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv3d.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv3d.compute.meta deleted file mode 100644 index 831592d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Conv3d.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5da0dcf3215520c41bdb8342e88aa56e -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 4 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DebugUtils.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DebugUtils.cginc deleted file mode 100644 index ef2c7bc..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DebugUtils.cginc +++ /dev/null @@ -1,99 +0,0 @@ -/// DEBUG ONLY: -/// `KERNEL_ASSERTS` allow to track out of bound read/write and assertion -/// in all kernels with the exception of those where FORCE_NO_DEBUG is defined. -/// to debug only a few kernel one can also define FORCE_NO_DEBUG per kernel rather. -/// To debug kernel be sure to set ComputeDebugUtils.debugKernels to true BarracudaComputeDebugUtils.cs also. -/// Production code should not define this as this will significantly degrade performances. -/// Defining those require Shader model 5.0 and not Metal (Metal does not support GetDimensions on buffer) -/// aka `#pragma target 5.0` see https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html. -#include "KernelDebug.cginc" -#if !defined(KERNEL_ASSERTS) - // KernelDebug.cginc allow to enable kernel debugging on yamato. Uncomment the line below to force it at dev time. - // #define KERNEL_ASSERTS -#endif - -//Keep in sync with BarracudaComputeDebugUtils.cs enum ComputeDebugUtils.KernelAssertContext -#define KERNEL_ASSERT_CONTEXT_READONLY_READ 0 -#define KERNEL_ASSERT_CONTEXT_READWRITE_READ 1 -#define KERNEL_ASSERT_CONTEXT_READWRITE_WRITE 2 -#define KERNEL_ASSERT_CONTEXT_SHARED_READ 3 -#define KERNEL_ASSERT_CONTEXT_ASSERTION 4 -#define KERNEL_ASSERT_CONTEXT_ASSERTION_WITH_VALUE 5 - -//Keep in sync with BarracudaComputeDebugUtils.cs enum ComputeDebugUtils.KernelAssertInfo -struct KernelAssertInfo -{ - uint lockValue; - //context - uint lineNumber; - uint context; - //specific to read/write OOB detection - uint index; - uint bufferSize; - //specific to assertion with value - uint debugValue; - //padding - uint padding0; - uint padding1; -}; - -#if (defined(KERNEL_ASSERTS) && !defined(FORCE_NO_DEBUG)) || defined(FORCE_DEBUG) - - RWStructuredBuffer KernelAssertInfoBuffer; - void LogAssertion(uint index, uint bufferSize, uint debugValue, uint lineNumber, uint context) - { - uint anAssertionIsAlreadyLogged; - InterlockedAdd(KernelAssertInfoBuffer[0].lockValue, 1, anAssertionIsAlreadyLogged); - if (!anAssertionIsAlreadyLogged) - { - KernelAssertInfoBuffer[0].lineNumber = lineNumber; - KernelAssertInfoBuffer[0].context = context; - KernelAssertInfoBuffer[0].index = index; - KernelAssertInfoBuffer[0].bufferSize = bufferSize; - KernelAssertInfoBuffer[0].debugValue = debugValue; - } - } - - uint GetSafeTensorIndex(uint index, uint bufferSize, uint lineNumber, uint context) - { - bool isIndexValid = (index >= 0 && index < bufferSize); - if (isIndexValid) - return index; - - LogAssertion(index, bufferSize, 0, lineNumber, context); - - //Always return a valid index to avoid GPU crashs so CPU get a chance to catch the error. - return 0; - } - - void KernelAssert(bool isOk, uint lineNumber) - { - if (isOk) - return; - - LogAssertion(0, 0, 0, lineNumber, KERNEL_ASSERT_CONTEXT_ASSERTION); - } - - void KernelAssertWithDebugValue(bool isOk, uint lineNumber, uint value) - { - if (isOk) - return; - - LogAssertion(0, 0, value, lineNumber, KERNEL_ASSERT_CONTEXT_ASSERTION_WITH_VALUE); - } - - #define ASSERT_TENSOR_INDEX(index, context) \ - uint dataNumStructs, dataStride; \ - data.GetDimensions(dataNumStructs, dataStride); \ - uint safeIndex = GetSafeTensorIndex(index, dataNumStructs, __LINE__, context); - #define TENSOR_READ(varName, index, context) ASSERT_TENSOR_INDEX(index, context); varName = data[safeIndex] - #define TENSOR_WRITE(varName, index, context) ASSERT_TENSOR_INDEX(index, context); data[safeIndex] = varName - - #define KERNEL_ASSERT(condition) KernelAssert(condition, __LINE__) - #define KERNEL_ASSERT_WITH_VALUE(condition, value) KernelAssertWithDebugValue(condition, __LINE__, value) -#else - #define TENSOR_READ(varName, index, context) varName = data[index] - #define TENSOR_WRITE(varName, index, context) data[index] = varName - #define KERNEL_ASSERT(condition) - #define KERNEL_ASSERT_WITH_VALUE(condition, value) -#endif diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DebugUtils.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DebugUtils.cginc.meta deleted file mode 100644 index aeafa08..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DebugUtils.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: a236e93868e2f6349b7a40e7552915fd -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense.compute deleted file mode 100644 index a3b2275..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense.compute +++ /dev/null @@ -1,1886 +0,0 @@ -//Important note: For Dense layers NCHW and NHWC as input and output are flattened tensors. -#pragma kernel Dense_L1Cached64 -#pragma kernel DenseTiled16x16 -#pragma kernel DenseTiled32x32 -#pragma kernel DenseTiled64x64 - -//#pragma kernel Dense_T8x8_R8x8_NHWC DENSE=1 BLOCK_SIZE=8 -#pragma kernel Dense_T8x8_R4x4 DENSE=1 BLOCK_SIZE=4 -#pragma kernel Dense_T16x16_R4x4 DENSE=1 BLOCK_SIZE=4 - -#pragma kernel Dense_Tilled2x2_Cached -//Shader compiler goes OOM when compiling this shader in KERNEL_ASSERTS mode on DX11, thus the FORCE_NO_DEBUG. -#pragma kernel Dense_Tilled4x4_Cached FORCE_NO_DEBUG=1 - -#pragma kernel MatMulPackB0Bias - -#pragma kernel Dense_V_L1Cached64 - - -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL(W) -TENSOR_DECL(B) -TENSOR_DECL(WBK) -TENSOR_DECL_RW(O) -float ffma(float a, float b, float c) { return dot(float2(a, c), float2(b, 1)); } //return a*b+c;} //fastfma(a,b,c); } - -#if DENSE -#define FUNC_NAME_CALL(KERNEL, SIZE) KERNEL##SIZE##x##SIZE -#define FUNC_NAME(KERNEL, SIZE) FUNC_NAME_CALL(KERNEL, SIZE) -#define CACHE_NAME_CALL(KERNEL, SIZE, TENSOR) KERNEL##SIZE##x##SIZE##_Cache_##TENSOR -#define CACHE_NAME(KERNEL, SIZE, TENSOR) CACHE_NAME_CALL(KERNEL, SIZE, TENSOR) - -//CACHE_DEPTH -// T >>X -//16: 178ms 272ms 181ms -// 8: 173ms 395ms 205ms -// 4: 176ms 630ms 260ms -// 2: 205ms 495ms 420ms -// 1: 209ms 980ms -- - - -//@HARDCODED_DIMS + BUF_OFFSET + lds read index alu opt -//CACHE_DEPTH -// T >>X -//16: 169ms 241ms 173ms -// 8: 169ms 356ms 178ms -// 4: 170ms 612ms 209ms -// 2: 178ms 900ms 380ms -// 1: 250ms 875ms -- - -//@BLOCKED_W + HARDCODED_DIMS + BUF_OFFSET + lds read index alu opt -//!INCLUDING ValidateData by mistake! -//CACHE_DEPTH -// T >>X -//16: 144ms 241ms 155ms -// 8: 158ms 357ms 164ms -// 4: 151ms 630ms 202ms -// 2: 180ms 815ms 350ms -// 1: 258ms 883ms -- -// @TODO: try 32 - - -//============================================ -//@BLOCKED_W + BUF_OFFSET + lds read index alu opt -//CACHE_DEPTH -// T T >>X -// hard_dims -//32: 167ms -//16: 122ms 141ms 140ms -// 8: 136ms 147ms 154ms -// 4: 130ms 141ms 189ms -// 2: 159ms ***ms ***ms -// 1: 220ms ***ms ***ms -// -//Vega -//32: 172ms -//16: 154ms -// 8: 156ms -// 4: 161ms -// 2: 162ms -// 1: 245ms -//iOS(8layers) -//32: 28ms - - -//@BLOCKED_W + lds read index alu opt -//16: 134ms 142ms 146ms - - -//@BLOCKED_W + BUF_OFFSET + optimized read indices -//CACHE_DEPTH -//16: 123ms 131ms 135ms - - -#define KERNEL_NAME Dense_T16x16_R -#if BLOCK_SIZE == 4 -#define TRANSPOSED_X 0 -#define SHIFTED_X 1 -#define BLOCKED_W 1 -#define HARDCODED_DIMS 0 -#define BUF_OFFSET 0 -#define DOUBLE_BUFFER_LDS_READS 0 -#define CACHE_DEPTH 16 -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, X)[CACHE_DEPTH*16*BLOCK_SIZE+SHIFTED_X*CACHE_DEPTH]; -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, W)[CACHE_DEPTH*16*BLOCK_SIZE]; -[numthreads(16,16,1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - int x = (int)dispatchThreadID.x * BLOCK_SIZE; - int y = (int)dispatchThreadID.y * BLOCK_SIZE; - int tx = (int)groupThreadID.x; - int ty = (int)groupThreadID.y; - int bx = ((int)dispatchThreadID.x - (int)groupThreadID.x) * BLOCK_SIZE; - int by = ((int)dispatchThreadID.y - (int)groupThreadID.y) * BLOCK_SIZE; - int ti = (int)threadIndex; - int n = (int)X.GetFlatWidth(); - int strideX = (int)X.GetFlatWidth(); - int strideW = (int)W.GetFlatWidth(); - int strideO = (int)O.GetFlatWidth(); - int offsetX = BUF_OFFSET; - int offsetW = BUF_OFFSET; - int offsetO = BUF_OFFSET; -#if HARDCODED_DIMS == 1 - n = 1024; - strideX = 1024; - strideW = 1024; - strideO = 1024; -#endif - - #define X_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, X) - #define W_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, W) - - //if (x >= (int)O.GetFlatWidth()) return; - //if (y >= (int)O.GetFlatHeight()) return; - - float4 dstA_0, dstA_1, dstA_2, dstA_3; - - dstA_0.x = B.FastGet(x+0); - dstA_1.x = B.FastGet(x+0); - dstA_2.x = B.FastGet(x+0); - dstA_3.x = B.FastGet(x+0); - dstA_0.y = B.FastGet(x+1); - dstA_1.y = B.FastGet(x+1); - dstA_2.y = B.FastGet(x+1); - dstA_3.y = B.FastGet(x+1); - dstA_0.z = B.FastGet(x+2); - dstA_1.z = B.FastGet(x+2); - dstA_2.z = B.FastGet(x+2); - dstA_3.z = B.FastGet(x+2); - dstA_0.w = B.FastGet(x+3); - dstA_1.w = B.FastGet(x+3); - dstA_2.w = B.FastGet(x+3); - dstA_3.w = B.FastGet(x+3); - - int j; - int readW = strideW * (ti>>6) + bx + (ti&63) + offsetW; - #if TRANSPOSED_X == 1 - int readX = strideX * (ti>>6) + by + (ti&63) + offsetX; - #elif SHIFTED_X == 1 - int4 readX = int4( - strideX * (by + (ti>>4) + 0) + (ti&15) + offsetX, - strideX * (by + (ti>>4) +16) + (ti&15) + offsetX, - strideX * (by + (ti>>4) +32) + (ti&15) + offsetX, - strideX * (by + (ti>>4) +48) + (ti&15) + offsetX); - #endif - - for (int i = 0; i < n; i += CACHE_DEPTH) - { - - #if CACHE_DEPTH == 32 - #if BLOCKED_W == 1 - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2) ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+256] = W.data[strideW * (i + (ti>>6) + 4) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+512] = W.data[strideW * (i + (ti>>6) + 8) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+768] = W.data[strideW * (i + (ti>>6) +12) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+1024]= W.data[strideW * (i + (ti>>6) +16) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+1280]= W.data[strideW * (i + (ti>>6) +20) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+1536]= W.data[strideW * (i + (ti>>6) +24) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+1792]= W.data[strideW * (i + (ti>>6) +28) + bx + (ti&63) + offsetW]; - #else - #endif - - #if TRANSPOSED_X == 1 - X_[ti ] = X.data[strideX * (i + (ti>>6) + 0) + by + (ti&63) + offsetX]; - X_[ti+256] = X.data[strideX * (i + (ti>>6) + 4) + by + (ti&63) + offsetX]; - X_[ti+512] = X.data[strideX * (i + (ti>>6) + 8) + by + (ti&63) + offsetX]; - X_[ti+768] = X.data[strideX * (i + (ti>>6) +12) + by + (ti&63) + offsetX]; - X_[ti+1024]= X.data[strideX * (i + (ti>>6) +16) + by + (ti&63) + offsetX]; - X_[ti+1280]= X.data[strideX * (i + (ti>>6) +20) + by + (ti&63) + offsetX]; - X_[ti+1536]= X.data[strideX * (i + (ti>>6) +24) + by + (ti&63) + offsetX]; - X_[ti+1792]= X.data[strideX * (i + (ti>>6) +28) + by + (ti&63) + offsetX]; - #elif SHIFTED_X == 1 - // 16x64 => 64x16 - X_[(ti>>5) + 65*(ti&31) + 0] = X.data[strideX * (by + (ti>>5) + 0) + i + (ti&31) + offsetX]; - X_[(ti>>5) + 65*(ti&31) + 8] = X.data[strideX * (by + (ti>>5) + 8) + i + (ti&31) + offsetX]; - X_[(ti>>5) + 65*(ti&31) +16] = X.data[strideX * (by + (ti>>5) +16) + i + (ti&31) + offsetX]; - X_[(ti>>5) + 65*(ti&31) +24] = X.data[strideX * (by + (ti>>5) +24) + i + (ti&31) + offsetX]; - X_[(ti>>5) + 65*(ti&31) +32] = X.data[strideX * (by + (ti>>5) +32) + i + (ti&31) + offsetX]; - X_[(ti>>5) + 65*(ti&31) +40] = X.data[strideX * (by + (ti>>5) +40) + i + (ti&31) + offsetX]; - X_[(ti>>5) + 65*(ti&31) +48] = X.data[strideX * (by + (ti>>5) +48) + i + (ti&31) + offsetX]; - X_[(ti>>5) + 65*(ti&31) +56] = X.data[strideX * (by + (ti>>5) +56) + i + (ti&31) + offsetX]; - #else - // 16x64 => 64x16 - #endif - - - #elif CACHE_DEPTH == 16 - #if BLOCKED_W == 1 - #if HARDCODED_DIMS - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2) ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+256] = W.data[strideW * (i + (ti>>6) + 4) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+512] = W.data[strideW * (i + (ti>>6) + 8) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+768] = W.data[strideW * (i + (ti>>6) +12) + bx + (ti&63) + offsetW]; - #else - [unroll] for (j = 0; j < 4; ++j, readW += strideW * 4) - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2) + 256*j] = W.data[readW]; - #endif - #else - W_[ti ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - W_[ti+256] = W.data[strideW * (i + (ti>>6) + 4) + bx + (ti&63) + offsetW]; - W_[ti+512] = W.data[strideW * (i + (ti>>6) + 8) + bx + (ti&63) + offsetW]; - W_[ti+768] = W.data[strideW * (i + (ti>>6) +12) + bx + (ti&63) + offsetW]; - #endif - - #if TRANSPOSED_X == 1 - #if HARDCODED_DIMS - X_[ti ] = X.data[strideX * (i + (ti>>6) + 0) + by + (ti&63) + offsetX]; - X_[ti+256] = X.data[strideX * (i + (ti>>6) + 4) + by + (ti&63) + offsetX]; - X_[ti+512] = X.data[strideX * (i + (ti>>6) + 8) + by + (ti&63) + offsetX]; - X_[ti+768] = X.data[strideX * (i + (ti>>6) +12) + by + (ti&63) + offsetX]; - #else - [unroll] for (j = 0; j < 4; ++j, readX += strideX * 4) - X_[ti + 256*j] = X.data[readX]; - #endif - - #elif SHIFTED_X == 1 - // 16x64 => 64x16 - #if HARDCODED_DIMS - X_[(ti>>4) + 65*(ti&15) + 0] = X.data[strideX * (by + (ti>>4) + 0) + i + (ti&15) + offsetX]; - X_[(ti>>4) + 65*(ti&15) +16] = X.data[strideX * (by + (ti>>4) +16) + i + (ti&15) + offsetX]; - X_[(ti>>4) + 65*(ti&15) +32] = X.data[strideX * (by + (ti>>4) +32) + i + (ti&15) + offsetX]; - X_[(ti>>4) + 65*(ti&15) +48] = X.data[strideX * (by + (ti>>4) +48) + i + (ti&15) + offsetX]; - #else - [unroll] for (j = 0; j < 4; ++j) - X_[(ti>>4) + 65*(ti&15) + 16*j] = X.data[readX[j]]; - readX += CACHE_DEPTH; - #endif - #else - // 16x64 => 64x16 - X_[ti ] = X.data[strideX * (by + (ti&63)) + i + (ti>>6) + 0 + offsetX]; - X_[ti+256] = X.data[strideX * (by + (ti&63)) + i + (ti>>6) + 4 + offsetX]; - X_[ti+512] = X.data[strideX * (by + (ti&63)) + i + (ti>>6) + 8 + offsetX]; - X_[ti+768] = X.data[strideX * (by + (ti&63)) + i + (ti>>6) +12 + offsetX]; - #endif - - #elif CACHE_DEPTH == 8 - #if BLOCKED_W == 1 - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2) ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2)+256] = W.data[strideW * (i + (ti>>6) + 4) + bx + (ti&63) + offsetW]; - #else - W_[ti ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - W_[ti+256] = W.data[strideW * (i + (ti>>6) + 4) + bx + (ti&63) + offsetW]; - #endif - - #if TRANSPOSED_X == 1 - X_[ti ] = X.data[strideX * (i + (ti>>6) + 0) + by + (ti&63) + offsetX]; - X_[ti+256] = X.data[strideX * (i + (ti>>6) + 4) + by + (ti&63) + offsetX]; - #elif SHIFTED_X == 1 - // 8x64 => 64x8 - X_[(ti>>3) + 65*(ti&7) + 0] = X.data[strideX * (by + (ti>>3) + 0) + i + (ti&7) + offsetX]; - X_[(ti>>3) + 65*(ti&7) +32] = X.data[strideX * (by + (ti>>3) +32) + i + (ti&7) + offsetX]; - #else - // 8x64 => 64x8 - X_[ti ] = X.data[strideX * (by + (ti&63)) + i + (ti>>6) + 0 + offsetX]; - X_[ti+256] = X.data[strideX * (by + (ti&63)) + i + (ti>>6) + 4 + offsetX]; - #endif - - #elif CACHE_DEPTH == 4 - #if BLOCKED_W == 1 - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2) ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - #else - W_[ti ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - #endif - #if TRANSPOSED_X == 1 - X_[ti ] = X.data[strideX * (i + (ti>>6) + 0) + by + (ti&63) + offsetX]; - #elif SHIFTED_X == 1 - // 4x64 => 64x4 - X_[(ti>>2) + 65*(ti&3) + 0] = X.data[strideX * (by + (ti>>2) + 0) + i + (ti&3) + offsetX]; - #else - // 4x64 => 64x4 - X_[ti ] = X.data[strideX * (by + (ti&63)) + i + (ti>>6) + 0 + offsetX]; - #endif - - #elif CACHE_DEPTH == 2 - if (ti < 128) - { - #if BLOCKED_W == 1 - W_[((ti>>6)<<6) + ((ti&3)<<4) + ((ti&63)>>2) ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - #else - W_[ti ] = W.data[strideW * (i + (ti>>6) + 0) + bx + (ti&63) + offsetW]; - #endif - #if TRANSPOSED_X == 1 - X_[ti ] = X.data[strideX * (i + (ti>>6) + 0) + by + (ti&63) + offsetX]; - #elif SHIFTED_X == 1 - X_[(ti>>1) + 65*(ti&1) + 0] = X.data[strideX * (by + (ti>>1) + 0) + i + (ti&1) + offsetX]; - #else - X_[ti ] = X.data[strideX * (by + (ti&63)) + i + (ti>>6) + 0 + offsetX]; - #endif - } - - #elif CACHE_DEPTH == 1 - if (ti < 64) - { - #if BLOCKED_W == 1 - W_[((ti&3)<<4) + ((ti&63)>>2) ] = W.data[strideW * i + bx + ti + offsetW]; - #else - W_[ti] = W.data[strideW * i + bx + ti + offsetW]; - #endif - #if TRANSPOSED_X == 1 - X_[ti] = X.data[strideX * i + by + ti + offsetX]; - #else - //X_[ti] = X.Get(by+ti, i); - X_[ti] = X.data[strideX * (by + ti) + i + offsetX]; - #endif - } - #endif - - GroupMemoryBarrierWithGroupSync(); - - int4 idX = int4(0,1,2,3); - int4 idW = int4(0,1,2,3); - #if BLOCKED_W == 1 - idW = int4(0,16,32,48); - #endif - int incX = 64 + (SHIFTED_X & ~TRANSPOSED_X); - int incW = 64; -#if 0 //DOUBLE_BUFFER_LDS_READS == 1 - float4 srcW_ = float4( - #if BLOCKED_W == 1 - W_[idW.x + tx], - W_[idW.y + tx], - W_[idW.z + tx], - W_[idW.w + tx] - #else - W_[idW.x + tx*4], - W_[idW.y + tx*4], - W_[idW.z + tx*4], - W_[idW.w + tx*4] - #endif - ); - idW += incW; - - //int lastX = idX.x + (CACHE_DEPTH - 2) * incX.x; - //while (idX.x < lastX.x) - for (int di = 0; di < CACHE_DEPTH - 2; di+=2) - { - float4 srcX, srcW; - srcX = float4( - X_[idX.x + ty*4], - X_[idX.y + ty*4], - X_[idX.z + ty*4], - X_[idX.w + ty*4]); - srcW = float4( - #if BLOCKED_W == 1 - W_[idW.x + tx], - W_[idW.y + tx], - W_[idW.z + tx], - W_[idW.w + tx] - #else - W_[idW.x + tx*4], - W_[idW.y + tx*4], - W_[idW.z + tx*4], - W_[idW.w + tx*4] - #endif - ); - idX += incX; - idW += incW; - - dstA_0.x = ffma(srcX.x, srcW_.x, dstA_0.x); - dstA_0.y = ffma(srcX.x, srcW_.y, dstA_0.y); - dstA_0.z = ffma(srcX.x, srcW_.z, dstA_0.z); - dstA_0.w = ffma(srcX.x, srcW_.w, dstA_0.w); - - dstA_1.x = ffma(srcX.y, srcW_.x, dstA_1.x); - dstA_1.y = ffma(srcX.y, srcW_.y, dstA_1.y); - dstA_1.z = ffma(srcX.y, srcW_.z, dstA_1.z); - dstA_1.w = ffma(srcX.y, srcW_.w, dstA_1.w); - - dstA_2.x = ffma(srcX.z, srcW_.x, dstA_2.x); - dstA_2.y = ffma(srcX.z, srcW_.y, dstA_2.y); - dstA_2.z = ffma(srcX.z, srcW_.z, dstA_2.z); - dstA_2.w = ffma(srcX.z, srcW_.w, dstA_2.w); - - dstA_3.x = ffma(srcX.w, srcW_.x, dstA_3.x); - dstA_3.y = ffma(srcX.w, srcW_.y, dstA_3.y); - dstA_3.z = ffma(srcX.w, srcW_.z, dstA_3.z); - dstA_3.w = ffma(srcX.w, srcW_.w, dstA_3.w); - - srcX = float4( - X_[idX.x + ty*4], - X_[idX.y + ty*4], - X_[idX.z + ty*4], - X_[idX.w + ty*4]); - srcW_ = float4( - #if BLOCKED_W == 1 - W_[idW.x + tx], - W_[idW.y + tx], - W_[idW.z + tx], - W_[idW.w + tx] - #else - W_[idW.x + tx*4], - W_[idW.y + tx*4], - W_[idW.z + tx*4], - W_[idW.w + tx*4] - #endif - ); - idX += incX; - idW += incW; - - dstA_0.x = ffma(srcX.x, srcW.x, dstA_0.x); - dstA_0.y = ffma(srcX.x, srcW.y, dstA_0.y); - dstA_0.z = ffma(srcX.x, srcW.z, dstA_0.z); - dstA_0.w = ffma(srcX.x, srcW.w, dstA_0.w); - - dstA_1.x = ffma(srcX.y, srcW.x, dstA_1.x); - dstA_1.y = ffma(srcX.y, srcW.y, dstA_1.y); - dstA_1.z = ffma(srcX.y, srcW.z, dstA_1.z); - dstA_1.w = ffma(srcX.y, srcW.w, dstA_1.w); - - dstA_2.x = ffma(srcX.z, srcW.x, dstA_2.x); - dstA_2.y = ffma(srcX.z, srcW.y, dstA_2.y); - dstA_2.z = ffma(srcX.z, srcW.z, dstA_2.z); - dstA_2.w = ffma(srcX.z, srcW.w, dstA_2.w); - - dstA_3.x = ffma(srcX.w, srcW.x, dstA_3.x); - dstA_3.y = ffma(srcX.w, srcW.y, dstA_3.y); - dstA_3.z = ffma(srcX.w, srcW.z, dstA_3.z); - dstA_3.w = ffma(srcX.w, srcW.w, dstA_3.w); - } - - float4 srcX = float4( - X_[idX.x + ty*4], - X_[idX.y + ty*4], - X_[idX.z + ty*4], - X_[idX.w + ty*4]); - float4 srcW = float4( - #if BLOCKED_W == 1 - W_[idW.x + tx], - W_[idW.y + tx], - W_[idW.z + tx], - W_[idW.w + tx] - #else - W_[idW.x + tx*4], - W_[idW.y + tx*4], - W_[idW.z + tx*4], - W_[idW.w + tx*4] - #endif - ); - - dstA_0.x = ffma(srcX.x, srcW_.x, dstA_0.x); - dstA_0.y = ffma(srcX.x, srcW_.y, dstA_0.y); - dstA_0.z = ffma(srcX.x, srcW_.z, dstA_0.z); - dstA_0.w = ffma(srcX.x, srcW_.w, dstA_0.w); - - dstA_1.x = ffma(srcX.y, srcW_.x, dstA_1.x); - dstA_1.y = ffma(srcX.y, srcW_.y, dstA_1.y); - dstA_1.z = ffma(srcX.y, srcW_.z, dstA_1.z); - dstA_1.w = ffma(srcX.y, srcW_.w, dstA_1.w); - - dstA_2.x = ffma(srcX.z, srcW_.x, dstA_2.x); - dstA_2.y = ffma(srcX.z, srcW_.y, dstA_2.y); - dstA_2.z = ffma(srcX.z, srcW_.z, dstA_2.z); - dstA_2.w = ffma(srcX.z, srcW_.w, dstA_2.w); - - dstA_3.x = ffma(srcX.w, srcW_.x, dstA_3.x); - dstA_3.y = ffma(srcX.w, srcW_.y, dstA_3.y); - dstA_3.z = ffma(srcX.w, srcW_.z, dstA_3.z); - dstA_3.w = ffma(srcX.w, srcW_.w, dstA_3.w); - - srcX = float4( - X_[idX.x + ty*4], - X_[idX.y + ty*4], - X_[idX.z + ty*4], - X_[idX.w + ty*4]); - idX += incX; - - dstA_0.x = ffma(srcX.x, srcW.x, dstA_0.x); - dstA_0.y = ffma(srcX.x, srcW.y, dstA_0.y); - dstA_0.z = ffma(srcX.x, srcW.z, dstA_0.z); - dstA_0.w = ffma(srcX.x, srcW.w, dstA_0.w); - - dstA_1.x = ffma(srcX.y, srcW.x, dstA_1.x); - dstA_1.y = ffma(srcX.y, srcW.y, dstA_1.y); - dstA_1.z = ffma(srcX.y, srcW.z, dstA_1.z); - dstA_1.w = ffma(srcX.y, srcW.w, dstA_1.w); - - dstA_2.x = ffma(srcX.z, srcW.x, dstA_2.x); - dstA_2.y = ffma(srcX.z, srcW.y, dstA_2.y); - dstA_2.z = ffma(srcX.z, srcW.z, dstA_2.z); - dstA_2.w = ffma(srcX.z, srcW.w, dstA_2.w); - - dstA_3.x = ffma(srcX.w, srcW.x, dstA_3.x); - dstA_3.y = ffma(srcX.w, srcW.y, dstA_3.y); - dstA_3.z = ffma(srcX.w, srcW.z, dstA_3.z); - dstA_3.w = ffma(srcX.w, srcW.w, dstA_3.w); - - - GroupMemoryBarrierWithGroupSync(); - } -#else // DOUBLE_BUFFER_LDS_READS - -#define CACHE_UNROLL 1 - for (int di = 0; di < CACHE_DEPTH; di+=CACHE_UNROLL) - { - float4 srcX = float4( - X_[idX.x + /*ti+0**/ ty*4], - X_[idX.y + /*ti+0**/ ty*4], - X_[idX.z + /*ti+0**/ ty*4], - X_[idX.w + /*ti+0**/ ty*4]); - //X_[di*_64 + ty*4 + 0], - //X_[di*_64 + ty*4 + 1], - //X_[di*_64 + ty*4 + 2], - //X_[di*_64 + ty*4 + 3]); - //X.Get(y+0, i+di), - //X.Get(y+1, i+di), - //X.Get(y+2, i+di), - //X.Get(y+3, i+di)); - float4 srcW = float4( - #if BLOCKED_W == 1 - W_[idW.x + tx], - W_[idW.y + tx], - W_[idW.z + tx], - W_[idW.w + tx] - #else - W_[idW.x + tx*4], - W_[idW.y + tx*4], - W_[idW.z + tx*4], - W_[idW.w + tx*4] - #endif - //W_[di*64 + tx*4 + 0], - //W_[di*64 + tx*4 + 1], - //W_[di*64 + tx*4 + 2], - //W_[di*64 + tx*4 + 3] - //W.Get(i+di, x+0), - //W.Get(i+di, x+1), - //W.Get(i+di, x+2), - //W.Get(i+di, x+3) - ); - idX += incX; - idW += incW; - - dstA_0.x = ffma(srcX.x, srcW.x, dstA_0.x); - dstA_0.y = ffma(srcX.x, srcW.y, dstA_0.y); - dstA_0.z = ffma(srcX.x, srcW.z, dstA_0.z); - dstA_0.w = ffma(srcX.x, srcW.w, dstA_0.w); - - dstA_1.x = ffma(srcX.y, srcW.x, dstA_1.x); - dstA_1.y = ffma(srcX.y, srcW.y, dstA_1.y); - dstA_1.z = ffma(srcX.y, srcW.z, dstA_1.z); - dstA_1.w = ffma(srcX.y, srcW.w, dstA_1.w); - - dstA_2.x = ffma(srcX.z, srcW.x, dstA_2.x); - dstA_2.y = ffma(srcX.z, srcW.y, dstA_2.y); - dstA_2.z = ffma(srcX.z, srcW.z, dstA_2.z); - dstA_2.w = ffma(srcX.z, srcW.w, dstA_2.w); - - dstA_3.x = ffma(srcX.w, srcW.x, dstA_3.x); - dstA_3.y = ffma(srcX.w, srcW.y, dstA_3.y); - dstA_3.z = ffma(srcX.w, srcW.z, dstA_3.z); - dstA_3.w = ffma(srcX.w, srcW.w, dstA_3.w); - -#if CACHE_UNROLL>=2 -#endif -#if CACHE_UNROLL>=3 -#endif -#if CACHE_UNROLL>=4 -#endif - } - - GroupMemoryBarrierWithGroupSync(); - } -#undef CACHE_UNROLL -#endif //DOUBLE_BUFFER_LDS_READS - - O.FastSetWithActivation(strideO * (y+0) + x+0 + offsetO, dstA_0.x); - O.FastSetWithActivation(strideO * (y+0) + x+1 + offsetO, dstA_0.y); - O.FastSetWithActivation(strideO * (y+0) + x+2 + offsetO, dstA_0.z); - O.FastSetWithActivation(strideO * (y+0) + x+3 + offsetO, dstA_0.w); - O.FastSetWithActivation(strideO * (y+1) + x+0 + offsetO, dstA_1.x); - O.FastSetWithActivation(strideO * (y+1) + x+1 + offsetO, dstA_1.y); - O.FastSetWithActivation(strideO * (y+1) + x+2 + offsetO, dstA_1.z); - O.FastSetWithActivation(strideO * (y+1) + x+3 + offsetO, dstA_1.w); - O.FastSetWithActivation(strideO * (y+2) + x+0 + offsetO, dstA_2.x); - O.FastSetWithActivation(strideO * (y+2) + x+1 + offsetO, dstA_2.y); - O.FastSetWithActivation(strideO * (y+2) + x+2 + offsetO, dstA_2.z); - O.FastSetWithActivation(strideO * (y+2) + x+3 + offsetO, dstA_2.w); - O.FastSetWithActivation(strideO * (y+3) + x+0 + offsetO, dstA_3.x); - O.FastSetWithActivation(strideO * (y+3) + x+1 + offsetO, dstA_3.y); - O.FastSetWithActivation(strideO * (y+3) + x+2 + offsetO, dstA_3.z); - O.FastSetWithActivation(strideO * (y+3) + x+3 + offsetO, dstA_3.w); - - #undef X_ - #undef W_ -} -#undef TRANSPOSED_X -#undef SHIFTED_X -#undef BLOCKED_W -#undef HARDCODED_DIMS -#undef BUF_OFFSET -#undef DOUBLE_BUFFER_LDS_READS -#undef CACHE_DEPTH -#else -[numthreads(16,16,1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - int x = (int)dispatchThreadID.x * BLOCK_SIZE; - int y = (int)dispatchThreadID.y * BLOCK_SIZE; - int n = (int)X.GetFlatWidth(); - - if (x >= (int)O.GetFlatWidth()) return; - if (y >= (int)O.GetFlatHeight()) return; - - float dstA[BLOCK_SIZE][BLOCK_SIZE]; - float srcX[BLOCK_SIZE]; - - int dy, dx; - for (dx = 0; dx < BLOCK_SIZE; ++dx) - for (dy = 0; dy < BLOCK_SIZE; ++dy) - dstA[dy][dx] = B.data[x+dx+B.offset];//B.Get(x+dx); - - for (int i = 0; i < n; ++i) - { - for (dy = 0; dy < BLOCK_SIZE; ++dy) - srcX[dy] = X.data[(y+dy)*X.channels+i];//X.Get(y+dy, i); - - for (dx = 0; dx < BLOCK_SIZE; ++dx) - { - float srcW = W.data[i*W.channels+x+dx];//W.Get(i, x+dx); - for (dy = 0; dy < BLOCK_SIZE; ++dy) - dstA[dy][dx] += srcX[dy] * srcW; - } - } - - for (dx = 0; dx < BLOCK_SIZE; ++dx) - for (dy = 0; dy < BLOCK_SIZE; ++dy) - O.SetWithActivation(y+dy, x+dx, dstA[dy][dx]); -} -#endif -#undef KERNEL_NAME - - -//CACHE_DEPTH -// T >>X -//16: 183ms 207ms -// 8: 158ms 202ms -// 4: 162ms 334ms -// 2: 159ms ***ms -// 1: 173ms -- - -#define KERNEL_NAME Dense_T8x8_R -#if BLOCK_SIZE == 8 -#define UNROLL_INNER_LOOP 0 -#define TRANSPOSED_X 0 -#define HARDCODED_DIMS 0 -#define BUF_OFFSET 0 -#define CACHE_DEPTH 8 -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, X)[CACHE_DEPTH*8*BLOCK_SIZE+(1-TRANSPOSED_X)*CACHE_DEPTH]; -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, W)[CACHE_DEPTH*8*BLOCK_SIZE]; -[numthreads(8,8,1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - int x = (int)dispatchThreadID.x * BLOCK_SIZE; - int y = (int)dispatchThreadID.y * BLOCK_SIZE; - int tx = (int)groupThreadID.x; - int ty = (int)groupThreadID.y; - int bx = ((int)dispatchThreadID.x - (int)groupThreadID.x) * BLOCK_SIZE; - int by = ((int)dispatchThreadID.y - (int)groupThreadID.y) * BLOCK_SIZE; - int ti = (int)threadIndex; - int n = (int)X.GetFlatWidth(); - int strideX = (int)X.GetFlatWidth(); - int strideW = (int)W.GetFlatWidth(); - int strideO = (int)O.GetFlatWidth(); - int offsetX = BUF_OFFSET; - int offsetW = BUF_OFFSET; - int offsetO = BUF_OFFSET; -#if HARDCODED_DIMS == 1 - n = 1024; - strideX = 1024; - strideW = 1024; - strideO = 1024; -#endif - - #define X_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, X) - #define W_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, W) - -#if UNROLL_INNER_LOOP - float4 dstA_0, dstA_1, dstA_2, dstA_3; - float4 dstB_0, dstB_1, dstB_2, dstB_3; - float4 dstC_0, dstC_1, dstC_2, dstC_3; - float4 dstD_0, dstD_1, dstD_2, dstD_3; - - dstA_0.x = dstC_0.x = B.FastGet(x+0); - dstA_1.x = dstC_1.x = B.FastGet(x+0); - dstA_2.x = dstC_2.x = B.FastGet(x+0); - dstA_3.x = dstC_3.x = B.FastGet(x+0); - dstA_0.y = dstC_0.y = B.FastGet(x+1); - dstA_1.y = dstC_1.y = B.FastGet(x+1); - dstA_2.y = dstC_2.y = B.FastGet(x+1); - dstA_3.y = dstC_3.y = B.FastGet(x+1); - dstA_0.z = dstC_0.z = B.FastGet(x+2); - dstA_1.z = dstC_1.z = B.FastGet(x+2); - dstA_2.z = dstC_2.z = B.FastGet(x+2); - dstA_3.z = dstC_3.z = B.FastGet(x+2); - dstA_0.w = dstC_0.w = B.FastGet(x+3); - dstA_1.w = dstC_1.w = B.FastGet(x+3); - dstA_2.w = dstC_2.w = B.FastGet(x+3); - dstA_3.w = dstC_3.w = B.FastGet(x+3); - - dstB_0.x = dstD_0.x = B.FastGet(x+4); - dstB_1.x = dstD_1.x = B.FastGet(x+4); - dstB_2.x = dstD_2.x = B.FastGet(x+4); - dstB_3.x = dstD_3.x = B.FastGet(x+4); - dstB_0.y = dstD_0.y = B.FastGet(x+5); - dstB_1.y = dstD_1.y = B.FastGet(x+5); - dstB_2.y = dstD_2.y = B.FastGet(x+5); - dstB_3.y = dstD_3.y = B.FastGet(x+5); - dstB_0.z = dstD_0.z = B.FastGet(x+6); - dstB_1.z = dstD_1.z = B.FastGet(x+6); - dstB_2.z = dstD_2.z = B.FastGet(x+6); - dstB_3.z = dstD_3.z = B.FastGet(x+6); - dstB_0.w = dstD_0.w = B.FastGet(x+7); - dstB_1.w = dstD_1.w = B.FastGet(x+7); - dstB_2.w = dstD_2.w = B.FastGet(x+7); - dstB_3.w = dstD_3.w = B.FastGet(x+7); -#else - float4 dstA_0[4], dstA_1[4], dstA_2[4], dstA_3[4]; - dstA_0[0].x = dstA_0[2].x = B.FastGet(x+0); - dstA_1[0].x = dstA_1[2].x = B.FastGet(x+0); - dstA_2[0].x = dstA_2[2].x = B.FastGet(x+0); - dstA_3[0].x = dstA_3[2].x = B.FastGet(x+0); - dstA_0[0].y = dstA_0[2].y = B.FastGet(x+1); - dstA_1[0].y = dstA_1[2].y = B.FastGet(x+1); - dstA_2[0].y = dstA_2[2].y = B.FastGet(x+1); - dstA_3[0].y = dstA_3[2].y = B.FastGet(x+1); - dstA_0[0].z = dstA_0[2].z = B.FastGet(x+2); - dstA_1[0].z = dstA_1[2].z = B.FastGet(x+2); - dstA_2[0].z = dstA_2[2].z = B.FastGet(x+2); - dstA_3[0].z = dstA_3[2].z = B.FastGet(x+2); - dstA_0[0].w = dstA_0[2].w = B.FastGet(x+3); - dstA_1[0].w = dstA_1[2].w = B.FastGet(x+3); - dstA_2[0].w = dstA_2[2].w = B.FastGet(x+3); - dstA_3[0].w = dstA_3[2].w = B.FastGet(x+3); - - dstA_0[1].x = dstA_0[3].x = B.FastGet(x+4); - dstA_1[1].x = dstA_1[3].x = B.FastGet(x+4); - dstA_2[1].x = dstA_2[3].x = B.FastGet(x+4); - dstA_3[1].x = dstA_3[3].x = B.FastGet(x+4); - dstA_0[1].y = dstA_0[3].y = B.FastGet(x+5); - dstA_1[1].y = dstA_1[3].y = B.FastGet(x+5); - dstA_2[1].y = dstA_2[3].y = B.FastGet(x+5); - dstA_3[1].y = dstA_3[3].y = B.FastGet(x+5); - dstA_0[1].z = dstA_0[3].z = B.FastGet(x+6); - dstA_1[1].z = dstA_1[3].z = B.FastGet(x+6); - dstA_2[1].z = dstA_2[3].z = B.FastGet(x+6); - dstA_3[1].z = dstA_3[3].z = B.FastGet(x+6); - dstA_0[1].w = dstA_0[3].w = B.FastGet(x+7); - dstA_1[1].w = dstA_1[3].w = B.FastGet(x+7); - dstA_2[1].w = dstA_2[3].w = B.FastGet(x+7); - dstA_3[1].w = dstA_3[3].w = B.FastGet(x+7); - -#endif - - for (int i = 0; i < n; i += CACHE_DEPTH) - { - #if TRANSPOSED_X == 1 - [unroll] - for (int j = 0; j < CACHE_DEPTH; ++j) - { - X_[ti + j*64] = X.data[strideX * (i + j) + by + ti + offsetX]; - - // split 64 into 8 blocks and interleave them - // 000000001111111122222222... => 012345678012345678... - W_[((ti&7)<<3) + (ti>>3) + j*64] = W.data[strideW * (i + j) + bx + ti + offsetW]; - } - #else - int tiDiv = (uint)ti/CACHE_DEPTH; - int tiMod = ti&(CACHE_DEPTH-1); - int jStride = 64/CACHE_DEPTH; - - [unroll] - for (int j = 0; j < CACHE_DEPTH; ++j) - { - // CACHE_DEPTHx64 => 64xCACHE_DEPTH - X_[tiDiv + 65*tiMod + j*jStride] = X.data[strideX * (by + tiDiv + j*jStride) + i + tiMod]; - - // split 64 into 8 blocks and interleave them - // 000000001111111122222222... => 012345678012345678... - W_[((ti&7)<<3) + (ti>>3) + j*64] = W.data[strideW * (i + j) + bx + ti + offsetW]; - } - #endif - - GroupMemoryBarrierWithGroupSync(); - -#if UNROLL_INNER_LOOP - int4 idX0 = int4(0,1,2,3); int4 idX1 = int4(4,5,6,7); - int4 idW0 = int4(0,8,16,24); int4 idW1 = int4(32,40,48,56); -#else - int4 idX[2], idW[2]; - idX[0] = int4(0,1,2,3); idX[1] = int4(4,5,6,7); - idW[0] = int4(0,8,16,24); idW[1] = int4(32,40,48,56); -#endif - int incX = 64 + (TRANSPOSED_X?0:1); - int incW = 64; - for (int di = 0; di < CACHE_DEPTH; di++) - { -#if UNROLL_INNER_LOOP - float4 srcX0 = float4( - X_[idX0.x + ty*8], - X_[idX0.y + ty*8], - X_[idX0.z + ty*8], - X_[idX0.w + ty*8]); - float4 srcX1 = float4( - X_[idX1.x + ty*8], - X_[idX1.y + ty*8], - X_[idX1.z + ty*8], - X_[idX1.w + ty*8]); - float4 srcW0 = float4( - W_[idW0.x + tx], - W_[idW0.y + tx], - W_[idW0.z + tx], - W_[idW0.w + tx]); - float4 srcW1 = float4( - W_[idW1.x + tx], - W_[idW1.y + tx], - W_[idW1.z + tx], - W_[idW1.w + tx]); - idX0 += incX; idX1 += incX; - idW0 += incW; idW1 += incW; - - dstA_0.x = ffma(srcX0.x, srcW0.x, dstA_0.x); - dstA_0.y = ffma(srcX0.x, srcW0.y, dstA_0.y); - dstA_0.z = ffma(srcX0.x, srcW0.z, dstA_0.z); - dstA_0.w = ffma(srcX0.x, srcW0.w, dstA_0.w); - dstA_1.x = ffma(srcX0.y, srcW0.x, dstA_1.x); - dstA_1.y = ffma(srcX0.y, srcW0.y, dstA_1.y); - dstA_1.z = ffma(srcX0.y, srcW0.z, dstA_1.z); - dstA_1.w = ffma(srcX0.y, srcW0.w, dstA_1.w); - dstA_2.x = ffma(srcX0.z, srcW0.x, dstA_2.x); - dstA_2.y = ffma(srcX0.z, srcW0.y, dstA_2.y); - dstA_2.z = ffma(srcX0.z, srcW0.z, dstA_2.z); - dstA_2.w = ffma(srcX0.z, srcW0.w, dstA_2.w); - dstA_3.x = ffma(srcX0.w, srcW0.x, dstA_3.x); - dstA_3.y = ffma(srcX0.w, srcW0.y, dstA_3.y); - dstA_3.z = ffma(srcX0.w, srcW0.z, dstA_3.z); - dstA_3.w = ffma(srcX0.w, srcW0.w, dstA_3.w); - - // - dstB_0.x = ffma(srcX0.x, srcW1.x, dstB_0.x); - dstB_0.y = ffma(srcX0.x, srcW1.y, dstB_0.y); - dstB_0.z = ffma(srcX0.x, srcW1.z, dstB_0.z); - dstB_0.w = ffma(srcX0.x, srcW1.w, dstB_0.w); - dstB_1.x = ffma(srcX0.y, srcW1.x, dstB_1.x); - dstB_1.y = ffma(srcX0.y, srcW1.y, dstB_1.y); - dstB_1.z = ffma(srcX0.y, srcW1.z, dstB_1.z); - dstB_1.w = ffma(srcX0.y, srcW1.w, dstB_1.w); - dstB_2.x = ffma(srcX0.z, srcW1.x, dstB_2.x); - dstB_2.y = ffma(srcX0.z, srcW1.y, dstB_2.y); - dstB_2.z = ffma(srcX0.z, srcW1.z, dstB_2.z); - dstB_2.w = ffma(srcX0.z, srcW1.w, dstB_2.w); - dstB_3.x = ffma(srcX0.w, srcW1.x, dstB_3.x); - dstB_3.y = ffma(srcX0.w, srcW1.y, dstB_3.y); - dstB_3.z = ffma(srcX0.w, srcW1.z, dstB_3.z); - dstB_3.w = ffma(srcX0.w, srcW1.w, dstB_3.w); - - // - dstC_0.x = ffma(srcX1.x, srcW0.x, dstC_0.x); - dstC_0.y = ffma(srcX1.x, srcW0.y, dstC_0.y); - dstC_0.z = ffma(srcX1.x, srcW0.z, dstC_0.z); - dstC_0.w = ffma(srcX1.x, srcW0.w, dstC_0.w); - dstC_1.x = ffma(srcX1.y, srcW0.x, dstC_1.x); - dstC_1.y = ffma(srcX1.y, srcW0.y, dstC_1.y); - dstC_1.z = ffma(srcX1.y, srcW0.z, dstC_1.z); - dstC_1.w = ffma(srcX1.y, srcW0.w, dstC_1.w); - dstC_2.x = ffma(srcX1.z, srcW0.x, dstC_2.x); - dstC_2.y = ffma(srcX1.z, srcW0.y, dstC_2.y); - dstC_2.z = ffma(srcX1.z, srcW0.z, dstC_2.z); - dstC_2.w = ffma(srcX1.z, srcW0.w, dstC_2.w); - dstC_3.x = ffma(srcX1.w, srcW0.x, dstC_3.x); - dstC_3.y = ffma(srcX1.w, srcW0.y, dstC_3.y); - dstC_3.z = ffma(srcX1.w, srcW0.z, dstC_3.z); - dstC_3.w = ffma(srcX1.w, srcW0.w, dstC_3.w); - - // - dstD_0.x = ffma(srcX1.x, srcW1.x, dstD_0.x); - dstD_0.y = ffma(srcX1.x, srcW1.y, dstD_0.y); - dstD_0.z = ffma(srcX1.x, srcW1.z, dstD_0.z); - dstD_0.w = ffma(srcX1.x, srcW1.w, dstD_0.w); - dstD_1.x = ffma(srcX1.y, srcW1.x, dstD_1.x); - dstD_1.y = ffma(srcX1.y, srcW1.y, dstD_1.y); - dstD_1.z = ffma(srcX1.y, srcW1.z, dstD_1.z); - dstD_1.w = ffma(srcX1.y, srcW1.w, dstD_1.w); - dstD_2.x = ffma(srcX1.z, srcW1.x, dstD_2.x); - dstD_2.y = ffma(srcX1.z, srcW1.y, dstD_2.y); - dstD_2.z = ffma(srcX1.z, srcW1.z, dstD_2.z); - dstD_2.w = ffma(srcX1.z, srcW1.w, dstD_2.w); - dstD_3.x = ffma(srcX1.w, srcW1.x, dstD_3.x); - dstD_3.y = ffma(srcX1.w, srcW1.y, dstD_3.y); - dstD_3.z = ffma(srcX1.w, srcW1.z, dstD_3.z); - dstD_3.w = ffma(srcX1.w, srcW1.w, dstD_3.w); - -#else - float4 srcX[2], srcW[2]; - srcX[0] = float4( - X_[idX[0].x + ty*8], - X_[idX[0].y + ty*8], - X_[idX[0].z + ty*8], - X_[idX[0].w + ty*8]); - srcX[1] = float4( - X_[idX[1].x + ty*8], - X_[idX[1].y + ty*8], - X_[idX[1].z + ty*8], - X_[idX[1].w + ty*8]); - srcW[0] = float4( - W_[idW[0].x + tx], - W_[idW[0].y + tx], - W_[idW[0].z + tx], - W_[idW[0].w + tx]); - srcW[1] = float4( - W_[idW[1].x + tx], - W_[idW[1].y + tx], - W_[idW[1].z + tx], - W_[idW[1].w + tx]); - idX[0] += incX; idX[1] += incX; - idW[0] += incW; idW[1] += incW; - - - [loop] - for (uint qw = 0; qw < 4; ++qw) - { - uint q = qw >> 1; - uint w = qw & 1; - dstA_0[qw].x = ffma(srcX[q].x, srcW[w].x, dstA_0[qw].x); - dstA_0[qw].y = ffma(srcX[q].x, srcW[w].y, dstA_0[qw].y); - dstA_0[qw].z = ffma(srcX[q].x, srcW[w].z, dstA_0[qw].z); - dstA_0[qw].w = ffma(srcX[q].x, srcW[w].w, dstA_0[qw].w); - dstA_1[qw].x = ffma(srcX[q].y, srcW[w].x, dstA_1[qw].x); - dstA_1[qw].y = ffma(srcX[q].y, srcW[w].y, dstA_1[qw].y); - dstA_1[qw].z = ffma(srcX[q].y, srcW[w].z, dstA_1[qw].z); - dstA_1[qw].w = ffma(srcX[q].y, srcW[w].w, dstA_1[qw].w); - dstA_2[qw].x = ffma(srcX[q].z, srcW[w].x, dstA_2[qw].x); - dstA_2[qw].y = ffma(srcX[q].z, srcW[w].y, dstA_2[qw].y); - dstA_2[qw].z = ffma(srcX[q].z, srcW[w].z, dstA_2[qw].z); - dstA_2[qw].w = ffma(srcX[q].z, srcW[w].w, dstA_2[qw].w); - dstA_3[qw].x = ffma(srcX[q].w, srcW[w].x, dstA_3[qw].x); - dstA_3[qw].y = ffma(srcX[q].w, srcW[w].y, dstA_3[qw].y); - dstA_3[qw].z = ffma(srcX[q].w, srcW[w].z, dstA_3[qw].z); - dstA_3[qw].w = ffma(srcX[q].w, srcW[w].w, dstA_3[qw].w); - } -#endif - } - - GroupMemoryBarrierWithGroupSync(); - } -#if UNROLL_INNER_LOOP - O.FastSetWithActivation(strideO * (y+0) + x+0 + offsetO], dstA_0.x); - O.FastSetWithActivation(strideO * (y+0) + x+1 + offsetO], dstA_0.y); - O.FastSetWithActivation(strideO * (y+0) + x+2 + offsetO], dstA_0.z); - O.FastSetWithActivation(strideO * (y+0) + x+3 + offsetO], dstA_0.w); - O.FastSetWithActivation(strideO * (y+0) + x+4 + offsetO], dstB_0.x); - O.FastSetWithActivation(strideO * (y+0) + x+5 + offsetO], dstB_0.y); - O.FastSetWithActivation(strideO * (y+0) + x+6 + offsetO], dstB_0.z); - O.FastSetWithActivation(strideO * (y+0) + x+7 + offsetO], dstB_0.w); - O.FastSetWithActivation(strideO * (y+1) + x+0 + offsetO], dstA_1.x); - O.FastSetWithActivation(strideO * (y+1) + x+1 + offsetO], dstA_1.y); - O.FastSetWithActivation(strideO * (y+1) + x+2 + offsetO], dstA_1.z); - O.FastSetWithActivation(strideO * (y+1) + x+3 + offsetO], dstA_1.w); - O.FastSetWithActivation(strideO * (y+1) + x+4 + offsetO], dstB_1.x); - O.FastSetWithActivation(strideO * (y+1) + x+5 + offsetO], dstB_1.y); - O.FastSetWithActivation(strideO * (y+1) + x+6 + offsetO], dstB_1.z); - O.FastSetWithActivation(strideO * (y+1) + x+7 + offsetO], dstB_1.w); - O.FastSetWithActivation(strideO * (y+2) + x+0 + offsetO], dstA_2.x); - O.FastSetWithActivation(strideO * (y+2) + x+1 + offsetO], dstA_2.y); - O.FastSetWithActivation(strideO * (y+2) + x+2 + offsetO], dstA_2.z); - O.FastSetWithActivation(strideO * (y+2) + x+3 + offsetO], dstA_2.w); - O.FastSetWithActivation(strideO * (y+2) + x+4 + offsetO], dstB_2.x); - O.FastSetWithActivation(strideO * (y+2) + x+5 + offsetO], dstB_2.y); - O.FastSetWithActivation(strideO * (y+2) + x+6 + offsetO], dstB_2.z); - O.FastSetWithActivation(strideO * (y+2) + x+7 + offsetO], dstB_2.w); - O.FastSetWithActivation(strideO * (y+3) + x+0 + offsetO], dstA_3.x); - O.FastSetWithActivation(strideO * (y+3) + x+1 + offsetO], dstA_3.y); - O.FastSetWithActivation(strideO * (y+3) + x+2 + offsetO], dstA_3.z); - O.FastSetWithActivation(strideO * (y+3) + x+3 + offsetO], dstA_3.w); - O.FastSetWithActivation(strideO * (y+3) + x+4 + offsetO], dstB_3.x); - O.FastSetWithActivation(strideO * (y+3) + x+5 + offsetO], dstB_3.y); - O.FastSetWithActivation(strideO * (y+3) + x+6 + offsetO], dstB_3.z); - O.FastSetWithActivation(strideO * (y+3) + x+7 + offsetO], dstB_3.w); - - O.FastSetWithActivation(strideO * (y+4) + x+0 + offsetO], dstC_0.x); - O.FastSetWithActivation(strideO * (y+4) + x+1 + offsetO], dstC_0.y); - O.FastSetWithActivation(strideO * (y+4) + x+2 + offsetO], dstC_0.z); - O.FastSetWithActivation(strideO * (y+4) + x+3 + offsetO], dstC_0.w); - O.FastSetWithActivation(strideO * (y+4) + x+4 + offsetO], dstD_0.x); - O.FastSetWithActivation(strideO * (y+4) + x+5 + offsetO], dstD_0.y); - O.FastSetWithActivation(strideO * (y+4) + x+6 + offsetO], dstD_0.z); - O.FastSetWithActivation(strideO * (y+4) + x+7 + offsetO], dstD_0.w); - O.FastSetWithActivation(strideO * (y+5) + x+0 + offsetO], dstC_1.x); - O.FastSetWithActivation(strideO * (y+5) + x+1 + offsetO], dstC_1.y); - O.FastSetWithActivation(strideO * (y+5) + x+2 + offsetO], dstC_1.z); - O.FastSetWithActivation(strideO * (y+5) + x+3 + offsetO], dstC_1.w); - O.FastSetWithActivation(strideO * (y+5) + x+4 + offsetO], dstD_1.x); - O.FastSetWithActivation(strideO * (y+5) + x+5 + offsetO], dstD_1.y); - O.FastSetWithActivation(strideO * (y+5) + x+6 + offsetO], dstD_1.z); - O.FastSetWithActivation(strideO * (y+5) + x+7 + offsetO], dstD_1.w); - O.FastSetWithActivation(strideO * (y+6) + x+0 + offsetO], dstC_2.x); - O.FastSetWithActivation(strideO * (y+6) + x+1 + offsetO], dstC_2.y); - O.FastSetWithActivation(strideO * (y+6) + x+2 + offsetO], dstC_2.z); - O.FastSetWithActivation(strideO * (y+6) + x+3 + offsetO], dstC_2.w); - O.FastSetWithActivation(strideO * (y+6) + x+4 + offsetO], dstD_2.x); - O.FastSetWithActivation(strideO * (y+6) + x+5 + offsetO], dstD_2.y); - O.FastSetWithActivation(strideO * (y+6) + x+6 + offsetO], dstD_2.z); - O.FastSetWithActivation(strideO * (y+6) + x+7 + offsetO], dstD_2.w); - O.FastSetWithActivation(strideO * (y+7) + x+0 + offsetO], dstC_3.x); - O.FastSetWithActivation(strideO * (y+7) + x+1 + offsetO], dstC_3.y); - O.FastSetWithActivation(strideO * (y+7) + x+2 + offsetO], dstC_3.z); - O.FastSetWithActivation(strideO * (y+7) + x+3 + offsetO], dstC_3.w); - O.FastSetWithActivation(strideO * (y+7) + x+4 + offsetO], dstD_3.x); - O.FastSetWithActivation(strideO * (y+7) + x+5 + offsetO], dstD_3.y); - O.FastSetWithActivation(strideO * (y+7) + x+6 + offsetO], dstD_3.z); - O.FastSetWithActivation(strideO * (y+7) + x+7 + offsetO], dstD_3.w); -#else - O.FastSetWithActivation(strideO * (y+0) + x+0 + offsetO], dstA_0[0].x); - O.FastSetWithActivation(strideO * (y+0) + x+1 + offsetO], dstA_0[0].y); - O.FastSetWithActivation(strideO * (y+0) + x+2 + offsetO], dstA_0[0].z); - O.FastSetWithActivation(strideO * (y+0) + x+3 + offsetO], dstA_0[0].w); - O.FastSetWithActivation(strideO * (y+0) + x+4 + offsetO], dstA_0[1].x); - O.FastSetWithActivation(strideO * (y+0) + x+5 + offsetO], dstA_0[1].y); - O.FastSetWithActivation(strideO * (y+0) + x+6 + offsetO], dstA_0[1].z); - O.FastSetWithActivation(strideO * (y+0) + x+7 + offsetO], dstA_0[1].w); - O.FastSetWithActivation(strideO * (y+1) + x+0 + offsetO], dstA_1[0].x); - O.FastSetWithActivation(strideO * (y+1) + x+1 + offsetO], dstA_1[0].y); - O.FastSetWithActivation(strideO * (y+1) + x+2 + offsetO], dstA_1[0].z); - O.FastSetWithActivation(strideO * (y+1) + x+3 + offsetO], dstA_1[0].w); - O.FastSetWithActivation(strideO * (y+1) + x+4 + offsetO], dstA_1[1].x); - O.FastSetWithActivation(strideO * (y+1) + x+5 + offsetO], dstA_1[1].y); - O.FastSetWithActivation(strideO * (y+1) + x+6 + offsetO], dstA_1[1].z); - O.FastSetWithActivation(strideO * (y+1) + x+7 + offsetO], dstA_1[1].w); - O.FastSetWithActivation(strideO * (y+2) + x+0 + offsetO], dstA_2[0].x); - O.FastSetWithActivation(strideO * (y+2) + x+1 + offsetO], dstA_2[0].y); - O.FastSetWithActivation(strideO * (y+2) + x+2 + offsetO], dstA_2[0].z); - O.FastSetWithActivation(strideO * (y+2) + x+3 + offsetO], dstA_2[0].w); - O.FastSetWithActivation(strideO * (y+2) + x+4 + offsetO], dstA_2[1].x); - O.FastSetWithActivation(strideO * (y+2) + x+5 + offsetO], dstA_2[1].y); - O.FastSetWithActivation(strideO * (y+2) + x+6 + offsetO], dstA_2[1].z); - O.FastSetWithActivation(strideO * (y+2) + x+7 + offsetO], dstA_2[1].w); - O.FastSetWithActivation(strideO * (y+3) + x+0 + offsetO], dstA_3[0].x); - O.FastSetWithActivation(strideO * (y+3) + x+1 + offsetO], dstA_3[0].y); - O.FastSetWithActivation(strideO * (y+3) + x+2 + offsetO], dstA_3[0].z); - O.FastSetWithActivation(strideO * (y+3) + x+3 + offsetO], dstA_3[0].w); - O.FastSetWithActivation(strideO * (y+3) + x+4 + offsetO], dstA_3[1].x); - O.FastSetWithActivation(strideO * (y+3) + x+5 + offsetO], dstA_3[1].y); - O.FastSetWithActivation(strideO * (y+3) + x+6 + offsetO], dstA_3[1].z); - O.FastSetWithActivation(strideO * (y+3) + x+7 + offsetO], dstA_3[1].w); - - O.FastSetWithActivation(strideO * (y+4) + x+0 + offsetO], dstA_0[2].x); - O.FastSetWithActivation(strideO * (y+4) + x+1 + offsetO], dstA_0[2].y); - O.FastSetWithActivation(strideO * (y+4) + x+2 + offsetO], dstA_0[2].z); - O.FastSetWithActivation(strideO * (y+4) + x+3 + offsetO], dstA_0[2].w); - O.FastSetWithActivation(strideO * (y+4) + x+4 + offsetO], dstA_0[3].x); - O.FastSetWithActivation(strideO * (y+4) + x+5 + offsetO], dstA_0[3].y); - O.FastSetWithActivation(strideO * (y+4) + x+6 + offsetO], dstA_0[3].z); - O.FastSetWithActivation(strideO * (y+4) + x+7 + offsetO], dstA_0[3].w); - O.FastSetWithActivation(strideO * (y+5) + x+0 + offsetO], dstA_1[2].x); - O.FastSetWithActivation(strideO * (y+5) + x+1 + offsetO], dstA_1[2].y); - O.FastSetWithActivation(strideO * (y+5) + x+2 + offsetO], dstA_1[2].z); - O.FastSetWithActivation(strideO * (y+5) + x+3 + offsetO], dstA_1[2].w); - O.FastSetWithActivation(strideO * (y+5) + x+4 + offsetO], dstA_1[3].x); - O.FastSetWithActivation(strideO * (y+5) + x+5 + offsetO], dstA_1[3].y); - O.FastSetWithActivation(strideO * (y+5) + x+6 + offsetO], dstA_1[3].z); - O.FastSetWithActivation(strideO * (y+5) + x+7 + offsetO], dstA_1[3].w); - O.FastSetWithActivation(strideO * (y+6) + x+0 + offsetO], dstA_2[2].x); - O.FastSetWithActivation(strideO * (y+6) + x+1 + offsetO], dstA_2[2].y); - O.FastSetWithActivation(strideO * (y+6) + x+2 + offsetO], dstA_2[2].z); - O.FastSetWithActivation(strideO * (y+6) + x+3 + offsetO], dstA_2[2].w); - O.FastSetWithActivation(strideO * (y+6) + x+4 + offsetO], dstA_2[3].x); - O.FastSetWithActivation(strideO * (y+6) + x+5 + offsetO], dstA_2[3].y); - O.FastSetWithActivation(strideO * (y+6) + x+6 + offsetO], dstA_2[3].z); - O.FastSetWithActivation(strideO * (y+6) + x+7 + offsetO], dstA_2[3].w); - O.FastSetWithActivation(strideO * (y+7) + x+0 + offsetO], dstA_3[2].x); - O.FastSetWithActivation(strideO * (y+7) + x+1 + offsetO], dstA_3[2].y); - O.FastSetWithActivation(strideO * (y+7) + x+2 + offsetO], dstA_3[2].z); - O.FastSetWithActivation(strideO * (y+7) + x+3 + offsetO], dstA_3[2].w); - O.FastSetWithActivation(strideO * (y+7) + x+4 + offsetO], dstA_3[3].x); - O.FastSetWithActivation(strideO * (y+7) + x+5 + offsetO], dstA_3[3].y); - O.FastSetWithActivation(strideO * (y+7) + x+6 + offsetO], dstA_3[3].z); - O.FastSetWithActivation(strideO * (y+7) + x+7 + offsetO], dstA_3[3].w); -#endif - - #undef X_ - #undef W_ -} -#undef TRANSPOSED_X -#undef BLOCKED_W -#undef HARDCODED_DIMS -#undef BUF_OFFSET -#undef CACHE_DEPTH -#elif BLOCK_SIZE == 4 -#define TRANSPOSED_X 0 -#define SHIFTED_X 0 -#define CACHE_DEPTH 4 -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, X)[CACHE_DEPTH*8*BLOCK_SIZE+SHIFTED_X*CACHE_DEPTH]; -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, W)[CACHE_DEPTH*8*BLOCK_SIZE]; -[numthreads(8,8,1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint threadIndex : SV_GroupIndex) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - int x = (int)dispatchThreadID.x * BLOCK_SIZE; - int y = (int)dispatchThreadID.y * BLOCK_SIZE; - int tx = (int)groupThreadID.x; - int ty = (int)groupThreadID.y; - int bx = ((int)dispatchThreadID.x - (int)groupThreadID.x) * BLOCK_SIZE; - int by = ((int)dispatchThreadID.y - (int)groupThreadID.y) * BLOCK_SIZE; - int ti = (int)threadIndex; - int n = (int)X.GetFlatWidth(); - int strideX = (int)X.GetFlatWidth(); - int strideW = (int)W.GetFlatWidth(); - - #define X_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, X) - #define W_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, W) - - //if (x >= (int)O.GetFlatWidth()) return; - //if (y >= (int)O.GetFlatHeight()) return; - - float4 dstA_0, dstA_1, dstA_2, dstA_3; - - dstA_0.x = B.FastGet(x+0); - dstA_1.x = B.FastGet(x+0); - dstA_2.x = B.FastGet(x+0); - dstA_3.x = B.FastGet(x+0); - dstA_0.y = B.FastGet(x+1); - dstA_1.y = B.FastGet(x+1); - dstA_2.y = B.FastGet(x+1); - dstA_3.y = B.FastGet(x+1); - dstA_0.z = B.FastGet(x+2); - dstA_1.z = B.FastGet(x+2); - dstA_2.z = B.FastGet(x+2); - dstA_3.z = B.FastGet(x+2); - dstA_0.w = B.FastGet(x+3); - dstA_1.w = B.FastGet(x+3); - dstA_2.w = B.FastGet(x+3); - dstA_3.w = B.FastGet(x+3); - - for (int i = 0; i < n; i += CACHE_DEPTH) - { - #if CACHE_DEPTH == 16 - W_[ti ] = W.data[strideW * (i + (ti>>5) + 0) + bx + (ti&31)]; - W_[ti+ 64] = W.data[strideW * (i + (ti>>5) + 2) + bx + (ti&31)]; - W_[ti+128] = W.data[strideW * (i + (ti>>5) + 4) + bx + (ti&31)]; - W_[ti+192] = W.data[strideW * (i + (ti>>5) + 6) + bx + (ti&31)]; - W_[ti+256] = W.data[strideW * (i + (ti>>5) + 8) + bx + (ti&31)]; - W_[ti+320] = W.data[strideW * (i + (ti>>5) +10) + bx + (ti&31)]; - W_[ti+384] = W.data[strideW * (i + (ti>>5) +12) + bx + (ti&31)]; - W_[ti+448] = W.data[strideW * (i + (ti>>5) +14) + bx + (ti&31)]; - #if TRANSPOSED_X == 1 - X_[ti ] = X.data[strideX * (i + (ti>>5) + 0) + by + (ti&31)]; - X_[ti+ 64] = X.data[strideX * (i + (ti>>5) + 2) + by + (ti&31)]; - X_[ti+128] = X.data[strideX * (i + (ti>>5) + 4) + by + (ti&31)]; - X_[ti+192] = X.data[strideX * (i + (ti>>5) + 6) + by + (ti&31)]; - X_[ti+256] = X.data[strideX * (i + (ti>>5) + 8) + by + (ti&31)]; - X_[ti+320] = X.data[strideX * (i + (ti>>5) +10) + by + (ti&31)]; - X_[ti+384] = X.data[strideX * (i + (ti>>5) +12) + by + (ti&31)]; - X_[ti+448] = X.data[strideX * (i + (ti>>5) +14) + by + (ti&31)]; - #elif SHIFTED_X == 1 - /* - g=ti/16 - j=ti&15 - - g0 j0123456789ABCDEF - g1 j0123456789ABCDEF - g2 j0123456789ABCDEF - g3 j0123456789ABCDEF - g0.j0 g1.j0 g2.j0 g3.j0 g0.j1 g1.j1 g2.j1 g3.j1 - - 16x32 => 32x16 - */ - X_[(ti>>4) + 33*(ti&15) + 0] = X.data[strideX * (by + (ti>>4) + 0) + i + (ti&15) ]; - X_[(ti>>4) + 33*(ti&15) + 4] = X.data[strideX * (by + (ti>>4) + 4) + i + (ti&15) ]; - X_[(ti>>4) + 33*(ti&15) + 8] = X.data[strideX * (by + (ti>>4) + 8) + i + (ti&15) ]; - X_[(ti>>4) + 33*(ti&15) +12] = X.data[strideX * (by + (ti>>4) +12) + i + (ti&15) ]; - X_[(ti>>4) + 33*(ti&15) +16] = X.data[strideX * (by + (ti>>4) +16) + i + (ti&15) ]; - X_[(ti>>4) + 33*(ti&15) +20] = X.data[strideX * (by + (ti>>4) +20) + i + (ti&15) ]; - X_[(ti>>4) + 33*(ti&15) +24] = X.data[strideX * (by + (ti>>4) +24) + i + (ti&15) ]; - X_[(ti>>4) + 33*(ti&15) +28] = X.data[strideX * (by + (ti>>4) +28) + i + (ti&15) ]; - #else - //X_[ti] = X.Get(by + (ti/16), i + (ti&15)); - X_[ti ] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 0]; - X_[ti+ 64] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 2]; - X_[ti+128] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 4]; - X_[ti+192] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 6]; - X_[ti+256] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 8]; - X_[ti+320] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) +10]; - X_[ti+384] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) +12]; - X_[ti+448] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) +14]; - #endif - - #elif CACHE_DEPTH == 8 - W_[ti ] = W.data[strideW * (i + (ti>>5) + 0) + bx + (ti&31)]; - W_[ti+ 64] = W.data[strideW * (i + (ti>>5) + 2) + bx + (ti&31)]; - W_[ti+128] = W.data[strideW * (i + (ti>>5) + 4) + bx + (ti&31)]; - W_[ti+192] = W.data[strideW * (i + (ti>>5) + 6) + bx + (ti&31)]; - #if TRANSPOSED_X == 1 - X_[ti ] = X.data[strideX * (i + (ti>>5) + 0) + by + (ti&31)]; - X_[ti+ 64] = X.data[strideX * (i + (ti>>5) + 2) + by + (ti&31)]; - X_[ti+128] = X.data[strideX * (i + (ti>>5) + 4) + by + (ti&31)]; - X_[ti+192] = X.data[strideX * (i + (ti>>5) + 6) + by + (ti&31)]; - #elif SHIFTED_X == 1 - // 8x32 => 32x8 - X_[(ti>>3) + 33*(ti&7) + 0] = X.data[strideX * (by + (ti>>3) + 0) + i + (ti&7) ]; - X_[(ti>>3) + 33*(ti&7) + 8] = X.data[strideX * (by + (ti>>3) + 8) + i + (ti&7) ]; - X_[(ti>>3) + 33*(ti&7) +16] = X.data[strideX * (by + (ti>>3) +16) + i + (ti&7) ]; - X_[(ti>>3) + 33*(ti&7) +24] = X.data[strideX * (by + (ti>>3) +24) + i + (ti&7) ]; - #else - // 8x32 => 32x8 - X_[ti ] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 0]; - X_[ti+ 64] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 2]; - X_[ti+128] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 4]; - X_[ti+192] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 6]; - #endif - - #elif CACHE_DEPTH == 4 - W_[ti ] = W.data[strideW * (i + (ti>>5) + 0) + bx + (ti&31)]; - W_[ti+ 64] = W.data[strideW * (i + (ti>>5) + 2) + bx + (ti&31)]; - #if TRANSPOSED_X == 1 - X_[ti ] = X.data[strideX * (i + (ti>>5) + 0) + by + (ti&31)]; - X_[ti+ 64] = X.data[strideX * (i + (ti>>5) + 2) + by + (ti&31)]; - #elif SHIFTED_X == 1 - // 4x32 => 32x4 - X_[(ti>>2) + 33*(ti&3) + 0] = X.data[strideX * (by + (ti>>2) + 0) + i + (ti&3) ]; - X_[(ti>>2) + 33*(ti&3) +16] = X.data[strideX * (by + (ti>>2) + 16) + i + (ti&3) ]; - #else - // 4x32 => 32x4 - X_[ti ] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 0]; - X_[ti+ 64] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 2]; - #endif - - #elif CACHE_DEPTH == 2 - W_[ti ] = W.data[strideW * (i + (ti>>5) + 0) + bx + (ti&31)]; - #if TRANSPOSED_X == 1 - X_[ti ] = X.data[strideX * (i + (ti>>5) + 0) + by + (ti&31)]; - #elif SHIFTED_X == 1 - // 2x32 => 32x2 - X_[(ti>>1) + 33*(ti&1) + 0] = X.data[strideX * (by + (ti>>1) + 0) + i + (ti&1) ]; - #else - X_[ti ] = X.data[strideX * (by + (ti&31)) + i + (ti>>5) + 0]; - #endif - - #elif CACHE_DEPTH == 1 - if (ti < 32) - { - W_[ti] = W.data[strideW * i + bx + ti]; - #if TRANSPOSED_X == 1 - X_[ti] = X.data[strideX * i + by + ti]; - #else - //X_[ti] = X.Get(by+ti, i); - X_[ti] = X.data[strideX * (by + ti) + i]; - #endif - } - #endif - - GroupMemoryBarrierWithGroupSync(); - - for (int di = 0; di < CACHE_DEPTH; di++) - { - int _32 = 32 + SHIFTED_X; - float4 srcX = float4( - X_[di*_32 + ty*4 + 0], - X_[di*_32 + ty*4 + 1], - X_[di*_32 + ty*4 + 2], - X_[di*_32 + ty*4 + 3]); - float4 srcW = float4( - W_[di*32 + tx*4 + 0], - W_[di*32 + tx*4 + 1], - W_[di*32 + tx*4 + 2], - W_[di*32 + tx*4 + 3]); - - dstA_0.x = ffma(srcX.x, srcW.x, dstA_0.x); - dstA_0.y = ffma(srcX.x, srcW.y, dstA_0.y); - dstA_0.z = ffma(srcX.x, srcW.z, dstA_0.z); - dstA_0.w = ffma(srcX.x, srcW.w, dstA_0.w); - - dstA_1.x = ffma(srcX.y, srcW.x, dstA_1.x); - dstA_1.y = ffma(srcX.y, srcW.y, dstA_1.y); - dstA_1.z = ffma(srcX.y, srcW.z, dstA_1.z); - dstA_1.w = ffma(srcX.y, srcW.w, dstA_1.w); - - dstA_2.x = ffma(srcX.z, srcW.x, dstA_2.x); - dstA_2.y = ffma(srcX.z, srcW.y, dstA_2.y); - dstA_2.z = ffma(srcX.z, srcW.z, dstA_2.z); - dstA_2.w = ffma(srcX.z, srcW.w, dstA_2.w); - - dstA_3.x = ffma(srcX.w, srcW.x, dstA_3.x); - dstA_3.y = ffma(srcX.w, srcW.y, dstA_3.y); - dstA_3.z = ffma(srcX.w, srcW.z, dstA_3.z); - dstA_3.w = ffma(srcX.w, srcW.w, dstA_3.w); - } - - GroupMemoryBarrierWithGroupSync(); - } - - O.SetWithActivation(y+0, x+0, dstA_0.x); - O.SetWithActivation(y+0, x+1, dstA_0.y); - O.SetWithActivation(y+0, x+2, dstA_0.z); - O.SetWithActivation(y+0, x+3, dstA_0.w); - O.SetWithActivation(y+1, x+0, dstA_1.x); - O.SetWithActivation(y+1, x+1, dstA_1.y); - O.SetWithActivation(y+1, x+2, dstA_1.z); - O.SetWithActivation(y+1, x+3, dstA_1.w); - O.SetWithActivation(y+2, x+0, dstA_2.x); - O.SetWithActivation(y+2, x+1, dstA_2.y); - O.SetWithActivation(y+2, x+2, dstA_2.z); - O.SetWithActivation(y+2, x+3, dstA_2.w); - O.SetWithActivation(y+3, x+0, dstA_3.x); - O.SetWithActivation(y+3, x+1, dstA_3.y); - O.SetWithActivation(y+3, x+2, dstA_3.z); - O.SetWithActivation(y+3, x+3, dstA_3.w); - /*for (dx = 0; dx < BLOCK_SIZE; ++dx) - for (dy = 0; dy < BLOCK_SIZE; ++dy) - O.SetWithActivation(y+dy, x+dx, dstA[dy][dx]); - */ - #undef X_ - #undef W_ -} -#undef TRANSPOSED_X -#undef SHIFTED_X -#undef CACHE_DEPTH -#else -[numthreads(8,8,1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - int x = (int)dispatchThreadID.x * BLOCK_SIZE; - int y = (int)dispatchThreadID.y * BLOCK_SIZE; - int n = (int)X.GetFlatWidth(); - - if (x >= (int)O.GetFlatWidth()) return; - if (y >= (int)O.GetFlatHeight()) return; - - float dstA[BLOCK_SIZE][BLOCK_SIZE]; - float srcX[BLOCK_SIZE]; - - int dy, dx; - for (dx = 0; dx < BLOCK_SIZE; ++dx) - for (dy = 0; dy < BLOCK_SIZE; ++dy) - dstA[dy][dx] = B.data[x+dx+B.offset];//B.Get(x+dx); - - for (int i = 0; i < n; ++i) - { - for (dy = 0; dy < BLOCK_SIZE; ++dy) - srcX[dy] = X.data[(y+dy)*X.channels+i];//X.Get(y+dy, i); - - for (dx = 0; dx < BLOCK_SIZE; ++dx) - { - float srcW = W.data[i*W.channels+x+dx];//W.Get(i, x+dx); - for (dy = 0; dy < BLOCK_SIZE; ++dy) - dstA[dy][dx] += srcX[dy] * srcW; - } - } - - for (dx = 0; dx < BLOCK_SIZE; ++dx) - for (dy = 0; dy < BLOCK_SIZE; ++dy) - O.SetWithActivation(y+dy, x+dx, dstA[dy][dx]); -} -#endif -#undef KERNEL_NAME - -#endif // DENSE - -// NOTE: usually this path is used for <16 batches -#undef CACHESIZE -#define CACHESIZE 64 -groupshared float Dense_L1Cached64_X[CACHESIZE]; - -[numthreads(CACHESIZE, 1, 1)] -void Dense_L1Cached64(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - #define X_ Dense_L1Cached64_X - - uint x = CACHESIZE * groupID.x + groupThreadID.x; - uint y = groupID.y; - - uint wIndex = W.Index(0, x); - - float acc = B.FastGet(min(x, O.GetFlatWidth()-1)); - // loop over X columns (flatWidth) and W rows (height) in CACHESIZE steps - for (uint i = 0; i < X.GetFlatWidth(); i += CACHESIZE) - { - // Cache X - // coalescent reads - X_[groupThreadID.x] = X.SafeGet(y, i + groupThreadID.x); - GroupMemoryBarrierWithGroupSync(); - - // X * W - if (i + CACHESIZE <= X.GetFlatWidth()) - { - [unroll] - for (uint di = 0; di < CACHESIZE; ++di) - { - acc = fastfma(X_[di], W.data[wIndex], acc); - wIndex += W.GetFlatWidth(); - } - } - else - { - // handle remainder of the line < CACHESIZE - for (uint di = 0; i + di < X.GetFlatWidth(); ++di) - { - acc = fastfma(X_[di], W.data[wIndex], acc); - wIndex += W.GetFlatWidth(); - } - } - - GroupMemoryBarrierWithGroupSync(); - } - - // needed all threads to load matrix line, x might be out of the bounds for writing - if (x < O.GetFlatWidth()) - O.SetWithActivation(y, x, acc); - - #undef X_ -} - - -#undef TILE_WIDTH -#define TILE_WIDTH NUMTHREAD(16,8,8) -groupshared float DenseTiled_Xcache[TILE_WIDTH][TILE_WIDTH]; -groupshared float DenseTiled_Wcache[TILE_WIDTH][TILE_WIDTH]; -[numthreads(TILE_WIDTH,TILE_WIDTH,1)] -void DenseTiled16x16(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - #define X_ DenseTiled_Xcache - #define W_ DenseTiled_Wcache - - uint tx = groupThreadID.x; - uint ty = groupThreadID.y; - uint x = groupID.x*TILE_WIDTH + tx; - uint y = groupID.y*TILE_WIDTH + ty; - - bool mask = (x < O.GetFlatWidth() && y < O.GetFlatHeight()); - - float v = B.FastGet(x); - for (uint m = 0; m < X.GetFlatWidth()/TILE_WIDTH; ++m) - { - if (mask) - { - X_[ty][tx] = X.Get(y, m*TILE_WIDTH + tx); - W_[ty][tx] = W.Get(m*TILE_WIDTH + ty, x); - } - else - { - X_[ty][tx] = 0; - W_[ty][tx] = 0; - } - - GroupMemoryBarrierWithGroupSync(); - - [unroll] - for (uint i = 0; i < TILE_WIDTH; ++i) - { - v = fastfma(X_[ty][i], W_[i][tx], v); - } - - GroupMemoryBarrierWithGroupSync(); - } - - if (mask) - O.SetWithActivation(y, x, v); - - #undef X_ - #undef W_ -} - -#undef TILE_WIDTH -#define TILE_WIDTH NUMTHREAD(16,8,8) // 32 crashes on MacBookPro/AMD -groupshared float DenseTiled_Xcache32[2*2][TILE_WIDTH][TILE_WIDTH]; -groupshared float DenseTiled_Wcache32[2*2][TILE_WIDTH][TILE_WIDTH]; -[numthreads(TILE_WIDTH,TILE_WIDTH,1)] -void DenseTiled32x32(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID) -{ - //DISPATCH ARGS(O.flatWidth / 2, O.flatHeight / 2, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - #define X_ DenseTiled_Xcache32 - #define W_ DenseTiled_Wcache32 - - uint tx = groupThreadID.x; - uint ty = groupThreadID.y; - uint x = groupID.x*TILE_WIDTH + tx; - uint y = groupID.y*TILE_WIDTH + ty; - - float b0 = B.FastGet(x*2+0); - float b1 = B.FastGet(x*2+1); - float4 v = float4(b0, b1, - b0, b1); - - for (uint m = 0; m < X.GetFlatWidth()/(TILE_WIDTH*2);) - { - float x0 = X.Get(y*2+0, m*TILE_WIDTH*2 + tx*2+0); - float x1 = X.Get(y*2+0, m*TILE_WIDTH*2 + tx*2+1); - float x2 = X.Get(y*2+1, m*TILE_WIDTH*2 + tx*2+0); - float x3 = X.Get(y*2+1, m*TILE_WIDTH*2 + tx*2+1); - - float w0 = W.Get(m*TILE_WIDTH*2 + ty*2+0, x*2+0); - float w1 = W.Get(m*TILE_WIDTH*2 + ty*2+0, x*2+1); - float w2 = W.Get(m*TILE_WIDTH*2 + ty*2+1, x*2+0); - float w3 = W.Get(m*TILE_WIDTH*2 + ty*2+1, x*2+1); - - ++m; - - X_[0][ty][tx] = x0; - X_[1][ty][tx] = x1; - X_[2][ty][tx] = x2; - X_[3][ty][tx] = x3; - - W_[0][ty][tx] = w0; - W_[1][ty][tx] = w1; - W_[2][ty][tx] = w2; - W_[3][ty][tx] = w3; - - GroupMemoryBarrierWithGroupSync(); - - [unroll] - for (uint i = 0; i < TILE_WIDTH; ++i) - { - float4 x = - float4( X_[0][ty][i], - X_[1][ty][i], - X_[2][ty][i], - X_[3][ty][i]); - float4 w = - float4( W_[0][i][tx], - W_[1][i][tx], - W_[2][i][tx], - W_[3][i][tx]); - - v.x = fastfma(w.x, x.x, v.x); - v.y = fastfma(w.y, x.x, v.y); - v.z = fastfma(w.x, x.z, v.z); - v.w = fastfma(w.y, x.z, v.w); - - v.x = fastfma(w.z, x.y, v.x); - v.y = fastfma(w.w, x.y, v.y); - v.z = fastfma(w.z, x.w, v.z); - v.w = fastfma(w.w, x.w, v.w); - } - - GroupMemoryBarrierWithGroupSync(); - } - - O.SetWithActivation(y*2+0, x*2+0, v.x); - O.SetWithActivation(y*2+0, x*2+1, v.y); - O.SetWithActivation(y*2+1, x*2+0, v.z); - O.SetWithActivation(y*2+1, x*2+1, v.w); - - #undef X_ - #undef W_ -} - -#undef TILE_WIDTH -#define TILE_WIDTH NUMTHREAD(16,8,8) -groupshared float DenseTiled_Xcache64[4*4][TILE_WIDTH*TILE_WIDTH]; -groupshared float DenseTiled_Wcache64[4*4][TILE_WIDTH*TILE_WIDTH]; -[numthreads(TILE_WIDTH,TILE_WIDTH,1)] -void DenseTiled64x64(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID) -{ - //DISPATCH ARGS(O.flatWidth / 4, O.flatHeight / 4, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - #define X_ DenseTiled_Xcache64 - #define W_ DenseTiled_Wcache64 - - uint tx = groupThreadID.x; - uint ty = groupThreadID.y; - uint x = groupID.x*TILE_WIDTH + tx; - uint y = groupID.y*TILE_WIDTH + ty; - - float b0 = B.FastGet(x*4+0); - float b1 = B.FastGet(x*4+1); - float b2 = B.FastGet(x*4+2); - float b3 = B.FastGet(x*4+3); - - float4 v0, v1, v2, v3; - v0 = v1 = v2 = v3 = float4(b0, b1, b2, b3); - - for (uint m = 0; m < X.GetFlatWidth()/(TILE_WIDTH*4); ++m) - { - for (uint yy = 0; yy < 4; ++yy) - for (uint xx = 0; xx < 4; ++xx) - { - X_[yy*4+xx][ty*TILE_WIDTH+tx] = X.Get(y*4+yy, (m*TILE_WIDTH + tx)*4+xx); - W_[yy*4+xx][ty*TILE_WIDTH+tx] = W.Get((m*TILE_WIDTH + ty)*4+yy, x*4+xx); - } - - GroupMemoryBarrierWithGroupSync(); - - for (uint i = 0; i < TILE_WIDTH; ++i) - { - [unroll] - for (uint q = 0; q < 4; ++q) - { - float x0 = X_[0*4+q][ty*TILE_WIDTH+i]; - float x1 = X_[1*4+q][ty*TILE_WIDTH+i]; - float x2 = X_[2*4+q][ty*TILE_WIDTH+i]; - float x3 = X_[3*4+q][ty*TILE_WIDTH+i]; - - float w0 = W_[q*4+0][i*TILE_WIDTH+tx]; - float w1 = W_[q*4+1][i*TILE_WIDTH+tx]; - float w2 = W_[q*4+2][i*TILE_WIDTH+tx]; - float w3 = W_[q*4+3][i*TILE_WIDTH+tx]; - - v0.x = fastfma(x0, w0, v0.x); //-- - v1.x = fastfma(x1, w0, v1.x); - v2.x = fastfma(x2, w0, v2.x); - v3.x = fastfma(x3, w0, v3.x); - v0.y = fastfma(x0, w1, v0.y); //-- - v1.y = fastfma(x1, w1, v1.y); - v2.y = fastfma(x2, w1, v2.y); - v3.y = fastfma(x3, w1, v3.y); - v0.z = fastfma(x0, w2, v0.z); //-- - v1.z = fastfma(x1, w2, v1.z); - v2.z = fastfma(x2, w2, v2.z); - v3.z = fastfma(x3, w2, v3.z); - v0.w = fastfma(x0, w3, v0.w); //-- - v1.w = fastfma(x1, w3, v1.w); - v2.w = fastfma(x2, w3, v2.w); - v3.w = fastfma(x3, w3, v3.w); - } - - GroupMemoryBarrierWithGroupSync(); - } - } - - O.SetWithActivation(y*4+0, x*4+0, v0.x); - O.SetWithActivation(y*4+0, x*4+1, v0.y); - O.SetWithActivation(y*4+0, x*4+2, v0.z); - O.SetWithActivation(y*4+0, x*4+3, v0.w); - - O.SetWithActivation(y*4+1, x*4+0, v1.x); - O.SetWithActivation(y*4+1, x*4+1, v1.y); - O.SetWithActivation(y*4+1, x*4+2, v1.z); - O.SetWithActivation(y*4+1, x*4+3, v1.w); - - O.SetWithActivation(y*4+2, x*4+0, v2.x); - O.SetWithActivation(y*4+2, x*4+1, v2.y); - O.SetWithActivation(y*4+2, x*4+2, v2.z); - O.SetWithActivation(y*4+2, x*4+3, v2.w); - - O.SetWithActivation(y*4+3, x*4+0, v3.x); - O.SetWithActivation(y*4+3, x*4+1, v3.y); - O.SetWithActivation(y*4+3, x*4+2, v3.z); - O.SetWithActivation(y*4+3, x*4+3, v3.w); - - #undef X_ - #undef W_ -} - -// reference: "Optimizing the General Matrix Multiplication" GPU - Pro 5 -// https://github.com/strin/gemm-android -// https://github.com/dividiti/gemmbench/tree/master/program/arm-mali-sgemm -// Best configurations one OnePlus 6T: -// K16, numthreads32x2/4/8 // K32 numthreads32x2/4/8 -#undef TILE_WIDTH -#define TILE_WIDTH 16 - -[numthreads(32, 4, 1)] -void Dense_Tilled2x2_Cached(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth / 2, O.flatHeight / 2, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - - uint flatHeightO = O.GetFlatHeight(); - uint flatWidthO = O.GetFlatWidth(); - uint flatWidthX = X.GetFlatWidth(); - - float b0 = B.FastGet(min(x * 2 + 0, flatWidthO-1)); - float b1 = B.FastGet(min(x * 2 + 1, flatWidthO-1)); - float4 v = float4(b0, b1, b0, b1); - - for (uint m = 0; m < (flatWidthX + 4 - 1) / 4; m += TILE_WIDTH) - { - for (uint i = 0; i < TILE_WIDTH; ++i) - { - uint k = m + i; - float4 x0 = float4(X.SafeGet(2 * y + 0, 4 * k + 0), X.SafeGet(2 * y + 0, 4 * k + 1), X.SafeGet(2 * y + 0, 4 * k + 2), X.SafeGet(2 * y + 0, 4 * k + 3)); - float4 x1 = float4(X.SafeGet(2 * y + 1, 4 * k + 0), X.SafeGet(2 * y + 1, 4 * k + 1), X.SafeGet(2 * y + 1, 4 * k + 2), X.SafeGet(2 * y + 1, 4 * k + 3)); - - float4 w0 = float4(W.SafeGet(4 * k + 0, 2 * x + 0), W.SafeGet(4 * k + 1, 2 * x + 0), W.SafeGet(4 * k + 2, 2 * x + 0), W.SafeGet(4 * k + 3, 2 * x + 0)); - float4 w1 = float4(W.SafeGet(4 * k + 0, 2 * x + 1), W.SafeGet(4 * k + 1, 2 * x + 1), W.SafeGet(4 * k + 2, 2 * x + 1), W.SafeGet(4 * k + 3, 2 * x + 1)); - - v += float4(dot(x0, w0), dot(x0, w1), dot(x1, w0), dot(x1, w1)); - } - AllMemoryBarrierWithGroupSync(); - } - - if ((y * 2 + 0 ) < flatHeightO && (x * 2 + 0) < flatWidthO) - O.SetWithActivation(y * 2 + 0, x * 2 + 0, v.x); - if ((y * 2 + 0) < flatHeightO && (x * 2 + 1) < flatWidthO) - O.SetWithActivation(y * 2 + 0, x * 2 + 1, v.y); - if ((y * 2 + 1) < flatHeightO && (x * 2 + 0) < flatWidthO) - O.SetWithActivation(y * 2 + 1, x * 2 + 0, v.z); - if ((y * 2 + 1) < flatHeightO && (x * 2 + 1) < flatWidthO) - O.SetWithActivation(y * 2 + 1, x * 2 + 1, v.w); -} - -#undef TILE_WIDTH -#define TILE_WIDTH 16 - -[numthreads(32, 4, 1)] -void Dense_Tilled4x4_Cached(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth / 4, O.flatHeight / 4, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - - uint flatHeightO = O.GetFlatHeight(); - uint flatWidthO = O.GetFlatWidth(); - uint flatWidthX = X.GetFlatWidth(); - - float b0 = B.FastGet(min(x * 4 + 0, flatWidthO - 1)); - float b1 = B.FastGet(min(x * 4 + 1, flatWidthO - 1)); - float b2 = B.FastGet(min(x * 4 + 2, flatWidthO - 1)); - float b3 = B.FastGet(min(x * 4 + 3, flatWidthO - 1)); - - float4 v0 = float4(b0, b1, b0, b1); - float4 v1 = float4(b2, b3, b2, b3); - float4 v2 = float4(b0, b1, b0, b1); - float4 v3 = float4(b2, b3, b2, b3); - - for (uint m = 0; m < (flatWidthX + 4 - 1) / 4; m += TILE_WIDTH) - { - for (uint i = 0; i < TILE_WIDTH; ++i) - { - uint k = m + i; - float4 x0 = float4(X.SafeGet(4 * y + 0, 4 * k + 0), X.SafeGet(4 * y + 0, 4 * k + 1), X.SafeGet(4 * y + 0, 4 * k + 2), X.SafeGet(4 * y + 0, 4 * k + 3)); - float4 x1 = float4(X.SafeGet(4 * y + 1, 4 * k + 0), X.SafeGet(4 * y + 1, 4 * k + 1), X.SafeGet(4 * y + 1, 4 * k + 2), X.SafeGet(4 * y + 1, 4 * k + 3)); - float4 x2 = float4(X.SafeGet(4 * y + 2, 4 * k + 0), X.SafeGet(4 * y + 2, 4 * k + 1), X.SafeGet(4 * y + 2, 4 * k + 2), X.SafeGet(4 * y + 2, 4 * k + 3)); - float4 x3 = float4(X.SafeGet(4 * y + 3, 4 * k + 0), X.SafeGet(4 * y + 3, 4 * k + 1), X.SafeGet(4 * y + 3, 4 * k + 2), X.SafeGet(4 * y + 3, 4 * k + 3)); - - float4 w0 = float4(W.SafeGet(4 * k + 0, 4 * x + 0), W.SafeGet(4 * k + 1, 4 * x + 0), W.SafeGet(4 * k + 2, 4 * x + 0), W.SafeGet(4 * k + 3, 4 * x + 0)); - float4 w1 = float4(W.SafeGet(4 * k + 0, 4 * x + 1), W.SafeGet(4 * k + 1, 4 * x + 1), W.SafeGet(4 * k + 2, 4 * x + 1), W.SafeGet(4 * k + 3, 4 * x + 1)); - float4 w2 = float4(W.SafeGet(4 * k + 0, 4 * x + 2), W.SafeGet(4 * k + 1, 4 * x + 2), W.SafeGet(4 * k + 2, 4 * x + 2), W.SafeGet(4 * k + 3, 4 * x + 2)); - float4 w3 = float4(W.SafeGet(4 * k + 0, 4 * x + 3), W.SafeGet(4 * k + 1, 4 * x + 3), W.SafeGet(4 * k + 2, 4 * x + 3), W.SafeGet(4 * k + 3, 4 * x + 3)); - - v0 += float4(dot(x0, w0), dot(x0, w1), dot(x1, w0), dot(x1, w1)); - v1 += float4(dot(x0, w2), dot(x0, w3), dot(x1, w2), dot(x1, w3)); - v2 += float4(dot(x2, w0), dot(x2, w1), dot(x3, w0), dot(x3, w1)); - v3 += float4(dot(x2, w2), dot(x2, w3), dot(x3, w2), dot(x3, w3)); - } - AllMemoryBarrierWithGroupSync(); - } - - if ((y * 4 + 0) < flatHeightO && (x * 4 + 0) < flatWidthO) - O.SetWithActivation(y * 4 + 0, x * 4 + 0, v0.x); - if ((y * 4 + 0) < flatHeightO && (x * 4 + 1) < flatWidthO) - O.SetWithActivation(y * 4 + 0, x * 4 + 1, v0.y); - if ((y * 4 + 1) < flatHeightO && (x * 4 + 0) < flatWidthO) - O.SetWithActivation(y * 4 + 1, x * 4 + 0, v0.z); - if ((y * 4 + 1) < flatHeightO && (x * 4 + 1) < flatWidthO) - O.SetWithActivation(y * 4 + 1, x * 4 + 1, v0.w); - - if ((y * 4 + 0) < flatHeightO && (x * 4 + 2) < flatWidthO) - O.SetWithActivation(y * 4 + 0, x * 4 + 2, v1.x); - if ((y * 4 + 0) < flatHeightO && (x * 4 + 3) < flatWidthO) - O.SetWithActivation(y * 4 + 0, x * 4 + 3, v1.y); - if ((y * 4 + 1) < flatHeightO && (x * 4 + 2) < flatWidthO) - O.SetWithActivation(y * 4 + 1, x * 4 + 2, v1.z); - if ((y * 4 + 1) < flatHeightO && (x * 4 + 3) < flatWidthO) - O.SetWithActivation(y * 4 + 1, x * 4 + 3, v1.w); - - if ((y * 4 + 2) < flatHeightO && (x * 4 + 0) < flatWidthO) - O.SetWithActivation(y * 4 + 2, x * 4 + 0, v2.x); - if ((y * 4 + 2) < flatHeightO && (x * 4 + 1) < flatWidthO) - O.SetWithActivation(y * 4 + 2, x * 4 + 1, v2.y); - if ((y * 4 + 3) < flatHeightO && (x * 4 + 0) < flatWidthO) - O.SetWithActivation(y * 4 + 3, x * 4 + 0, v2.z); - if ((y * 4 + 3) < flatHeightO && (x * 4 + 1) < flatWidthO) - O.SetWithActivation(y * 4 + 3, x * 4 + 1, v2.w); - - if ((y * 4 + 2) < flatHeightO && (x * 4 + 2) < flatWidthO) - O.SetWithActivation(y * 4 + 2, x * 4 + 2, v3.x); - if ((y * 4 + 2) < flatHeightO && (x * 4 + 3) < flatWidthO) - O.SetWithActivation(y * 4 + 2, x * 4 + 3, v3.y); - if ((y * 4 + 3) < flatHeightO && (x * 4 + 2) < flatWidthO) - O.SetWithActivation(y * 4 + 3, x * 4 + 2, v3.z); - if ((y * 4 + 3) < flatHeightO && (x * 4 + 3) < flatWidthO) - O.SetWithActivation(y * 4 + 3, x * 4 + 3, v3.w); -} - - -[numthreads(8, 8, 1)] -void MatMulPackB0Bias(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_ARGS2(X, O); - - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - - if (x >= O.GetFlatWidth()) return; - if (y >= O.GetFlatHeight()) return; - - float v = X.Get(y, x); - O.Set(y, x, v); - O.FastSet(O.GetLength() + x, 0.0f); -} - - - -#undef CACHESIZE -#undef LDS_ -#undef X_OFFSET -#undef W_OFFSET -#define CACHESIZE 64 -groupshared float Dense_V_L1Cached64_LDS[CACHESIZE]; - -[numthreads(64, 1, 1)] -void Dense_V_L1Cached64(uint3 groupID : SV_GroupID, uint threadIndex : SV_GroupIndex, uint3 groupThreadID : SV_GroupThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - -#define LDS_ Dense_V_L1Cached64_LDS - - uint ti = threadIndex; - - uint bx = CACHESIZE * groupID.x + ti; - - float dstO = B.FastGet(min(bx, O.GetFlatWidth() - 1)); - - // loop over X columns (flatWidth) and W rows (height) in CACHESIZE steps - for (uint i = 0; i < X.GetFlatWidth(); i += CACHESIZE) - { - // Cache X - // coalescent reads - LDS_[ti] = X.FastGet(min(i + ti, X.GetFlatWidth() - 1)); - - GroupMemoryBarrierWithGroupSync(); - - // X * W - [unroll] - for (uint di = 0; di < CACHESIZE; ++di) - { - dstO = fastfma(LDS_[di], W.SafeGet(bx + (i + di)*W.GetFlatWidth()), dstO); - } - - GroupMemoryBarrierWithGroupSync(); - } - - if(bx < O.GetFlatWidth()) - O.FastSetWithActivation(bx, dstO); - -#undef LDS_ -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense.compute.meta deleted file mode 100644 index 33ad83c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense.compute.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 6b08c0ac202ad41deb8881132b21894c -timeCreated: 1507457322 -licenseType: Pro -ComputeShaderImporter: - currentAPIMask: 196608 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense3.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense3.compute deleted file mode 100644 index 4d13084..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense3.compute +++ /dev/null @@ -1,429 +0,0 @@ -#pragma kernel Dense3_T8x8_R8x8_NHWC BLOCK_SIZE=8 KERNEL_PER_TG=64 CHANNELS_FIRST=0 -#pragma kernel Dense3_T8x8_R8x8_NCHW BLOCK_SIZE=8 KERNEL_PER_TG=64 CHANNELS_FIRST=1 - -#pragma kernel Dense3_T8x16_R4x4_NHWC BLOCK_SIZE=4 KERNEL_PER_TG=32 CHANNELS_FIRST=0 -#pragma kernel Dense3_T8x16_R4x4_NCHW BLOCK_SIZE=4 KERNEL_PER_TG=32 CHANNELS_FIRST=1 - -#pragma kernel Dense3_L1Cached64_NHWC CHANNELS_FIRST=0 -#pragma kernel Dense3_L1Cached64_NCHW CHANNELS_FIRST=1 - - -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL(W) -TENSOR_DECL(B) -TENSOR_DECL(WBK) -TENSOR_DECL_RW(O) - - -float ffma(float a, float b, float c) { return dot(float2(a, c), float2(b, 1)); } //return a*b+c;} //fastfma(a,b,c); } -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SIZE) KERNEL##SIZE##x##SIZE##_NCHW - #define CACHE_NAME_CALL(KERNEL, SIZE, TENSOR) KERNEL##SIZE##x##SIZE##_Cache_##TENSOR##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SIZE) KERNEL##SIZE##x##SIZE##_NHWC - #define CACHE_NAME_CALL(KERNEL, SIZE, TENSOR) KERNEL##SIZE##x##SIZE##_Cache_##TENSOR##_NHWC -#endif -#define FUNC_NAME(KERNEL, SIZE) FUNC_NAME_CALL(KERNEL, SIZE) -#define CACHE_NAME(KERNEL, SIZE, TENSOR) CACHE_NAME_CALL(KERNEL, SIZE, TENSOR) - - -#if BLOCK_SIZE == 8 -#if KERNEL_PER_TG == 64 -#define KERNEL_NAME Dense3_T8x8_R -#define CACHE_WIDTH_W_PAD 1 - -#define CACHE_WIDTH_X 64 -#define CACHE_WIDTH_W (64+CACHE_WIDTH_W_PAD) - -#define CACHE_DEPTH 8 -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, LDS)[1039]; // [(8*9)*(3*8+7)+(7)*8+7+1] // [(CACHE_WIDTH_A + CACHE_WIDTH_B)* BLOCK_SIZE]; -[numthreads(8, 8, 1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE)(uint3 groupID : SV_GroupID, uint threadIndex : SV_GroupIndex, uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint ti = threadIndex; - uint bx = groupID.x * 8 * BLOCK_SIZE; - uint by = groupID.y * 8 * BLOCK_SIZE; - - uint n = X.width; - uint strideX = X.channels; - uint strideW = W.GetFlatWidth(); - uint lengthW = W.GetLength() - 1; - uint dzX = groupID.z * n * strideX; - uint dzO = groupID.z * strideW * strideX; - -#define LDS_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, LDS) -#define X_OFFSET 0 -#define W_OFFSET CACHE_DEPTH*8*BLOCK_SIZE - - float dstO[BLOCK_SIZE*BLOCK_SIZE]; - uint tg_X = 0; - uint tg_W = 0; - - [unroll] for (tg_W = 0; tg_W < BLOCK_SIZE; ++tg_W) - dstO[0*BLOCK_SIZE + tg_W] = B.FastGet(min(B.GetLength()-1, bx + ((ti & 7) << 3) + tg_W)); - - [unroll] for (tg_X = 1; tg_X < BLOCK_SIZE; ++tg_X) - [unroll] for (tg_W = 0; tg_W < BLOCK_SIZE; ++tg_W) - dstO[tg_X*BLOCK_SIZE + tg_W] = dstO[0*BLOCK_SIZE + tg_W]; - - for (uint i = 0; i < n; i += CACHE_DEPTH) - { - #if CHANNELS_FIRST - //LDS_[X_OFFSET + ti + 8 * 8 * [0..7]] = X.FastGet((i + [0..7]) + X.width * (by + ti)); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 0] = X.MaskedGet(((by + ti) < strideX) && ((i + 0) < X.width), dzX + (i + 0) + X.width * (by + ti)); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 1] = X.MaskedGet(((by + ti) < strideX) && ((i + 1) < X.width), dzX + (i + 1) + X.width * (by + ti)); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 2] = X.MaskedGet(((by + ti) < strideX) && ((i + 2) < X.width), dzX + (i + 2) + X.width * (by + ti)); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 3] = X.MaskedGet(((by + ti) < strideX) && ((i + 3) < X.width), dzX + (i + 3) + X.width * (by + ti)); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 4] = X.MaskedGet(((by + ti) < strideX) && ((i + 4) < X.width), dzX + (i + 4) + X.width * (by + ti)); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 5] = X.MaskedGet(((by + ti) < strideX) && ((i + 5) < X.width), dzX + (i + 5) + X.width * (by + ti)); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 6] = X.MaskedGet(((by + ti) < strideX) && ((i + 6) < X.width), dzX + (i + 6) + X.width * (by + ti)); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 7] = X.MaskedGet(((by + ti) < strideX) && ((i + 7) < X.width), dzX + (i + 7) + X.width * (by + ti)); - #else - //LDS_[X_OFFSET + ti + 8 * 8 * [0..7]] = X.FastGet(X.channels * (i + [0..7]) + by + ti); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 0] = X.MaskedGet(((by + ti) < strideX) && ((i + 0) < X.width), dzX + X.channels * (i + 0) + by + ti); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 1] = X.MaskedGet(((by + ti) < strideX) && ((i + 1) < X.width), dzX + X.channels * (i + 1) + by + ti); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 2] = X.MaskedGet(((by + ti) < strideX) && ((i + 2) < X.width), dzX + X.channels * (i + 2) + by + ti); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 3] = X.MaskedGet(((by + ti) < strideX) && ((i + 3) < X.width), dzX + X.channels * (i + 3) + by + ti); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 4] = X.MaskedGet(((by + ti) < strideX) && ((i + 4) < X.width), dzX + X.channels * (i + 4) + by + ti); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 5] = X.MaskedGet(((by + ti) < strideX) && ((i + 5) < X.width), dzX + X.channels * (i + 5) + by + ti); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 6] = X.MaskedGet(((by + ti) < strideX) && ((i + 6) < X.width), dzX + X.channels * (i + 6) + by + ti); - LDS_[X_OFFSET + ti + CACHE_WIDTH_X * 7] = X.MaskedGet(((by + ti) < strideX) && ((i + 7) < X.width), dzX + X.channels * (i + 7) + by + ti); - #endif - - //LDS_[W_OFFSET + ti + writeIndex + (8 * 8 + 1) * [0..7]] = W.FastGet(strideB * (i + [0..7]) + bx + ti); - uint WWriteIndex = (ti & 0x20) >> 5;// (ti > 31) ? CACHE_WIDTH_B_PAD : 0; - - LDS_[W_OFFSET + (ti + WWriteIndex) + 0 * CACHE_WIDTH_W] = W.FastGet(min(strideW * (i + 0) + bx + ti, lengthW)); - LDS_[W_OFFSET + (ti + WWriteIndex) + 1 * CACHE_WIDTH_W] = W.FastGet(min(strideW * (i + 1) + bx + ti, lengthW)); - LDS_[W_OFFSET + (ti + WWriteIndex) + 2 * CACHE_WIDTH_W] = W.FastGet(min(strideW * (i + 2) + bx + ti, lengthW)); - LDS_[W_OFFSET + (ti + WWriteIndex) + 3 * CACHE_WIDTH_W] = W.FastGet(min(strideW * (i + 3) + bx + ti, lengthW)); - LDS_[W_OFFSET + (ti + WWriteIndex) + 4 * CACHE_WIDTH_W] = W.FastGet(min(strideW * (i + 4) + bx + ti, lengthW)); - LDS_[W_OFFSET + (ti + WWriteIndex) + 5 * CACHE_WIDTH_W] = W.FastGet(min(strideW * (i + 5) + bx + ti, lengthW)); - LDS_[W_OFFSET + (ti + WWriteIndex) + 6 * CACHE_WIDTH_W] = W.FastGet(min(strideW * (i + 6) + bx + ti, lengthW)); - LDS_[W_OFFSET + (ti + WWriteIndex) + 7 * CACHE_WIDTH_W] = W.FastGet(min(strideW * (i + 7) + bx + ti, lengthW)); - - GroupMemoryBarrierWithGroupSync(); - - //uint ptrX = X_OFFSET + (ti/8) * 8; - //uint ptrW = W_OFFSET + (ti%8) * 8 + readIndex; - uint ptrX = X_OFFSET + (ti & 0x78); - uint ptrW = ((ti & 7) << 3); - ptrW += (ti & 0x4) >> 2; // ptrW += (ptrW > 31) ? CACHE_WIDTH_W_PAD : 0; - ptrW += W_OFFSET; - - float srcX[BLOCK_SIZE]; - float srcW[BLOCK_SIZE]; - - [unroll] for (uint tg_CacheExecuteIdx = 0; tg_CacheExecuteIdx < CACHE_DEPTH; tg_CacheExecuteIdx++) - { - srcX[0] = LDS_[ptrX | 0]; - srcX[1] = LDS_[ptrX | 1]; - srcX[2] = LDS_[ptrX | 2]; - srcX[3] = LDS_[ptrX | 3]; - srcX[4] = LDS_[ptrX | 4]; - srcX[5] = LDS_[ptrX | 5]; - srcX[6] = LDS_[ptrX | 6]; - srcX[7] = LDS_[ptrX | 7]; - - srcW[0] = LDS_[ptrW + 0]; - srcW[1] = LDS_[ptrW + 1]; - srcW[2] = LDS_[ptrW + 2]; - srcW[3] = LDS_[ptrW + 3]; - srcW[4] = LDS_[ptrW + 4]; - srcW[5] = LDS_[ptrW + 5]; - srcW[6] = LDS_[ptrW + 6]; - srcW[7] = LDS_[ptrW + 7]; - - ptrX += CACHE_WIDTH_X; - ptrW += CACHE_WIDTH_W; - - [unroll] for (tg_X = 0; tg_X < BLOCK_SIZE; ++tg_X) - [unroll] for (tg_W = 0; tg_W < BLOCK_SIZE; ++tg_W) - dstO[tg_X*BLOCK_SIZE + tg_W] = ffma(srcX[tg_X], srcW[tg_W], dstO[tg_X*BLOCK_SIZE + tg_W]); - } - - GroupMemoryBarrierWithGroupSync(); - } - - #if CHANNELS_FIRST - [unroll] for (tg_X = 0; tg_X < BLOCK_SIZE; ++tg_X) - [unroll] for (tg_W = 0; tg_W < BLOCK_SIZE; ++tg_W) - { - uint writeXId = ((bx + 8 * (ti % 8)) + tg_X); - uint writeWId = ((by + 8 * (ti / 8)) + tg_W); - if (writeWId < O.channels && writeXId < O.width) - O.FastSet(dzO + writeXId + O.width * writeWId, dstO[BLOCK_SIZE * tg_W + tg_X]); - } - #else - [unroll] for (uint tg_XOffset = 0; tg_XOffset < BLOCK_SIZE; tg_XOffset += 2) - { - [unroll] for (tg_X = 0; tg_X < 2; ++tg_X) - [unroll] for (tg_W = 0; tg_W < BLOCK_SIZE; ++tg_W) - { - //To avoid bank conflict store in 32 groups [8pixelsGroups,4channelsGroups] each group contain 64 values [8pixels,8kernels] for a total of 2048 values [64pixels,32channels] - uint ldsOffsetOfGroup = 65 * (tg_X*BLOCK_SIZE + tg_W);//64 * ([0,3]*8+[0,7]) = [0,1984] - LDS_[ldsOffsetOfGroup + ti] = dstO[BLOCK_SIZE * tg_W + (tg_XOffset + tg_X)]; - } - - GroupMemoryBarrierWithGroupSync(); - - [unroll] for (tg_X = 0; tg_X < 16; ++tg_X) - { - // (((tg_A % 4) * 8) + (ti % 8)) * CACHE_WIDTH_A - uint ldsOffsetOfGroup = 65 * (((tg_X & 1) << 3) + (ti & 7));//CACHE_WIDTH_A * ([0,3]*8+[0,7]) = [0,1984] - // (ti / 8) * 8 + (tg_A / 4) - uint ldsOffsetInGroup = (ti & 0x78) + (tg_X >> 1);//[0,7]*8+[0,7] = [0,63] - //load from LDS and store to DDR - uint readIndex = ldsOffsetOfGroup + ldsOffsetInGroup;//[0,2047] - // bx + tg_!%4 + (tgA/4)*8 + tg_AOffset - uint writeXId = bx + (tg_X & 1) + ((tg_X >> 1) << 3) + tg_XOffset; - uint writeIndex = dzO + O.channels * writeXId + (by + ti); - if ((by + ti) < O.channels && writeXId < O.width) - O.FastSet(writeIndex, LDS_[readIndex]); - } - } - #endif -} - -#endif -#undef CACHE_DEPTH -#undef KERNEL_NAME -#elif BLOCK_SIZE == 4 -#if KERNEL_PER_TG == 32 - -//TODO optimize -#define KERNEL_NAME Dense3_T8x16_R -#define CACHE_DEPTH 8 - -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, LDS)[16*8*4 + 8*8*4]; // [(8*9)*(3*8+7)+(7)*8+7+1] // [(CACHE_WIDTH_A + CACHE_WIDTH_B)* BLOCK_SIZE]; - -[numthreads(8, 16, 1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE)(uint3 groupID : SV_GroupID, uint threadIndex : SV_GroupIndex) -{ - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - -#define LDS_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, LDS) - - - uint x = 8 * groupID.x + (threadIndex % 8); - uint y = 16 * groupID.y + (threadIndex / 8); - - uint n = X.width; - uint strideX = X.channels; - uint strideW = W.GetFlatWidth(); - uint dzX = groupID.z * n * strideX; - uint dzO = groupID.z * strideW * strideX; - - float dstO[BLOCK_SIZE*BLOCK_SIZE]; - dstO[0 ] = B.FastGet(min(4 * x + 0, strideW - 1)); - dstO[1 ] = B.FastGet(min(4 * x + 0, strideW - 1)); - dstO[2 ] = B.FastGet(min(4 * x + 0, strideW - 1)); - dstO[3 ] = B.FastGet(min(4 * x + 0, strideW - 1)); - dstO[4 ] = B.FastGet(min(4 * x + 1, strideW - 1)); - dstO[5 ] = B.FastGet(min(4 * x + 1, strideW - 1)); - dstO[6 ] = B.FastGet(min(4 * x + 1, strideW - 1)); - dstO[7 ] = B.FastGet(min(4 * x + 1, strideW - 1)); - dstO[8 ] = B.FastGet(min(4 * x + 2, strideW - 1)); - dstO[9 ] = B.FastGet(min(4 * x + 2, strideW - 1)); - dstO[10] = B.FastGet(min(4 * x + 2, strideW - 1)); - dstO[11] = B.FastGet(min(4 * x + 2, strideW - 1)); - dstO[12] = B.FastGet(min(4 * x + 3, strideW - 1)); - dstO[13] = B.FastGet(min(4 * x + 3, strideW - 1)); - dstO[14] = B.FastGet(min(4 * x + 3, strideW - 1)); - dstO[15] = B.FastGet(min(4 * x + 3, strideW - 1)); - - //float acc = B.FastGet(min(x, strideW - 1)); - // loop over X columns (flatWidth) and W rows (height) in CACHESIZE steps - for (uint i = 0; i < n; i += CACHE_DEPTH) - { - // Cache X - // coalescent reads - #if CHANNELS_FIRST - LDS_[(threadIndex / 8) * 8 + (threadIndex % 8) + 16 * 8 * 0] = X.MaskedGet((4 * y + 0 < X.channels) && (i + (threadIndex % 8)) < X.width, dzX + (i + (threadIndex % 8)) + X.width * (4 * y + 0)); - LDS_[(threadIndex / 8) * 8 + (threadIndex % 8) + 16 * 8 * 1] = X.MaskedGet((4 * y + 1 < X.channels) && (i + (threadIndex % 8)) < X.width, dzX + (i + (threadIndex % 8)) + X.width * (4 * y + 1)); - LDS_[(threadIndex / 8) * 8 + (threadIndex % 8) + 16 * 8 * 2] = X.MaskedGet((4 * y + 2 < X.channels) && (i + (threadIndex % 8)) < X.width, dzX + (i + (threadIndex % 8)) + X.width * (4 * y + 2)); - LDS_[(threadIndex / 8) * 8 + (threadIndex % 8) + 16 * 8 * 3] = X.MaskedGet((4 * y + 3 < X.channels) && (i + (threadIndex % 8)) < X.width, dzX + (i + (threadIndex % 8)) + X.width * (4 * y + 3)); - #else - LDS_[(threadIndex / 8)*8 + (threadIndex % 8) + 16*8 * 0] = X.MaskedGet((4 * y + 0 < X.channels) && (i + (threadIndex % 8)) < X.width, dzX + X.channels*(i + (threadIndex % 8)) + 4 * y + 0); - LDS_[(threadIndex / 8)*8 + (threadIndex % 8) + 16*8 * 1] = X.MaskedGet((4 * y + 1 < X.channels) && (i + (threadIndex % 8)) < X.width, dzX + X.channels*(i + (threadIndex % 8)) + 4 * y + 1); - LDS_[(threadIndex / 8)*8 + (threadIndex % 8) + 16*8 * 2] = X.MaskedGet((4 * y + 2 < X.channels) && (i + (threadIndex % 8)) < X.width, dzX + X.channels*(i + (threadIndex % 8)) + 4 * y + 2); - LDS_[(threadIndex / 8)*8 + (threadIndex % 8) + 16*8 * 3] = X.MaskedGet((4 * y + 3 < X.channels) && (i + (threadIndex % 8)) < X.width, dzX + X.channels*(i + (threadIndex % 8)) + 4 * y + 3); - #endif - LDS_[8 * 16 * 4 + ((threadIndex / 8)%8) * 8 + (threadIndex % 8) + 8 * 8 * (2*((threadIndex/8)/8)+0)] = W.MaskedGet((4 * x + 0 < strideW) && (i + ((threadIndex / 8)%8)) < W.GetFlatHeight(), 4 * x + (2*((threadIndex/8)/8)+0) + (i + ((threadIndex / 8)%8))*strideW); - LDS_[8 * 16 * 4 + ((threadIndex / 8)%8) * 8 + (threadIndex % 8) + 8 * 8 * (2*((threadIndex/8)/8)+1)] = W.MaskedGet((4 * x + 1 < strideW) && (i + ((threadIndex / 8)%8)) < W.GetFlatHeight(), 4 * x + (2*((threadIndex/8)/8)+1) + (i + ((threadIndex / 8)%8))*strideW); - - GroupMemoryBarrierWithGroupSync(); - - float srcX[4]; - float srcW[4]; - - // X * W - [unroll] - for (uint di = 0; di < CACHE_DEPTH; ++di) - { - srcX[0] = LDS_[di + (threadIndex / 8) * 8 + 8 * 16 * 0]; - srcX[1] = LDS_[di + (threadIndex / 8) * 8 + 8 * 16 * 1]; - srcX[2] = LDS_[di + (threadIndex / 8) * 8 + 8 * 16 * 2]; - srcX[3] = LDS_[di + (threadIndex / 8) * 8 + 8 * 16 * 3]; - - srcW[0] = LDS_[4 * 8 * 16 + 8 * di + (threadIndex % 8) + 8 * 8 * 0]; - srcW[1] = LDS_[4 * 8 * 16 + 8 * di + (threadIndex % 8) + 8 * 8 * 1]; - srcW[2] = LDS_[4 * 8 * 16 + 8 * di + (threadIndex % 8) + 8 * 8 * 2]; - srcW[3] = LDS_[4 * 8 * 16 + 8 * di + (threadIndex % 8) + 8 * 8 * 3]; - - dstO[0] = fastfma(srcX[0], srcW[0], dstO[0]); - dstO[1] = fastfma(srcX[1], srcW[0], dstO[1]); - dstO[2] = fastfma(srcX[2], srcW[0], dstO[2]); - dstO[3] = fastfma(srcX[3], srcW[0], dstO[3]); - - dstO[4] = fastfma(srcX[0], srcW[1], dstO[4]); - dstO[5] = fastfma(srcX[1], srcW[1], dstO[5]); - dstO[6] = fastfma(srcX[2], srcW[1], dstO[6]); - dstO[7] = fastfma(srcX[3], srcW[1], dstO[7]); - - dstO[8] = fastfma(srcX[0], srcW[2], dstO[8]); - dstO[9 ] = fastfma(srcX[1], srcW[2], dstO[9]); - dstO[10] = fastfma(srcX[2], srcW[2], dstO[10]); - dstO[11] = fastfma(srcX[3], srcW[2], dstO[11]); - - dstO[12] = fastfma(srcX[0], srcW[3], dstO[12]); - dstO[13] = fastfma(srcX[1], srcW[3], dstO[13]); - dstO[14] = fastfma(srcX[2], srcW[3], dstO[14]); - dstO[15] = fastfma(srcX[3], srcW[3], dstO[15]); - } - - GroupMemoryBarrierWithGroupSync(); - } - - #if CHANNELS_FIRST - O.FastSet(dzO + (4 * x + 0) + O.width * (4 * y + 0), dstO[0]); - O.FastSet(dzO + (4 * x + 0) + O.width * (4 * y + 1), dstO[1]); - O.FastSet(dzO + (4 * x + 0) + O.width * (4 * y + 2), dstO[2]); - O.FastSet(dzO + (4 * x + 0) + O.width * (4 * y + 3), dstO[3]); - - O.FastSet(dzO + (4 * x + 1) + O.width * (4 * y + 0), dstO[4]); - O.FastSet(dzO + (4 * x + 1) + O.width * (4 * y + 1), dstO[5]); - O.FastSet(dzO + (4 * x + 1) + O.width * (4 * y + 2), dstO[6]); - O.FastSet(dzO + (4 * x + 1) + O.width * (4 * y + 3), dstO[7]); - - O.FastSet(dzO + (4 * x + 2) + O.width * (4 * y + 0), dstO[8]); - O.FastSet(dzO + (4 * x + 2) + O.width * (4 * y + 1), dstO[9]); - O.FastSet(dzO + (4 * x + 2) + O.width * (4 * y + 2), dstO[10]); - O.FastSet(dzO + (4 * x + 2) + O.width * (4 * y + 3), dstO[11]); - - O.FastSet(dzO + (4 * x + 3) + O.width * (4 * y + 0), dstO[12]); - O.FastSet(dzO + (4 * x + 3) + O.width * (4 * y + 1), dstO[13]); - O.FastSet(dzO + (4 * x + 3) + O.width * (4 * y + 2), dstO[14]); - O.FastSet(dzO + (4 * x + 3) + O.width * (4 * y + 3), dstO[15]); - #else - O.FastSet(dzO + (4 * x + 0)*O.channels + 4 * y + 0, dstO[0]); - O.FastSet(dzO + (4 * x + 0)*O.channels + 4 * y + 1, dstO[1]); - O.FastSet(dzO + (4 * x + 0)*O.channels + 4 * y + 2, dstO[2]); - O.FastSet(dzO + (4 * x + 0)*O.channels + 4 * y + 3, dstO[3]); - - O.FastSet(dzO + (4 * x + 1)*O.channels + 4 * y + 0, dstO[4]); - O.FastSet(dzO + (4 * x + 1)*O.channels + 4 * y + 1, dstO[5]); - O.FastSet(dzO + (4 * x + 1)*O.channels + 4 * y + 2, dstO[6]); - O.FastSet(dzO + (4 * x + 1)*O.channels + 4 * y + 3, dstO[7]); - - O.FastSet(dzO + (4 * x + 2)*O.channels + 4 * y + 0, dstO[8]); - O.FastSet(dzO + (4 * x + 2)*O.channels + 4 * y + 1, dstO[9]); - O.FastSet(dzO + (4 * x + 2)*O.channels + 4 * y + 2, dstO[10]); - O.FastSet(dzO + (4 * x + 2)*O.channels + 4 * y + 3, dstO[11]); - - O.FastSet(dzO + (4 * x + 3)*O.channels + 4 * y + 0, dstO[12]); - O.FastSet(dzO + (4 * x + 3)*O.channels + 4 * y + 1, dstO[13]); - O.FastSet(dzO + (4 * x + 3)*O.channels + 4 * y + 2, dstO[14]); - O.FastSet(dzO + (4 * x + 3)*O.channels + 4 * y + 3, dstO[15]); - #endif -} - - -#endif -#undef CACHE_DEPTH -#undef KERNEL_NAME -#endif - -#undef FUNC_NAME -#undef CACHE_NAME -#undef FUNC_NAME_CALL -#undef CACHE_NAME_CALL - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL) KERNEL##_NCHW - #define CACHE_NAME_CALL(KERNEL, TENSOR) KERNEL##_Cache_##TENSOR##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL) KERNEL##_NHWC - #define CACHE_NAME_CALL(KERNEL, TENSOR) KERNEL##_Cache_##TENSOR##_NHWC -#endif -#define FUNC_NAME(KERNEL) FUNC_NAME_CALL(KERNEL) -#define CACHE_NAME(KERNEL, TENSOR) CACHE_NAME_CALL(KERNEL, TENSOR) - -// NOTE: usually this path is used for <16 batches -#undef CACHESIZE -#undef LDS_ - -#define KERNEL_NAME Dense3_L1Cached64 -#define CACHESIZE 64 - -groupshared float CACHE_NAME(KERNEL_NAME, LDS)[CACHESIZE]; - -[numthreads(64, 1, 1)] -void FUNC_NAME(KERNEL_NAME)(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID, uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - -#define LDS_ CACHE_NAME(KERNEL_NAME, LDS) - - uint x = CACHESIZE * groupID.x + groupThreadID.x; - uint y = groupID.y; - - uint n = X.width; - uint strideX = X.channels; - uint strideW = W.GetFlatWidth(); - uint dzX = groupID.z * n * strideX; - uint dzO = groupID.z * strideW * strideX; - - float acc = B.FastGet(min(x, strideW - 1)); - // loop over X columns (flatWidth) and W rows (height) in CACHESIZE steps - for (uint i = 0; i < n; i += CACHESIZE) - { - // Cache X - // coalescent reads - bool maskX = (y < strideX) && (i + groupThreadID.x) < X.width; - #if CHANNELS_FIRST - LDS_[groupThreadID.x] = X.MaskedGet(maskX, dzX + y * X.width + (i + groupThreadID.x)); - #else - LDS_[groupThreadID.x] = X.MaskedGet(maskX, dzX + (i + groupThreadID.x) * X.channels + y); - #endif - - GroupMemoryBarrierWithGroupSync(); - - // X * W - [unroll] - for (uint di = 0; di < CACHESIZE; ++di) - { - acc = fastfma(LDS_[di], W.MaskedGet(x < strideW && (i+di) < W.GetFlatHeight(), x + (i + di)*strideW), acc); - } - - GroupMemoryBarrierWithGroupSync(); - } - - if ((x < O.width) && (y < O.channels)) - { -#if CHANNELS_FIRST - O.FastSet(dzO + y * O.width + x, acc); -#else - O.FastSet(dzO + x * O.channels + y, acc); -#endif - } - -#undef LDS_ -} -#undef KERNEL_NAME -#undef CACHESIZE diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense3.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense3.compute.meta deleted file mode 100644 index 8dbec1d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Dense3.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b2365b5a091a4ed4aa09dd10bd46f7e1 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 4 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DenseFP16.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DenseFP16.compute deleted file mode 100644 index c501d9d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DenseFP16.compute +++ /dev/null @@ -1,73 +0,0 @@ -#pragma kernel DenseFP16Div2_NHWC CHANNELS_FIRST=0 -#pragma kernel DenseFP16Div2_NCHW CHANNELS_FIRST=1 - -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL(W) -TENSOR_DECL(B) -TENSOR_DECL(WBK) -TENSOR_DECL_RW(O) - -float f16tof32_(uint src) -{ - // Based on Fabian Giesen's public domain half_to_float_fast3 - const uint magic = 113 << 23; - const uint shiftedExp = 0x7c00 << 13; // exponent mask after shift - - // Mask out sign bit - uint o = src & 0x7fff; - if (o) - { - // Move exponent + mantissa to correct bits - o <<= 13; - uint exponent = o & shiftedExp; - if (exponent == 0) - { - // Handle denormal - o = asuint(asfloat(o + magic) - asfloat(magic)); - } - else if (exponent == shiftedExp) // Inf/NaN - o += (255 - 31) << 23; - else - o += (127 - 15) << 23; - } - - // Copy sign bit - o |= (src & 0x8000) << 16; - - return asfloat(o); -} - -float2 Unpack(SharedTensor t, uint y, uint x) -{ - uint v = asuint(t.data[t.Index(y, x) >> 1]); - // TEMPORARY: f16tof32 is broken in GLSL/Metal compiler - // using custom conversion function for now - //return float2(f16tof32(v), f16tof32(v>>16)); - return float2(f16tof32_(v), f16tof32_(v>>16)); -} - -// NOTE: usually this path is used for <16 batches -NUMTHREADS((256,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(DenseFP16Div2)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth/2, O.flatHeight, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - - if (x*2 >= O.GetFlatWidth()) return; - if (y >= O.GetFlatHeight()) return; - - float2 acc = Unpack(B, 0, x*2); - for (uint i = 0; i < X.width; ++i) - { - float2 w = Unpack(W, i, x*2); - acc += X.Get(y, i) * w; - } - - O.Set(y, x*2+0, acc[0]); - O.Set(y, x*2+1, acc[1]); -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DenseFP16.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DenseFP16.compute.meta deleted file mode 100644 index f0111a6..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/DenseFP16.compute.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: cff3cb66e54744fa4888ef91a11ec90c -timeCreated: 1508334838 -licenseType: Pro -ComputeShaderImporter: - currentAPIMask: 196608 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Generic.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Generic.compute deleted file mode 100644 index 8a341d7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Generic.compute +++ /dev/null @@ -1,438 +0,0 @@ -#pragma kernel ScaleBias_NHWC CHANNELS_FIRST=0 -#pragma kernel ScaleBias_NCHW CHANNELS_FIRST=1 -#pragma kernel ScaleBias_CNyx_NHWC CHANNELS_FIRST=0 -//#pragma kernel ScaleBias_CNyx_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel ScaleBias_CNyx2_NHWC CHANNELS_FIRST=0 -//#pragma kernel ScaleBias_CNyx2_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel ScaleBias_Flat_NHWC CHANNELS_FIRST=0 -#pragma kernel ScaleBias_Flat_NCHW CHANNELS_FIRST=1 -#pragma kernel ScaleBias_Loop_NHWC CHANNELS_FIRST=0 -#pragma kernel ScaleBias_Loop_NCHW CHANNELS_FIRST=1 -#pragma kernel InstanceNormTail_CNyx2_NHWC CHANNELS_FIRST=0 -//#pragma kernel InstanceNormTail_CNyx2_NCHW CHANNELS_FIRST=1 //This kernel require NHWC by design -#pragma kernel InstanceNormTail_Flat_NHWC CHANNELS_FIRST=0 -#pragma kernel InstanceNormTail_Flat_NCHW CHANNELS_FIRST=1 -#pragma kernel InstanceNormTail_Loop_NHWC CHANNELS_FIRST=0 -#pragma kernel InstanceNormTail_Loop_NCHW CHANNELS_FIRST=1 -#pragma kernel Upsample2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Upsample2D_NCHW CHANNELS_FIRST=1 -#pragma kernel UpsampleBilinear2D_NHWC CHANNELS_FIRST=0 -#pragma kernel UpsampleBilinear2D_NCHW CHANNELS_FIRST=1 -#pragma kernel UpsampleBilinear2D_2x2_NHWC CHANNELS_FIRST=0 -#pragma kernel UpsampleBilinear2D_2x2_NCHW CHANNELS_FIRST=1 -#pragma kernel Copy_NHWC CHANNELS_FIRST=0 -#pragma kernel Copy_NCHW CHANNELS_FIRST=1 -#pragma kernel ReshapeFromNHWCModel_Flat_NCHW CHANNELS_FIRST=1 -#pragma kernel ReshapeFromNHWCModel_Loop_NCHW CHANNELS_FIRST=1 -#pragma kernel TransposeToChannelFirst - -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL(W) -TENSOR_DECL(S) -TENSOR_DECL(B) -TENSOR_DECL(WBK) -TENSOR_DECL_RW(O) - -uint4 _Pool; -uint4 _Pad; -float _Epsilon; -uint _LoopStride; - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(ScaleBias)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - float bias = B.Get(0, 0, 0, c); - float scale = W.Get(0, 0, 0, c); - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - v = v * scale + bias; - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((16,16,1), (16,8,1), (16,4,1)) -void KERNEL_FUNC(ScaleBias_CNyx)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint c = dispatchThreadID.x; - uint nyx = dispatchThreadID.y; - - uint x = nyx % X.width; - uint ny = nyx / X.width; - uint y = ny % X.height; - uint n = ny / X.height; - - if (c >= X.channels) return; - if (n >= X.batch) return; - - float bias = B.Get(0, 0, 0, c); - float scale = W.Get(0, 0, 0, c); - - float v = X.Get(n, y, x, c); - v = v * scale + bias; - O.Set(n, y, x, c, v); -} - -NUMTHREADS((256,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(ScaleBias_Flat)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.length, 1, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint i = dispatchThreadID.x; - if (i >= O.GetLength()) return; - - uint c = X.GetChannelFromIndex(i); - float bias = B.FastGet(c); - float scale = W.FastGet(c); - - float v = X.FastGet(i); - v = v * scale + bias; - O.FastSet(i, v); -} - -NUMTHREADS((256,1,1), (128,1,1), (64,1,1)) -void KERNEL_FUNC(ScaleBias_Loop)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.length, 1, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint i = dispatchThreadID.x; - uint len = O.GetLength(); - - while (i < len) - { - uint c = X.GetChannelFromIndex(i); - float bias = B.FastGet(c); - float scale = W.FastGet(c); - - float v = X.FastGet(i); - v = v * scale + bias; - O.FastSet(i, v); - - i += _LoopStride; - } -} - -NUMTHREADS((32,4,1), (32,2,1), (16,2,1)) -void KERNEL_FUNC(ScaleBias_CNyx2)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_SHARED2_ARGS4(X, W, B, WBK, O); - - uint c = dispatchThreadID.x; - uint i = dispatchThreadID.y * X.channels + c; - - if (c >= X.channels) return; - if (i >= X.GetLength()) return; - - float bias = B.FastGet(c); - float scale = W.FastGet(c); - - float v = X.FastGet(i); - v = v * scale + bias; - - O.FastSet(i, v); -} - -NUMTHREADS((256, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(InstanceNormTail_Flat)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.length, 1, 1); - TENSOR_ARG(W); - TENSOR_SHARED2_ARGS4(X, S, B, WBK, O); - - uint i = dispatchThreadID.x; - if (i >= O.GetLength()) return; - - uint c = X.GetChannelFromIndex(i); - uint b = i / (X.height * X.width * X.channels); - - float mean = W.Get(b, 0, 0, c); - float variance = W.Get(b, 1, 0, c); - - float scale = S.FastGet(c); - float bias = B.FastGet(c); - - // normalization factor - float invNormFactor = 1 / sqrt(variance + _Epsilon); - - float v = X.FastGet(i); - v = v * invNormFactor - mean * invNormFactor; - v = v * scale + bias; - - O.FastSetWithActivation(i, v); -} - -NUMTHREADS((256, 1, 1), (128, 1, 1), (64, 1, 1)) -void KERNEL_FUNC(InstanceNormTail_Loop)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.length, 1, 1); - TENSOR_ARG(W); - TENSOR_SHARED2_ARGS4(X, S, B, WBK, O); - - uint i = dispatchThreadID.x; - uint len = O.GetLength(); - - while (i < len) - { - uint c = X.GetChannelFromIndex(i); - uint b = i / (X.height * X.width * X.channels); - - float mean = W.Get(b, 0, 0, c); - float variance = W.Get(b, 1, 0, c); - - float scale = S.FastGet(c); - float bias = B.FastGet(c); - - // normalization factor - float invNormFactor = 1 / sqrt(variance + _Epsilon); - - float v = X.FastGet(i); - v = v * invNormFactor - mean * invNormFactor; - v = v * scale + bias; - - O.FastSetWithActivation(i, v); - - i += _LoopStride; - } -} - -NUMTHREADS((32, 4, 1), (32, 2, 1), (16, 2, 1)) -void KERNEL_FUNC(InstanceNormTail_CNyx2)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.batch * O.height * O.width, 1); - TENSOR_ARG(W); - TENSOR_SHARED2_ARGS4(X, S, B, WBK, O); - - uint c = dispatchThreadID.x; - uint i = dispatchThreadID.y * X.channels + c; - uint b = i / (X.height * X.width * X.channels); - - if (c >= X.channels) return; - if (i >= X.GetLength()) return; - - float mean = W.Get(b, 0, 0, c); - float variance = W.Get(b, 1, 0, c); - - float scale = S.FastGet(c); - float bias = B.FastGet(c); - - // normalization factor - float invNormFactor = 1 / sqrt(variance + _Epsilon); - - float v = X.FastGet(i); - v = v * invNormFactor - mean * invNormFactor; - v = v * scale + bias; - - O.FastSetWithActivation(i, v); -} - -[numthreads(4,4,4)] -void KERNEL_FUNC(UpsampleBilinear2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - float2 dstPos = float2(x, y); - float2 srcPos = (dstPos + 0.5) / _Pool.xy - 0.5; - - for (uint n = 0; n < O.batch; ++n) - { - float p00 = X.ClampGet(n, floor(srcPos) + float2(0, 0), c); - float p01 = X.ClampGet(n, floor(srcPos) + float2(0, 1), c); - float p10 = X.ClampGet(n, floor(srcPos) + float2(1, 0), c); - float p11 = X.ClampGet(n, floor(srcPos) + float2(1, 1), c); - - float v = - p00 * (1-frac(srcPos.x)) * (1-frac(srcPos.y)) + - p01 * (1-frac(srcPos.x)) * frac(srcPos.y) + - p10 * frac(srcPos.x) * (1-frac(srcPos.y)) + - p11 * frac(srcPos.x) * frac(srcPos.y); - - O.Set(n, y, x, c, v); - } -} - - -//Only a part of LDS will be used. Size match NUMTHREADS to simplify shader code when storing to LDS. -groupshared float UpsampleBilinear2D_2x2_Cache[8][8]; -NUMTHREADS((8,8,1), (8,8,1), (8,8,1)) -void KERNEL_FUNC(UpsampleBilinear2D_2x2)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID) -{ - //DISPATCH ARGS(O.width, O.height, O.channels); - TENSOR_ARGS2(X, O); - - int2 tg_SrcBasePos = groupID.xy * 4 - 1; - uint c = dispatchThreadID.z; - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - - float2 srcLDSPos = (groupThreadID.xy + 0.5f) / 2.0f - 0.5f; - uint2 srcLDSBasePos = floor(srcLDSPos) + uint2(1,1); - - for (uint n = 0; n < O.batch; ++n) - { - //store inputs to LDS - UpsampleBilinear2D_2x2_Cache[groupThreadID.x][groupThreadID.y] = X.ClampGet(n, tg_SrcBasePos + groupThreadID.xy, c); - GroupMemoryBarrierWithGroupSync(); - - //read inputs from LDS - float p00 = UpsampleBilinear2D_2x2_Cache[srcLDSBasePos.x+0][srcLDSBasePos.y+0]; - float p01 = UpsampleBilinear2D_2x2_Cache[srcLDSBasePos.x+0][srcLDSBasePos.y+1]; - float p10 = UpsampleBilinear2D_2x2_Cache[srcLDSBasePos.x+1][srcLDSBasePos.y+0]; - float p11 = UpsampleBilinear2D_2x2_Cache[srcLDSBasePos.x+1][srcLDSBasePos.y+1]; - - float v = - p00 * (1-frac(srcLDSPos.x)) * (1-frac(srcLDSPos.y)) + - p01 * (1-frac(srcLDSPos.x)) * frac(srcLDSPos.y) + - p10 * frac(srcLDSPos.x) * (1-frac(srcLDSPos.y)) + - p11 * frac(srcLDSPos.x) * frac(srcLDSPos.y); - - if ((c < O.channels) && (x < O.width) && (y < O.height)) - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Upsample2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - // NOTE: dispatched over X (not O) - //DISPATCH ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= X.channels) return; - if (x >= X.width) return; - if (y >= X.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, y, x, c); - - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint oy = y * _Pool.y + dy; - uint ox = x * _Pool.x + dx; - O.Set(n, oy, ox, c, v); - } - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(Copy)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - // NOTE: dispatched over X (not O) - //DISPATCH ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= X.channels) return; if (x >= X.width) return; if (y >= X.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float v = X.Get(n, y, x, c); - O.Set(n + _Pad[0], y + _Pad[1], x + _Pad[2], c + _Pad[3], v); - } -} - -NUMTHREADS((256,1,1), (128,1,1), (64,1,1)) -void ReshapeFromNHWCModel_Flat_NCHW(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; uint x = dispatchThreadID.y; uint y = dispatchThreadID.z; - if (c >= O.channels) return; if (x >= O.width) return; if (y >= O.height) return; - - for (uint n = 0; n < O.batch; ++n) - { - //find the memory offset of target item in HWC format (aka on O) - uint index_NHWC = O.IndexHWC(n,y,x,c); - //from this offset find indices of item in HWC format before the reshape (aka on X) - uint c_NHWC, y_NHWC, x_NHWC, b_NHWC; - X.GetPositionFromIndexNHWC(index_NHWC, b_NHWC, y_NHWC, x_NHWC, c_NHWC); - - //finally copy item - float v = X.Get(b_NHWC, y_NHWC, x_NHWC, c_NHWC); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((64,1,1), (64,1,1), (64,1,1)) -void ReshapeFromNHWCModel_Loop_NCHW(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.length, 1, 1); - TENSOR_ARGS2(X, O); - - uint i = dispatchThreadID.x; - uint len = O.GetLength(); - - while (i < len) - { - uint c, y, x, n; - O.GetPositionFromIndexNCHW(i, n, y, x, c); - - //find the memory offset of target item in HWC format (aka on O) - uint index_NHWC = O.IndexHWC(n,y,x,c); - //from this offset find indices of item in HWC format before the reshape (aka on X) - uint c_NHWC, y_NHWC, x_NHWC, b_NHWC; - X.GetPositionFromIndexNHWC(index_NHWC, b_NHWC, y_NHWC, x_NHWC, c_NHWC); - - //finally copy item - float v = X.Get(b_NHWC, y_NHWC, x_NHWC, c_NHWC); - O.Set(n, y, x, c, v); - - i += _LoopStride; - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void TransposeToChannelFirst(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH_ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2_8D(X, O); - - uint c = dispatchThreadID.x; uint w = dispatchThreadID.y; uint h = dispatchThreadID.z; - if (c >= O.channels) return; if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - float v = X.Get8D(s,r,n,t,d,h,w,c); - uint index = X.IndexSRNCTDHW(s,r,n,t,d,h,w,c); - O.FastSet(index, v); - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Generic.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Generic.compute.meta deleted file mode 100644 index 47cf351..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Generic.compute.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 62f5efacd43b24dd38ead3ce0d80cc34 -timeCreated: 1495527718 -licenseType: Pro -ComputeShaderImporter: - currentAPIMask: 196608 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebug.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebug.cginc deleted file mode 100644 index 13ae39f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebug.cginc +++ /dev/null @@ -1,2 +0,0 @@ -//See DebugUtils.cginc -//#define KERNEL_ASSERTS diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebug.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebug.cginc.meta deleted file mode 100644 index 43630dd..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebug.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 658d58a262863454e8daacc86138ba3f -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugDisabled.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugDisabled.cginc deleted file mode 100644 index 13ae39f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugDisabled.cginc +++ /dev/null @@ -1,2 +0,0 @@ -//See DebugUtils.cginc -//#define KERNEL_ASSERTS diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugDisabled.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugDisabled.cginc.meta deleted file mode 100644 index 2758b41..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugDisabled.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: ae661a10fea2b40fcbe9ef81c40653cc -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugEnabled.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugEnabled.cginc deleted file mode 100644 index e1b5ae4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugEnabled.cginc +++ /dev/null @@ -1,2 +0,0 @@ -//See DebugUtils.cginc -#define KERNEL_ASSERTS diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugEnabled.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugEnabled.cginc.meta deleted file mode 100644 index 4179d1d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/KernelDebugEnabled.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 801f6bbcb80e44fab8b21ca2a87367a8 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/MatMul.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/MatMul.compute deleted file mode 100644 index b39cb32..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/MatMul.compute +++ /dev/null @@ -1,406 +0,0 @@ -#pragma kernel MultidimMatMul_T16x16_R4x4_AR3_BR2_NHWC RANKA=3 RANKB=2 BLOCK_SIZE=4 CHANNELS_FIRST=0 -#pragma kernel MultidimMatMul_T16x16_R4x4_AR3_BR2_NCHW RANKA=3 RANKB=2 BLOCK_SIZE=4 CHANNELS_FIRST=1 - -#pragma kernel MultidimMatMul_T8x8_R8x8_AR3_BR2_NHWC RANKA=3 RANKB=2 BLOCK_SIZE=8 KERNEL_PER_TG=64 CHANNELS_FIRST=0 -#pragma kernel MultidimMatMul_T8x8_R8x8_AR3_BR2_NCHW RANKA=3 RANKB=2 BLOCK_SIZE=8 KERNEL_PER_TG=64 CHANNELS_FIRST=1 - -#pragma kernel MultidimMatMul_L1Cached64_AR3_BR2_NHWC RANKA=3 RANKB=2 CHANNELS_FIRST=0 -#pragma kernel MultidimMatMul_L1Cached64_AR3_BR2_NCHW RANKA=3 RANKB=2 CHANNELS_FIRST=1 - -#include "Tensor.cginc" - -TENSOR_DECL(A) -TENSOR_DECL(B) -//TENSOR_DECL(C) -TENSOR_DECL_RW(O) - - -float ffma(float a, float b, float c) { return dot(float2(a, c), float2(b, 1)); } //return a*b+c;} //fastfma(a,b,c); } -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SIZE, RANK1, RANK2) KERNEL##SIZE##x##SIZE##_AR##RANK1##_BR##RANK2##_NCHW - #define CACHE_NAME_CALL(KERNEL, SIZE, TENSOR) KERNEL##SIZE##x##SIZE##_Cache_##TENSOR##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SIZE, RANK1, RANK2) KERNEL##SIZE##x##SIZE##_AR##RANK1##_BR##RANK2##_NHWC - #define CACHE_NAME_CALL(KERNEL, SIZE, TENSOR) KERNEL##SIZE##x##SIZE##_Cache_##TENSOR##_NHWC -#endif -#define FUNC_NAME(KERNEL, SIZE, RANK1, RANK2) FUNC_NAME_CALL(KERNEL, SIZE, RANK1, RANK2) -#define CACHE_NAME(KERNEL, SIZE, TENSOR) CACHE_NAME_CALL(KERNEL, SIZE, TENSOR) - - -#if BLOCK_SIZE == 8 -#if KERNEL_PER_TG == 64 -#define KERNEL_NAME MultidimMatMul_T8x8_R -#define CACHE_WIDTH_B_PAD 2 - -#define CACHE_WIDTH_A 64 -#define CACHE_WIDTH_B (64+CACHE_WIDTH_B_PAD) - -#define CACHE_DEPTH 8 -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, LDS)[1039]; // [(8*9)*(3*8+7)+(7)*8+7+1] // [(CACHE_WIDTH_A + CACHE_WIDTH_B)* BLOCK_SIZE]; -[numthreads(8, 8, 1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE, RANKA, RANKB)(uint3 groupID : SV_GroupID, uint threadIndex : SV_GroupIndex) -{ - TENSOR_ARGS3(A, B, O); - - uint ti = threadIndex; - uint bx = groupID.x * 8 * BLOCK_SIZE; - uint by = groupID.y * 8 * BLOCK_SIZE; - - uint n = A.width; - uint strideA = A.channels; - uint strideB = B.GetFlatWidth(); - uint lengthB = B.GetLength() - 1; - uint dzA = groupID.z * n * strideA; - uint dzO = groupID.z * strideB * strideA; - -#define LDS_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, LDS) -#define A_OFFSET 0 -#define B_OFFSET CACHE_DEPTH*8*BLOCK_SIZE - - float dstO[BLOCK_SIZE*BLOCK_SIZE]; - uint tg_A = 0; - uint tg_B = 0; - [unroll] for (tg_A = 0; tg_A < BLOCK_SIZE; ++tg_A) - [unroll] for (tg_B = 0; tg_B < BLOCK_SIZE; ++tg_B) - dstO[tg_A*BLOCK_SIZE + tg_B] = 0.0f; - - for (uint i = 0; i < n; i += CACHE_DEPTH) - { - #if CHANNELS_FIRST - //LDS_[A_OFFSET + ti + 8 * 8 * [0..7]] = A.FastGet((i + [0..7]) + A.width * (by + ti)); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 0] = A.MaskedGet(((by + ti) < strideA) && ((i + 0) < A.width), dzA + (i + 0) + A.width * (by + ti)); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 1] = A.MaskedGet(((by + ti) < strideA) && ((i + 1) < A.width), dzA + (i + 1) + A.width * (by + ti)); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 2] = A.MaskedGet(((by + ti) < strideA) && ((i + 2) < A.width), dzA + (i + 2) + A.width * (by + ti)); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 3] = A.MaskedGet(((by + ti) < strideA) && ((i + 3) < A.width), dzA + (i + 3) + A.width * (by + ti)); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 4] = A.MaskedGet(((by + ti) < strideA) && ((i + 4) < A.width), dzA + (i + 4) + A.width * (by + ti)); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 5] = A.MaskedGet(((by + ti) < strideA) && ((i + 5) < A.width), dzA + (i + 5) + A.width * (by + ti)); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 6] = A.MaskedGet(((by + ti) < strideA) && ((i + 6) < A.width), dzA + (i + 6) + A.width * (by + ti)); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 7] = A.MaskedGet(((by + ti) < strideA) && ((i + 7) < A.width), dzA + (i + 7) + A.width * (by + ti)); - #else - //LDS_[A_OFFSET + ti + 8 * 8 * [0..7]] = A.FastGet(A.channels * (i + [0..7]) + by + ti); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 0] = A.MaskedGet(((by + ti) < A.channels) && (i + 0) < A.width, dzA + A.channels * (i + 0) + by + ti); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 1] = A.MaskedGet(((by + ti) < A.channels) && (i + 1) < A.width, dzA + A.channels * (i + 1) + by + ti); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 2] = A.MaskedGet(((by + ti) < A.channels) && (i + 2) < A.width, dzA + A.channels * (i + 2) + by + ti); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 3] = A.MaskedGet(((by + ti) < A.channels) && (i + 3) < A.width, dzA + A.channels * (i + 3) + by + ti); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 4] = A.MaskedGet(((by + ti) < A.channels) && (i + 4) < A.width, dzA + A.channels * (i + 4) + by + ti); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 5] = A.MaskedGet(((by + ti) < A.channels) && (i + 5) < A.width, dzA + A.channels * (i + 5) + by + ti); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 6] = A.MaskedGet(((by + ti) < A.channels) && (i + 6) < A.width, dzA + A.channels * (i + 6) + by + ti); - LDS_[A_OFFSET + ti + CACHE_WIDTH_A * 7] = A.MaskedGet(((by + ti) < A.channels) && (i + 7) < A.width, dzA + A.channels * (i + 7) + by + ti); - #endif - - - //LDS_[B_OFFSET + ti + writeIndex + (8 * 8 + 1) * [0..7]] = B.FastGet(strideB * (i + [0..7]) + bx + ti); - uint BWriteIndex = (ti & 0x20) >> 4;// (ti > 31) ? CACHE_WIDTH_B_PAD : 0; - - LDS_[B_OFFSET + (ti + BWriteIndex) + 0 * CACHE_WIDTH_B] = B.FastGet(min(strideB * (i + 0) + bx + ti, lengthB)); - LDS_[B_OFFSET + (ti + BWriteIndex) + 1 * CACHE_WIDTH_B] = B.FastGet(min(strideB * (i + 1) + bx + ti, lengthB)); - LDS_[B_OFFSET + (ti + BWriteIndex) + 2 * CACHE_WIDTH_B] = B.FastGet(min(strideB * (i + 2) + bx + ti, lengthB)); - LDS_[B_OFFSET + (ti + BWriteIndex) + 3 * CACHE_WIDTH_B] = B.FastGet(min(strideB * (i + 3) + bx + ti, lengthB)); - LDS_[B_OFFSET + (ti + BWriteIndex) + 4 * CACHE_WIDTH_B] = B.FastGet(min(strideB * (i + 4) + bx + ti, lengthB)); - LDS_[B_OFFSET + (ti + BWriteIndex) + 5 * CACHE_WIDTH_B] = B.FastGet(min(strideB * (i + 5) + bx + ti, lengthB)); - LDS_[B_OFFSET + (ti + BWriteIndex) + 6 * CACHE_WIDTH_B] = B.FastGet(min(strideB * (i + 6) + bx + ti, lengthB)); - LDS_[B_OFFSET + (ti + BWriteIndex) + 7 * CACHE_WIDTH_B] = B.FastGet(min(strideB * (i + 7) + bx + ti, lengthB)); - - GroupMemoryBarrierWithGroupSync(); - - //uint ptrA = A_OFFSET + (ti/8) * 8; - //uint ptrB = B_OFFSET + (ti%8) * 8 + readIndex; - uint ptrA = A_OFFSET + (ti & 0x78); - uint ptrB = ((ti & 7) << 3); - ptrB += (ti & 0x4) >> 1; // ptrB += (ptrB > 31) ? CACHE_WIDTH_B_PAD : 0; - ptrB += B_OFFSET; - - float srcA[BLOCK_SIZE]; - float srcB[BLOCK_SIZE]; - - [unroll] for (uint tg_CacheExecuteIdx = 0; tg_CacheExecuteIdx < CACHE_DEPTH; tg_CacheExecuteIdx++) - { - srcA[0] = LDS_[ptrA | 0]; - srcA[1] = LDS_[ptrA | 1]; - srcA[2] = LDS_[ptrA | 2]; - srcA[3] = LDS_[ptrA | 3]; - srcA[4] = LDS_[ptrA | 4]; - srcA[5] = LDS_[ptrA | 5]; - srcA[6] = LDS_[ptrA | 6]; - srcA[7] = LDS_[ptrA | 7]; - - srcB[0] = LDS_[ptrB + 0]; - srcB[1] = LDS_[ptrB + 1]; - srcB[2] = LDS_[ptrB + 2]; - srcB[3] = LDS_[ptrB + 3]; - srcB[4] = LDS_[ptrB + 4]; - srcB[5] = LDS_[ptrB + 5]; - srcB[6] = LDS_[ptrB + 6]; - srcB[7] = LDS_[ptrB + 7]; - - ptrA += CACHE_WIDTH_A; - ptrB += CACHE_WIDTH_B; - - [unroll] for (tg_A = 0; tg_A < BLOCK_SIZE; ++tg_A) - [unroll] for (tg_B = 0; tg_B < BLOCK_SIZE; ++tg_B) - dstO[tg_A*BLOCK_SIZE + tg_B] = ffma(srcA[tg_A], srcB[tg_B], dstO[tg_A*BLOCK_SIZE + tg_B]); - } - - GroupMemoryBarrierWithGroupSync(); - } - - #if CHANNELS_FIRST - [unroll] for (tg_A = 0; tg_A < BLOCK_SIZE; ++tg_A) - [unroll] for (tg_B = 0; tg_B < BLOCK_SIZE; ++tg_B) - { - uint writeAId = ((bx + 8 * (ti % 8)) + tg_A); - uint writeBId = ((by + 8 * (ti / 8)) + tg_B); - if (writeBId < O.channels && writeAId < O.width) - O.FastSet(dzO + writeAId + O.width * writeBId, dstO[BLOCK_SIZE * tg_B + tg_A]); - } - #else - [unroll] for (uint tg_AOffset = 0; tg_AOffset < BLOCK_SIZE; tg_AOffset += 2) - { - [unroll] for (tg_A = 0; tg_A < 2; ++tg_A) - [unroll] for (tg_B = 0; tg_B < BLOCK_SIZE; ++tg_B) - { - //To avoid bank conflict store in 32 groups [8pixelsGroups,4channelsGroups] each group contain 64 values [8pixels,8kernels] for a total of 2048 values [64pixels,32channels] - uint ldsOffsetOfGroup = 65 * (tg_A*BLOCK_SIZE + tg_B);//64 * ([0,3]*8+[0,7]) = [0,1984] - LDS_[ldsOffsetOfGroup + ti] = dstO[BLOCK_SIZE * tg_B + (tg_AOffset + tg_A)]; - } - - GroupMemoryBarrierWithGroupSync(); - - [unroll] for (tg_A = 0; tg_A < 16; ++tg_A) - { - // (((tg_A % 4) * 8) + (ti % 8)) * CACHE_WIDTH_A - uint ldsOffsetOfGroup = 65 * (((tg_A & 1) << 3) + (ti & 7));//CACHE_WIDTH_A * ([0,3]*8+[0,7]) = [0,1984] - // (ti / 8) * 8 + (tg_A / 4) - uint ldsOffsetInGroup = (ti & 0x78) + (tg_A >> 1);//[0,7]*8+[0,7] = [0,63] - //load from LDS and store to DDR - uint readIndex = ldsOffsetOfGroup + ldsOffsetInGroup;//[0,2047] - // bx + tg_!%4 + (tgA/4)*8 + tg_AOffset - uint writeXId = bx + (tg_A & 1) + ((tg_A >> 1) << 3) + tg_AOffset; - uint writeIndex = dzO + O.channels * writeXId + (by + ti); - if ((by+ti) < O.channels && writeXId < O.width) - O.FastSet(writeIndex, LDS_[readIndex]); - } - } - #endif -} - -#endif -#undef CACHE_DEPTH -#undef KERNEL_NAME -#endif -#if BLOCK_SIZE == 4 -#define KERNEL_NAME MultidimMatMul_T16x16_R -#define CACHE_DEPTH 16 -groupshared float CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, LDS)[2*CACHE_DEPTH*16*BLOCK_SIZE]; -[numthreads(16, 16, 1)] -void FUNC_NAME(KERNEL_NAME, BLOCK_SIZE, RANKA, RANKB)(uint3 groupID : SV_GroupID, uint threadIndex : SV_GroupIndex) -{ - TENSOR_ARGS3(A, B, O); - - uint ti = threadIndex; - uint bx = groupID.x * 16 * BLOCK_SIZE; - uint by = groupID.y * 16 * BLOCK_SIZE; - uint n = A.width; - uint strideA = A.channels; - uint strideB = B.GetFlatWidth(); - -#define LDS_ CACHE_NAME(KERNEL_NAME, BLOCK_SIZE, LDS) -#define A_OFFSET 0 -#define B_OFFSET CACHE_DEPTH*16*BLOCK_SIZE - - float dstO[BLOCK_SIZE*BLOCK_SIZE]; - dstO[0 * BLOCK_SIZE + 0] = 0; - dstO[0 * BLOCK_SIZE + 1] = 0; - dstO[0 * BLOCK_SIZE + 2] = 0; - dstO[0 * BLOCK_SIZE + 3] = 0; - dstO[1 * BLOCK_SIZE + 0] = 0; - dstO[1 * BLOCK_SIZE + 1] = 0; - dstO[1 * BLOCK_SIZE + 2] = 0; - dstO[1 * BLOCK_SIZE + 3] = 0; - dstO[2 * BLOCK_SIZE + 0] = 0; - dstO[2 * BLOCK_SIZE + 1] = 0; - dstO[2 * BLOCK_SIZE + 2] = 0; - dstO[2 * BLOCK_SIZE + 3] = 0; - dstO[3 * BLOCK_SIZE + 0] = 0; - dstO[3 * BLOCK_SIZE + 1] = 0; - dstO[3 * BLOCK_SIZE + 2] = 0; - dstO[3 * BLOCK_SIZE + 3] = 0; - - uint tiD64M64 = (ti & 0x3c0); - uint tiMod4M16 = ((ti & 3) << 4); - uint tiMod64 = (ti & 63); - uint tiMod64D4 = (tiMod64 >> 2); - uint tiD64 = (ti >> 6); - - for (uint i = 0; i < n; i += CACHE_DEPTH) - { - //LDS_[B_OFFSET + ((ti/64)*64) + ((ti%4)*16) + ((ti%64)/4) + 16*16*[0..3]] = B.FastGet(strideB * (i + (ti / 64) + 4*[0..3]) + bx + (ti % 64)); - LDS_[B_OFFSET + tiD64M64 + tiMod4M16 + tiMod64D4 + 16 * 16 * 0] = B.FastGet(strideB * (i + tiD64 + 4 * 0) + bx + tiMod64); - LDS_[B_OFFSET + tiD64M64 + tiMod4M16 + tiMod64D4 + 16 * 16 * 1] = B.FastGet(strideB * (i + tiD64 + 4 * 1) + bx + tiMod64); - LDS_[B_OFFSET + tiD64M64 + tiMod4M16 + tiMod64D4 + 16 * 16 * 2] = B.FastGet(strideB * (i + tiD64 + 4 * 2) + bx + tiMod64); - LDS_[B_OFFSET + tiD64M64 + tiMod4M16 + tiMod64D4 + 16 * 16 * 3] = B.FastGet(strideB * (i + tiD64 + 4 * 3) + bx + tiMod64); - - //LDS_[A_OFFSET + ti + 16 * 16 * [0..3]] = A.FastGet((by + (ti % 64)) + strideA * (i + (ti / 64) + 4 * [0..3])); - LDS_[A_OFFSET + ti + 16*16*0] = A.FastGet((by + tiMod64) + strideA * (i + tiD64 + 4*0)); - LDS_[A_OFFSET + ti + 16*16*1] = A.FastGet((by + tiMod64) + strideA * (i + tiD64 + 4*1)); - LDS_[A_OFFSET + ti + 16*16*2] = A.FastGet((by + tiMod64) + strideA * (i + tiD64 + 4*2)); - LDS_[A_OFFSET + ti + 16*16*3] = A.FastGet((by + tiMod64) + strideA * (i + tiD64 + 4*3)); - - GroupMemoryBarrierWithGroupSync(); - - uint ptrA = (ti >> 4) << 2; - uint ptrB = B_OFFSET + (ti&15); - - float srcA[BLOCK_SIZE]; - float srcB[BLOCK_SIZE]; - - for (uint tg_CacheExecuteIdx = 0; tg_CacheExecuteIdx < CACHE_DEPTH; tg_CacheExecuteIdx++) - { - srcA[0] = LDS_[ptrA | 0]; - srcA[1] = LDS_[ptrA | 1]; - srcA[2] = LDS_[ptrA | 2]; - srcA[3] = LDS_[ptrA | 3]; - - srcB[0] = LDS_[ptrB | 0*16]; - srcB[1] = LDS_[ptrB | 1*16]; - srcB[2] = LDS_[ptrB | 2*16]; - srcB[3] = LDS_[ptrB | 3*16]; - - ptrA += 64; - ptrB += 64; - - - dstO[0 * BLOCK_SIZE + 0] = ffma(srcA[0], srcB[0], dstO[0 * BLOCK_SIZE + 0]); - dstO[0 * BLOCK_SIZE + 1] = ffma(srcA[0], srcB[1], dstO[0 * BLOCK_SIZE + 1]); - dstO[0 * BLOCK_SIZE + 2] = ffma(srcA[0], srcB[2], dstO[0 * BLOCK_SIZE + 2]); - dstO[0 * BLOCK_SIZE + 3] = ffma(srcA[0], srcB[3], dstO[0 * BLOCK_SIZE + 3]); - dstO[1 * BLOCK_SIZE + 0] = ffma(srcA[1], srcB[0], dstO[1 * BLOCK_SIZE + 0]); - dstO[1 * BLOCK_SIZE + 1] = ffma(srcA[1], srcB[1], dstO[1 * BLOCK_SIZE + 1]); - dstO[1 * BLOCK_SIZE + 2] = ffma(srcA[1], srcB[2], dstO[1 * BLOCK_SIZE + 2]); - dstO[1 * BLOCK_SIZE + 3] = ffma(srcA[1], srcB[3], dstO[1 * BLOCK_SIZE + 3]); - dstO[2 * BLOCK_SIZE + 0] = ffma(srcA[2], srcB[0], dstO[2 * BLOCK_SIZE + 0]); - dstO[2 * BLOCK_SIZE + 1] = ffma(srcA[2], srcB[1], dstO[2 * BLOCK_SIZE + 1]); - dstO[2 * BLOCK_SIZE + 2] = ffma(srcA[2], srcB[2], dstO[2 * BLOCK_SIZE + 2]); - dstO[2 * BLOCK_SIZE + 3] = ffma(srcA[2], srcB[3], dstO[2 * BLOCK_SIZE + 3]); - dstO[3 * BLOCK_SIZE + 0] = ffma(srcA[3], srcB[0], dstO[3 * BLOCK_SIZE + 0]); - dstO[3 * BLOCK_SIZE + 1] = ffma(srcA[3], srcB[1], dstO[3 * BLOCK_SIZE + 1]); - dstO[3 * BLOCK_SIZE + 2] = ffma(srcA[3], srcB[2], dstO[3 * BLOCK_SIZE + 2]); - dstO[3 * BLOCK_SIZE + 3] = ffma(srcA[3], srcB[3], dstO[3 * BLOCK_SIZE + 3]); - } - - GroupMemoryBarrierWithGroupSync(); - } - - for (uint tg_registerChannelOffset = 0; tg_registerChannelOffset < BLOCK_SIZE; tg_registerChannelOffset += 2) - { - uint tg_kId; - uint tg_pId; - //Store 4 pixels x 2 channels per threads to LDS. - [unroll] for (tg_kId = 0; tg_kId < 2; ++tg_kId) - [unroll] for (tg_pId = 0; tg_pId < BLOCK_SIZE; ++tg_pId) - { - LDS_[64 * ((threadIndex % 16) * 2 + tg_kId) + (threadIndex / 16) * BLOCK_SIZE + tg_pId] = dstO[tg_pId * BLOCK_SIZE + (tg_registerChannelOffset + tg_kId)]; - } - - GroupMemoryBarrierWithGroupSync(); - - //We have a buffers of [64pixels,32channels] floats, each thread will store [1pixels,8channels] so a threadgroup is storing 64 pixels and 4 channels at a time to DDR in a linear fashion. - uint writePixelId = by + (threadIndex % 64); - - [unroll] for (tg_kId = 0; tg_kId < 32; tg_kId += 4) - { - uint readChannelId = tg_kId + (threadIndex / 64); - uint readIndex = 64 * readChannelId + (threadIndex % 64); - uint writeChannelId = bx + (readChannelId % 2) + (readChannelId / 2)*BLOCK_SIZE + tg_registerChannelOffset; - O.FastSet(writeChannelId * strideA + writePixelId, LDS_[readIndex]); - } - - GroupMemoryBarrierWithGroupSync(); - } - -#undef A_ -#undef B_ -} -#undef CACHE_DEPTH -#undef KERNEL_NAME -#endif - -#undef FUNC_NAME -#undef CACHE_NAME -#undef FUNC_NAME_CALL -#undef CACHE_NAME_CALL - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, RANK1, RANK2) KERNEL##_AR##RANK1##_BR##RANK2##_NCHW - #define CACHE_NAME_CALL(KERNEL, TENSOR) KERNEL##_Cache_##TENSOR##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, RANK1, RANK2) KERNEL##_AR##RANK1##_BR##RANK2##_NHWC - #define CACHE_NAME_CALL(KERNEL, TENSOR) KERNEL##_Cache_##TENSOR##_NHWC -#endif -#define FUNC_NAME(KERNEL, RANK1, RANK2) FUNC_NAME_CALL(KERNEL, RANK1, RANK2) -#define CACHE_NAME(KERNEL, TENSOR) CACHE_NAME_CALL(KERNEL, TENSOR) - -// NOTE: usually this path is used for <16 batches -#undef CACHESIZE -#undef LDS_ -#undef X_OFFSET -#undef W_OFFSET - -#define KERNEL_NAME MultidimMatMul_L1Cached64 -#define CACHESIZE 64 - -groupshared float CACHE_NAME(KERNEL_NAME, LDS)[CACHESIZE]; - -[numthreads(64, 1, 1)] -void FUNC_NAME(KERNEL_NAME, RANKA, RANKB)(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_GroupThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_ARGS3(A, B, O); - -#define LDS_ CACHE_NAME(KERNEL_NAME, LDS) - - uint x = CACHESIZE * groupID.x + groupThreadID.x; - uint y = groupID.y; - - uint n = A.width; - uint strideA = A.channels; - uint strideB = B.GetFlatWidth(); - uint dzA = groupID.z * n * strideA; - uint dzO = groupID.z * strideB * strideA; - - float acc = 0.0; - // loop over X columns (flatWidth) and W rows (height) in CACHESIZE steps - for (uint i = 0; i < n; i += CACHESIZE) - { - // Cache X - // coalescent reads - bool maskA = (y < strideA) && (i + groupThreadID.x) < A.width; - #if CHANNELS_FIRST - LDS_[groupThreadID.x] = A.MaskedGet(maskA, dzA + y * A.width + (i + groupThreadID.x)); - #else - LDS_[groupThreadID.x] = A.MaskedGet(maskA, dzA + (i + groupThreadID.x) * A.channels + y); - #endif - - GroupMemoryBarrierWithGroupSync(); - - // X * W - [unroll] - for (uint di = 0; di < CACHESIZE; ++di) - { - acc = fastfma(LDS_[di], B.MaskedGet(x < strideB && (i + di) < B.GetFlatHeight(), x + (i + di)*strideB), acc); - } - - GroupMemoryBarrierWithGroupSync(); - } - - if ((x < O.width) && (y < O.channels)) - { -#if CHANNELS_FIRST - O.FastSet(dzO + y * O.width + x, acc); -#else - O.FastSet(dzO + x * O.channels + y, acc); -#endif - } - -#undef LDS_ -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/MatMul.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/MatMul.compute.meta deleted file mode 100644 index 48d1a04..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/MatMul.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1892719d60b907b4eb8befb172f72544 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 4 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pad.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pad.compute deleted file mode 100644 index 881d047..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pad.compute +++ /dev/null @@ -1,166 +0,0 @@ -#pragma kernel Border2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Border2D_NCHW CHANNELS_FIRST=1 -#pragma kernel Pad2DEdge_NHWC CHANNELS_FIRST=0 -#pragma kernel Pad2DEdge_NCHW CHANNELS_FIRST=1 -#pragma kernel Pad2DReflect_NHWC CHANNELS_FIRST=0 -#pragma kernel Pad2DReflect_NCHW CHANNELS_FIRST=1 -#pragma kernel Pad2DSymmetric_NHWC CHANNELS_FIRST=0 -#pragma kernel Pad2DSymmetric_NCHW CHANNELS_FIRST=1 - -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL(B) -TENSOR_DECL_RW(O) - -uint4 _Pool; -uint4 _Stride; -uint4 _Pad; -float _Beta; - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Border2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - // NOTE: negative "pad" variable crop X tensor - int croppedWidth = _Pool.x; - int croppedHeight = _Pool.y; - int croppedChannels = _Pool.z; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - int readC = c - _Pad.z; - - bool paddedTexel = (readX < 0 || readX >= croppedWidth || readY < 0 || readY >= croppedHeight || readC < 0 || readC >= croppedChannels); - - for (uint n = 0; n < O.batch; ++n) - { - float v = _Beta; - - if (!paddedTexel) - v = X.Get(n, readY, readX, readC); - - O.Set(n, y, x, c, v); - } -} - -void ClampHWToTensorShape(uint2 shape, inout int height, inout int width) -{ - width = clamp(width, 0, (int)shape.x - 1); - height = clamp(height, 0, (int)shape.y - 1); -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Pad2DEdge)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - - //clamp read indices to source - ClampHWToTensorShape(uint2(X.width, X.height), readY, readX); - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, readY, readX, c); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Pad2DReflect)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - - uint2 Xshape = uint2(X.width, X.height); - - int lastXIndex = Xshape.x - 1; - int lastYIndex = Xshape.y - 1; - - //x reflect indexing - readX = (readX < 0) ? -readX : readX; - readX = (readX > lastXIndex) ? lastXIndex - (readX - lastXIndex) : readX; - //y reflect indexing - readY = (readY < 0) ? -readY : readY; - readY = (readY > lastYIndex) ? lastYIndex - (readY - lastYIndex) : readY; - - //clamp read indices to source - ClampHWToTensorShape(Xshape, readY, readX); - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, readY, readX, c); - O.Set(n, y, x, c, v); - } -} - -NUMTHREADS((4, 8, 8), (4, 8, 4), (4, 4, 4)) -void KERNEL_FUNC(Pad2DSymmetric)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - int readX = x - _Pad.x; - int readY = y - _Pad.y; - - uint2 Xshape = uint2(X.width, X.height); - - int lastXIndex = Xshape.x - 1; - int lastYIndex = Xshape.y - 1; - - //x reflect indexing - readX = (readX < 0) ? -readX - 1: readX; - readX = (readX > lastXIndex) ? lastXIndex - (readX - lastXIndex) + 1: readX; - //y reflect indexing - readY = (readY < 0) ? -readY - 1: readY; - readY = (readY > lastYIndex) ? lastYIndex - (readY - lastYIndex) + 1: readY; - - //clamp read indices to source - ClampHWToTensorShape(Xshape, readY, readX); - - for (uint n = 0; n < O.batch; ++n) - { - float v = X.Get(n, readY, readX, c); - O.Set(n, y, x, c, v); - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pad.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pad.compute.meta deleted file mode 100644 index fec92d4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pad.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: cf52068b3397856488e3ec8c94fa02ef -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 4 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders.meta deleted file mode 100644 index 9a5316b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c23201977ed5ef64885111460f407afb -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Activation.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Activation.shader deleted file mode 100644 index 0f90bde..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Activation.shader +++ /dev/null @@ -1,199 +0,0 @@ -Shader "Barracuda/Activation" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile None Relu Selu Abs Neg Ceil Floor Round Reciprocal Swish Tanh Softplus Sigmoid HardSigmoid Relu6 Elu LeakyRelu Exp Log Sqrt Acos Acosh Asin Asinh Atan Atanh Cos Cosh Sin Sinh Tan Pow Clip Erf Sign LogicalNot - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - float signed_pow(float f, float e) - { - // handle negative f - float v = pow(abs(f), e); - float s = (e % 2 == 1) ? - sign(f) : // exponent is odd => sign(f) * pow(abs(f), e) - 1; // exponent is even => pow(abs(f), e) - return v * s; - } - - float erf(float v) - { - // Abramowitz/Stegun approximations - // erf(x) = -erf(-x) - float x = abs(v); - - float p = 0.3275911f; - float a1 = 0.254829592f; float a2 = -0.284496736f; float a3 = 1.421413741f; - float a4 = -1.453152027f; float a5 = 1.061405429f; - - float t = 1.0f / (1.0f + p * x); - float t2 = t * t; - float t3 = t2 * t; - float t4 = t3 * t; - float t5 = t4 * t; - - return sign(v)*(1 - (a1*t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5)*exp(-x * x)); - } - - float _Alpha; - float _Beta; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - float4 v = X.Get4(n, h, w, c4); - - #ifdef Relu - v = 0.5f * (v + abs(v)); - #endif - #ifdef Selu - v = _Beta * (max(v, 0.0f) + min(_Alpha * (exp(v) - 1.0f), 0.0f)); - #endif - #ifdef Abs - v = abs(v); - #endif - #ifdef Neg - v = -v; - #endif - #ifdef Ceil - v = ceil(v); - #endif - #ifdef Floor - v = floor(v); - #endif - #ifdef Round - v = round(v); - #endif - #ifdef Reciprocal - v = 1.0f / v; - #endif - #ifdef Swish - v = v / (1 + exp(-v)); - #endif - #ifdef Tanh - v = tanh(clamp(v,-16.0f,16.0f));//clamp to avoid NaNs for large values. - #endif - #ifdef Softplus - v = log(exp(v) + 1); - #endif - #ifdef Sigmoid - v = 1 / (1 + exp(-v)); - #endif - #ifdef HardSigmoid - v = max(0.0f, min(1.0f, _Alpha * v + _Beta)); - #endif - #ifdef Relu6 - v = min(max(0, v), 6); - #endif - #ifdef Elu - if (v.x <= 0) - v.x = _Alpha * (exp(v.x) - 1); - if (v.y <= 0) - v.y = _Alpha * (exp(v.y) - 1); - if (v.z <= 0) - v.z = _Alpha * (exp(v.z) - 1); - if (v.w <= 0) - v.w = _Alpha * (exp(v.w) - 1); - #endif - #ifdef LeakyRelu - v = max(v, _Alpha * v); - #endif - #ifdef Exp - v = exp(v); - #endif - #ifdef Log - v = log(v); - #endif - #ifdef Sqrt - v = sqrt(v); - #endif - #ifdef Acos - v = acos(v); - #endif - #ifdef Acosh - v = log(v + sqrt(v * v - 1.0f)); - #endif - #ifdef Asin - v = asin(v); - #endif - #ifdef Asinh - v = log(v + sqrt(v*v + 1.0f)); - #endif - #ifdef Atan - v = atan(v); - #endif - #ifdef Atanh - v = 0.5f * log((1.0f + v) / (1.0f - v)); - #endif - #ifdef Cos - v = cos(v); - #endif - #ifdef Cosh - v = 0.5f * (exp(v) + exp(-v)); - #endif - #ifdef Sin - v = sin(v); - #endif - #ifdef Sinh - v = 0.5f * (exp(v) - exp(-v)); - #endif - #ifdef Tan - v = tan(v); - #endif - #ifdef Pow - v.x = signed_pow(v.x, _Alpha); - v.y = signed_pow(v.y, _Alpha); - v.z = signed_pow(v.z, _Alpha); - v.w = signed_pow(v.w, _Alpha); - #endif - #ifdef Clip - v = clamp(v, _Alpha, _Beta); - #endif - #ifdef Erf - v.x = erf(v.x); - v.y = erf(v.y); - v.z = erf(v.z); - v.w = erf(v.w); - #endif - #ifdef Sign - v = sign(v); - #endif - #ifdef LogicalNot - v = (v == 0.0f) ? 1.0f : 0.0f; - #endif - - if (4 * c4 >= X.channels) - v.x = 0.0f; - if (4 * c4 + 1 >= X.channels) - v.y = 0.0f; - if (4 * c4 + 2 >= X.channels) - v.z = 0.0f; - if (4 * c4 + 3 >= X.channels) - v.w = 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Activation.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Activation.shader.meta deleted file mode 100644 index 51798bd..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Activation.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 9626ea9ab0b94e94a95ddbd110d29e78 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/AvgPool2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/AvgPool2D.shader deleted file mode 100644 index 7caf5fc..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/AvgPool2D.shader +++ /dev/null @@ -1,60 +0,0 @@ -Shader "Barracuda/AvgPool2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - uint4 _Pool; - uint4 _Pad; - uint4 _Stride; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - - uint2 leftCorner = _Pad.xy; - uint2 rightCorner = uint2(X.width, X.height) + _Pad.xy; - - float4 acc4 = 0; - float counter = 0; - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint oy = h * _Stride.y + dy; - uint ox = w * _Stride.x + dx; - - bool mask = (oy >= leftCorner.y) && (ox >= leftCorner.x) && (oy < rightCorner.y) && (ox < rightCorner.x); - acc4 += (mask) ? X.Get4(n, min(oy - leftCorner.y, X.height - 1), min(ox - leftCorner.x, X.width - 1), c4) : 0; - counter += (mask) ? 1 : 0; - } - - acc4 /= counter; - - return acc4; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/AvgPool2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/AvgPool2D.shader.meta deleted file mode 100644 index 4eb1f34..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/AvgPool2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 0c6f0ed2e703bff4dae9ffaf72e4d67f -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Border2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Border2D.shader deleted file mode 100644 index 6282dfe..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Border2D.shader +++ /dev/null @@ -1,58 +0,0 @@ -Shader "Barracuda/Border2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pad; - int4 _Pool; - float _Beta; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - int croppedWidth = _Pool.x; - int croppedHeight = _Pool.y; - - int readX = (int)(w) - _Pad.x; - int readY = (int)(h) - _Pad.y; - - float4 v = 0.0f; - if (readX < 0 || readX >= croppedWidth || - readY < 0 || readY >= croppedHeight) - { - v = _Beta; - } - else - { - v = X.Get4(n, readY, readX, c4); - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Border2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Border2D.shader.meta deleted file mode 100644 index fb4dc11..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Border2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: e7bb264f71a76b64ca7a26148d7c18fd -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Broadcast.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Broadcast.shader deleted file mode 100644 index 002df54..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Broadcast.shader +++ /dev/null @@ -1,191 +0,0 @@ -Shader "Barracuda/Broadcast" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile Sub Pow Mul Min Mean Max LogicalXor LogicalOr LogicalAnd LessEqual Less GreaterEqual Greater Equal Div Add - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(B) - - int _IsFirstDispatch; - float _Alpha; - - float signed_pow(float f, float e) - { - // handle negative f - float v = pow(abs(f), e); - float s = (e % 2 == 1) ? - sign(f) : // exponent is odd => sign(f) * pow(abs(f), e) - 1; // exponent is even => pow(abs(f), e) - return v * s; - } - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS3(X, B, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 v = 0.0; - #ifdef Sub - v = X.BroadcastGet4(n, h, w, c4) - B.BroadcastGet4(n, h, w, c4); - #endif - #ifdef Pow - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - v.x = signed_pow(a.x, b.x); - v.y = signed_pow(a.y, b.y); - v.z = signed_pow(a.z, b.z); - v.w = signed_pow(a.w, b.w); - #endif - #ifdef Mul - v = X.BroadcastGet4(n, h, w, c4) * B.BroadcastGet4(n, h, w, c4); - #endif - #ifdef Min - v = min(X.BroadcastGet4(n, h, w, c4), B.BroadcastGet4(n, h, w, c4)); - #endif - #ifdef Mean - float4 a = X.BroadcastGet4(n, h, w, c4); - a *= _IsFirstDispatch ? _Alpha : 1.0f; - float4 b = B.BroadcastGet4(n, h, w, c4) * _Alpha; - v = a + b; - #endif - #ifdef Max - v = max(X.BroadcastGet4(n, h, w, c4), B.BroadcastGet4(n, h, w, c4)); - #endif - #ifdef LogicalXor - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - - a.x = (a.x == 0.0f) ? 0.0f : 1.0f; - a.y = (a.y == 0.0f) ? 0.0f : 1.0f; - a.z = (a.z == 0.0f) ? 0.0f : 1.0f; - a.w = (a.w == 0.0f) ? 0.0f : 1.0f; - - b.x = (b.x == 0.0f) ? 0.0f : 1.0f; - b.y = (b.y == 0.0f) ? 0.0f : 1.0f; - b.z = (b.z == 0.0f) ? 0.0f : 1.0f; - b.w = (b.w == 0.0f) ? 0.0f : 1.0f; - - v = a * (1 - 2 * b) + b; - #endif - #ifdef LogicalOr - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - - a.x = (a.x == 0.0f) ? 0.0f : 1.0f; - a.y = (a.y == 0.0f) ? 0.0f : 1.0f; - a.z = (a.z == 0.0f) ? 0.0f : 1.0f; - a.w = (a.w == 0.0f) ? 0.0f : 1.0f; - - b.x = (b.x == 0.0f) ? 0.0f : 1.0f; - b.y = (b.y == 0.0f) ? 0.0f : 1.0f; - b.z = (b.z == 0.0f) ? 0.0f : 1.0f; - b.w = (b.w == 0.0f) ? 0.0f : 1.0f; - - v = a * (1 - b) + b; - #endif - #ifdef LogicalAnd - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - - a.x = (a.x == 0.0f) ? 0.0f : 1.0f; - a.y = (a.y == 0.0f) ? 0.0f : 1.0f; - a.z = (a.z == 0.0f) ? 0.0f : 1.0f; - a.w = (a.w == 0.0f) ? 0.0f : 1.0f; - - b.x = (b.x == 0.0f) ? 0.0f : 1.0f; - b.y = (b.y == 0.0f) ? 0.0f : 1.0f; - b.z = (b.z == 0.0f) ? 0.0f : 1.0f; - b.w = (b.w == 0.0f) ? 0.0f : 1.0f; - - v.x = a.x * b.x != 0.0 ? 1.0f : 0.0f; - v.y = a.y * b.y != 0.0 ? 1.0f : 0.0f; - v.z = a.z * b.z != 0.0 ? 1.0f : 0.0f; - v.w = a.w * b.w != 0.0 ? 1.0f : 0.0f; - #endif - #ifdef LessEqual - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - - v.x = (a.x <= b.x) ? 1.0f : 0.0f; - v.y = (a.y <= b.y) ? 1.0f : 0.0f; - v.z = (a.z <= b.z) ? 1.0f : 0.0f; - v.w = (a.w <= b.w) ? 1.0f : 0.0f; - #endif - #ifdef Less - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - - v.x = (a.x < b.x) ? 1.0f : 0.0f; - v.y = (a.y < b.y) ? 1.0f : 0.0f; - v.z = (a.z < b.z) ? 1.0f : 0.0f; - v.w = (a.w < b.w) ? 1.0f : 0.0f; - #endif - #ifdef GreaterEqual - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - - v.x = (a.x >= b.x) ? 1.0f : 0.0f; - v.y = (a.y >= b.y) ? 1.0f : 0.0f; - v.z = (a.z >= b.z) ? 1.0f : 0.0f; - v.w = (a.w >= b.w) ? 1.0f : 0.0f; - #endif - #ifdef Greater - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - - v.x = (a.x > b.x) ? 1.0f : 0.0f; - v.y = (a.y > b.y) ? 1.0f : 0.0f; - v.z = (a.z > b.z) ? 1.0f : 0.0f; - v.w = (a.w > b.w) ? 1.0f : 0.0f; - #endif - #ifdef Equal - float4 a = X.BroadcastGet4(n, h, w, c4); - float4 b = B.BroadcastGet4(n, h, w, c4); - - v.x = (a.x == b.x) ? 1.0f : 0.0f; - v.y = (a.y == b.y) ? 1.0f : 0.0f; - v.z = (a.z == b.z) ? 1.0f : 0.0f; - v.w = (a.w == b.w) ? 1.0f : 0.0f; - #endif - #ifdef Div - v = X.BroadcastGet4(n, h, w, c4) / B.BroadcastGet4(n, h, w, c4); - #endif - #ifdef Add - v = X.BroadcastGet4(n, h, w, c4) + B.BroadcastGet4(n, h, w, c4); - #endif - - if (4 * c4 >= O.channels) - v.x = 0.0f; - if (4 * c4 + 1 >= O.channels) - v.y = 0.0f; - if (4 * c4 + 2 >= O.channels) - v.z = 0.0f; - if (4 * c4 + 3 >= O.channels) - v.w = 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Broadcast.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Broadcast.shader.meta deleted file mode 100644 index 83c3249..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Broadcast.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: f868a56d815cb174a9054230194069c9 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BroadcastWhere.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BroadcastWhere.shader deleted file mode 100644 index 9d78332..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BroadcastWhere.shader +++ /dev/null @@ -1,57 +0,0 @@ -Shader "Barracuda/BroadcastWhere" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(W) - TENSOR_DECL(K) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS4(X, W, K, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 cond = (X.BroadcastGet4(n, h, w, c4) != 0.0f); - float4 a = W.BroadcastGet4(n, h, w, c4); - float4 b = K.BroadcastGet4(n, h, w, c4); - - float4 v = 0.0f; - v.x = cond.x ? a.x : b.x; - v.y = cond.y ? a.y : b.y; - v.z = cond.z ? a.z : b.z; - v.w = cond.w ? a.w : b.w; - - if (4 * c4 >= O.channels) - v.x = 0.0f; - if (4 * c4 + 1 >= O.channels) - v.y = 0.0f; - if (4 * c4 + 2 >= O.channels) - v.z = 0.0f; - if (4 * c4 + 3 >= O.channels) - v.w = 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BroadcastWhere.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BroadcastWhere.shader.meta deleted file mode 100644 index 3c77579..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BroadcastWhere.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 8eefed1a026d30840a504a3df988f403 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BufferToTensor.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BufferToTensor.shader deleted file mode 100644 index 180395c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BufferToTensor.shader +++ /dev/null @@ -1,56 +0,0 @@ -Shader "Barracuda/BufferToTensor" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - - uint _InputHeight; - uint _InputWidth; - - Texture2D Xtex2D; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_O(O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 v = 0.0f; - - [unroll] - for (uint cc = 0; cc < 4; cc++) - { - if (c4*4+cc >= O.channels) - break; - - uint index = n * O.height * O.width * O.channels + h * O.width * O.channels + w * O.channels + 4 * c4 + cc; - - uint x = (index) % _InputWidth; - uint y = (index) / _InputWidth; - - v[cc] = Xtex2D.Load(uint3(x, y, 0)).r; - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BufferToTensor.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BufferToTensor.shader.meta deleted file mode 100644 index 0b2e33d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/BufferToTensor.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 97a746f9b7f26334c840552c379b55e0 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/CommonVertexShader.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/CommonVertexShader.cginc deleted file mode 100644 index 18018d4..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/CommonVertexShader.cginc +++ /dev/null @@ -1,22 +0,0 @@ - -#include "UnityCG.cginc" - -struct appdata -{ - float4 vertex : POSITION; - float2 uv : TEXCOORD0; -}; - -struct v2f -{ - float2 uv : TEXCOORD0; - float4 vertex : SV_POSITION; -}; - -v2f vert(appdata v) -{ - v2f o; - o.vertex = UnityObjectToClipPos(v.vertex); - o.uv = v.uv; - return o; -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/CommonVertexShader.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/CommonVertexShader.cginc.meta deleted file mode 100644 index 4ac868c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/CommonVertexShader.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: ccbdf3223f3727b49b4a9b9b1f13b205 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Concat.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Concat.shader deleted file mode 100644 index 193701e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Concat.shader +++ /dev/null @@ -1,71 +0,0 @@ -Shader "Barracuda/Concat" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(OPred) - - uint4 _Pad; - uint _IsFirstPass; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS3(X, OPred, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - uint c; - - float4 v = 0; - - if (_IsFirstPass == 1) - v = 0; - else - v = OPred.Get4(n, h, w, c4); - - if ((n >= _Pad.x && n - _Pad.x < X.batch) && - (h >= _Pad.y && h - _Pad.y < X.height) && - (w >= _Pad.z && w - _Pad.z < X.width)) - { - c = 4 * c4 + 0; - if (c >= _Pad.w && c - _Pad.w < X.channels) - v.x = X.Get(n - _Pad.x, h - _Pad.y, w - _Pad.z, c - _Pad.w); - - c = 4 * c4 + 1; - if (c >= _Pad.w && c - _Pad.w < X.channels) - v.y = X.Get(n - _Pad.x, h - _Pad.y, w - _Pad.z, c - _Pad.w); - - c = 4 * c4 + 2; - if (c >= _Pad.w && c - _Pad.w < X.channels) - v.z = X.Get(n - _Pad.x, h - _Pad.y, w - _Pad.z, c - _Pad.w); - - c = 4 * c4 + 3; - if (c >= _Pad.w && c - _Pad.w < X.channels) - v.w = X.Get(n - _Pad.x, h - _Pad.y, w - _Pad.z, c - _Pad.w); - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Concat.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Concat.shader.meta deleted file mode 100644 index 7386348..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Concat.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: d7d0dd0d75980854698fda3b64064f15 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2D.shader deleted file mode 100644 index c3063d0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2D.shader +++ /dev/null @@ -1,68 +0,0 @@ -Shader "Barracuda/Conv2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(K) - TENSOR_DECL(B) - - uint4 _Pad; - uint4 _Stride; - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_O(O); - TENSOR_ARG(X); - TENSOR_ARG(K); - TENSOR_ARG(B); - - uint n, h, w, k4; - O.GetPositionFromUV(i.uv, n, h, w, k4); - - float4 acc4 = B.Get4(0, 0, 0, k4); - - for (uint c4 = 0; c4 < X.channels4; c4++) - { - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - { - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos = uint2(w, h) * _Stride.xy + uint2(dx, dy); - float4 v = X.SafeGet4(n, pos, c4, _Pad.xy); - - float4 w0 = K.Get4(dy, dx, 4 * c4 + 0, k4); - float4 w1 = K.Get4(dy, dx, 4 * c4 + 1, k4); - float4 w2 = K.Get4(dy, dx, 4 * c4 + 2, k4); - float4 w3 = K.Get4(dy, dx, 4 * c4 + 3, k4); - - acc4.x += dot(v, float4(w0.x, w1.x, w2.x, w3.x)); - acc4.y += dot(v, float4(w0.y, w1.y, w2.y, w3.y)); - acc4.z += dot(v, float4(w0.z, w1.z, w2.z, w3.z)); - acc4.w += dot(v, float4(w0.w, w1.w, w2.w, w3.w)); - } - } - } - - return ApplyFusedActivation(acc4); - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2D.shader.meta deleted file mode 100644 index e8f1980..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: d0c49b9d8f87a034b9a2ccc84df087ef -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2DTrans.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2DTrans.shader deleted file mode 100644 index e242f3d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2DTrans.shader +++ /dev/null @@ -1,86 +0,0 @@ -Shader "Barracuda/Conv2DTrans" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(K) - TENSOR_DECL(B) - - uint4 _Pad; - uint4 _Stride; - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_O(O); - TENSOR_ARG(X); - TENSOR_ARG(K); - TENSOR_ARG(B); - - uint n, h, w, k4; - O.GetPositionFromUV(i.uv, n, h, w, k4); - - uint2 strideMask = _Stride.xy - 1; - - float4 acc4 = B.Get4(0, 0, 0, k4); - - uint strideH = 1; - uint strideW = 1; - - for (uint c4 = 0; c4 < X.channels4; c4++) - { - for (uint dy = 0; dy < K.GetKernelHeight(); dy += strideH) - { - for (uint dx = 0; dx < K.GetKernelWidth(); dx += strideW) - { - uint readX = (w + dx - _Pad.x) / _Stride.x; - uint readY = (h + dy - _Pad.y) / _Stride.y; - - // early out if read input index fall upon leftmost outer zero padding - if ((w + dx) < _Pad.x) continue; - if ((h + dy) < _Pad.y) continue; - - // early out if read input index fall upon rightmost outer zero padding - if (readX >= X.width) continue; - if (readY >= X.height) continue; - - if ((w + dx - _Pad.x) % _Stride.x != 0) continue; - if ((h + dy - _Pad.y) % _Stride.y != 0) continue; - - float4 v = X.Get4(n, readY, readX, c4); - - float4 w0 = K.Get4(K.GetKernelHeight() - 1 - dy, K.GetKernelWidth() - 1 - dx, 4 * c4 + 0, k4); - float4 w1 = K.Get4(K.GetKernelHeight() - 1 - dy, K.GetKernelWidth() - 1 - dx, 4 * c4 + 1, k4); - float4 w2 = K.Get4(K.GetKernelHeight() - 1 - dy, K.GetKernelWidth() - 1 - dx, 4 * c4 + 2, k4); - float4 w3 = K.Get4(K.GetKernelHeight() - 1 - dy, K.GetKernelWidth() - 1 - dx, 4 * c4 + 3, k4); - - acc4.x += dot(v, float4(w0.x, w1.x, w2.x, w3.x)); - acc4.y += dot(v, float4(w0.y, w1.y, w2.y, w3.y)); - acc4.z += dot(v, float4(w0.z, w1.z, w2.z, w3.z)); - acc4.w += dot(v, float4(w0.w, w1.w, w2.w, w3.w)); - } - } - } - - return ApplyFusedActivation(acc4); - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2DTrans.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2DTrans.shader.meta deleted file mode 100644 index 262342a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Conv2DTrans.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 390e5d6f68d6cea4187c73311334cce8 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Copy.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Copy.shader deleted file mode 100644 index 6defd9d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Copy.shader +++ /dev/null @@ -1,54 +0,0 @@ -Shader "Barracuda/Copy" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 v = 0.0f; - [unroll] - for (uint cc = 0; cc < 4; cc++) - { - if (c4 * 4 + cc >= O.channels) - break; - - uint index = n * O.height * O.width * O.channels + h * O.width * O.channels + w * O.channels + (4 * c4 + cc); - - uint cX = index % X.channels; - uint wX = (index / X.channels) % X.width; - uint hX = (index / X.channels / X.width) % X.height; - uint nX = (index / X.channels / X.width / X.height); - - v[cc] = X.Get(nX, hX, wX, cX); - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Copy.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Copy.shader.meta deleted file mode 100644 index 7c6fcea..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Copy.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: c72b5e72f9c141943ab0c51ddbc37622 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense.shader deleted file mode 100644 index 1c3517c..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense.shader +++ /dev/null @@ -1,56 +0,0 @@ -Shader "Barracuda/Dense" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(W) - TENSOR_DECL(B) - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_O(O); - TENSOR_ARG(X); - TENSOR_ARG(W); - TENSOR_ARG(B); - - uint n, h, w, k4; - O.GetPositionFromUV(i.uv, n, h, w, k4); - - float4 acc4 = B.Get4(0, 0, 0, k4); - for (uint c4 = 0; c4 < X.channels4; c4++) - { - float4 v = X.Get4(n, 0, 0, c4); - float4 w0 = W.Get4(4 * c4 + 0, 0, 0, k4); - float4 w1 = W.Get4(4 * c4 + 1, 0, 0, k4); - float4 w2 = W.Get4(4 * c4 + 2, 0, 0, k4); - float4 w3 = W.Get4(4 * c4 + 3, 0, 0, k4); - - acc4.x += dot(v, float4(w0.x, w1.x, w2.x, w3.x)); - acc4.y += dot(v, float4(w0.y, w1.y, w2.y, w3.y)); - acc4.z += dot(v, float4(w0.z, w1.z, w2.z, w3.z)); - acc4.w += dot(v, float4(w0.w, w1.w, w2.w, w3.w)); - } - - return ApplyFusedActivation(acc4); - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense.shader.meta deleted file mode 100644 index 1fb0bfa..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 5c7b7cbbc9eafbe419d22e9485aacb45 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense3.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense3.shader deleted file mode 100644 index bf7efde..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense3.shader +++ /dev/null @@ -1,47 +0,0 @@ -Shader "Barracuda/Dense3" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(W) - TENSOR_DECL(B) - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_O(O); - TENSOR_ARG(X); - TENSOR_ARG(W); - TENSOR_ARG(B); - - uint n, h, w, k4; - O.GetPositionFromUV(i.uv, n, h, w, k4); - - float4 acc4 = B.Get(0, 0, 0, w); - for (uint j = 0; j < X.width; ++j) - { - acc4 += X.Get4(n, 0, j, k4) * W.Get(j, 0, 0, w); - } - - return ApplyFusedActivation(acc4); - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense3.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense3.shader.meta deleted file mode 100644 index 86ab6eb..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Dense3.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: d15d796a4efe4b0429e2d4c08f53e10a -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_CRD.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_CRD.shader deleted file mode 100644 index 2195d64..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_CRD.shader +++ /dev/null @@ -1,56 +0,0 @@ -Shader "Barracuda/DepthToSpace_CRD" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - uint4 _Pool; - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, y, x, c4; - O.GetPositionFromUV(i.uv, n, y, x, c4); - - uint bsX = _Pool.x; - uint bsY = _Pool.y; - - float4 v = 0; - [unroll] - for (uint cc = 0; cc < 4; cc++) - { - uint iy = y / bsY; - uint by = y % bsY; - uint ix = x / bsX; - uint bx = x % bsX; - - uint cRead = ((4 * c4 + cc) * bsX * bsY) + (by * bsX) + bx; - - if(cRead < X.channels) - v[cc] = X.Get(n, iy, ix, cRead); - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_CRD.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_CRD.shader.meta deleted file mode 100644 index 0af51a9..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_CRD.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 23341d4f86653834a9d49a4bd2eed862 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_DCR.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_DCR.shader deleted file mode 100644 index 0741ae0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_DCR.shader +++ /dev/null @@ -1,56 +0,0 @@ -Shader "Barracuda/DepthToSpace_DCR" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - uint4 _Pool; - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, y, x, c4; - O.GetPositionFromUV(i.uv, n, y, x, c4); - - uint bsX = _Pool.x; - uint bsY = _Pool.y; - - float4 v = 0; - [unroll] - for (uint cc = 0; cc < 4; cc++) - { - uint iy = y / bsY; - uint by = y % bsY; - uint ix = x / bsX; - uint bx = x % bsX; - - uint cRead = (by * bsX * O.channels) + (bx * O.channels) + (4 * c4 + cc); - - if (cRead < X.channels) - v[cc] = X.Get(n, iy, ix, cRead); - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_DCR.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_DCR.shader.meta deleted file mode 100644 index 514a4a7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthToSpace_DCR.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 443f2de71dcda184581a1e90c9bb9ea2 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthwiseConv2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthwiseConv2D.shader deleted file mode 100644 index f4493ee..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthwiseConv2D.shader +++ /dev/null @@ -1,56 +0,0 @@ -Shader "Barracuda/DepthwiseConv2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(K) - TENSOR_DECL(B) - - uint4 _Pad; - uint4 _Stride; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS4(X, K, B, O); - - uint n, h, w, k4; - O.GetPositionFromUV(i.uv, n, h, w, k4); - - float4 acc4 = B.Get4(0, 0, 0, k4); - - for (uint dy = 0; dy < K.GetKernelHeight(); ++dy) - { - for (uint dx = 0; dx < K.GetKernelWidth(); ++dx) - { - uint2 pos = uint2(w, h) * _Stride.xy + uint2(dx, dy); - float4 v = X.SafeGet4(n, pos, k4, _Pad.xy); - - float4 w0 = K.Get4(dy, dx, 0, k4); - - acc4 += v * w0; - } - } - - return ApplyFusedActivation(acc4); - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthwiseConv2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthwiseConv2D.shader.meta deleted file mode 100644 index a3bf646..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/DepthwiseConv2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 9bb27abd97d768e4a89ca0ed9f2bd88a -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Gather.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Gather.shader deleted file mode 100644 index cb7584d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Gather.shader +++ /dev/null @@ -1,66 +0,0 @@ -Shader "Barracuda/Gather" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile Input1D Input2D - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(K) - - uint _Axis; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS3(X, K, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 v = 0.0f; - if (_Axis == 0) - v = X.Get4((uint)K.Get(n,0,0,0), h, w, c4); - else if (_Axis == 1) - v = X.Get4(n, (uint)K.Get(h,0,0,0), w, c4); - else if (_Axis == 2) - v = X.Get4(n, h, (uint)K.Get(w,0,0,0), c4); - else if (_Axis == 3) - { - v.x = X.Get(n, h, w, (uint)K.Get(4 * c4 + 0, 0, 0, 0)); - v.y = X.Get(n, h, w, (uint)K.Get(4 * c4 + 1, 0, 0, 0)); - v.z = X.Get(n, h, w, (uint)K.Get(4 * c4 + 2, 0, 0, 0)); - v.w = X.Get(n, h, w, (uint)K.Get(4 * c4 + 3, 0, 0, 0)); - } - - if (4 * c4 >= O.channels) - v.x = 0.0f; - if (4 * c4 + 1 >= O.channels) - v.y = 0.0f; - if (4 * c4 + 2 >= O.channels) - v.z = 0.0f; - if (4 * c4 + 3 >= O.channels) - v.w = 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Gather.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Gather.shader.meta deleted file mode 100644 index f6edac2..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Gather.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: c27dc5cba8ccd9d408583df574b77160 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgPool2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgPool2D.shader deleted file mode 100644 index 0ceb859..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgPool2D.shader +++ /dev/null @@ -1,43 +0,0 @@ -Shader "Barracuda/GlobalAvgPool2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 acc4 = 0; - for (uint y = 0; y < X.height; ++y) - for (uint x = 0; x < X.width; ++x) - acc4 += X.Get4(n, y, x, c4); - - acc4 /= (X.height * X.width); - - return acc4; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgPool2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgPool2D.shader.meta deleted file mode 100644 index 5877017..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgPool2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: ec56be125cfe2de4e8664b6e4fd7c00b -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgVariancePool2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgVariancePool2D.shader deleted file mode 100644 index 0eabffe..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgVariancePool2D.shader +++ /dev/null @@ -1,57 +0,0 @@ -Shader "Barracuda/GlobalAvgVariancePool2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float mean = 0; - float mean2 = 0; - for (uint y = 0; y < X.height; ++y) - { - for (uint x = 0; x < X.width; ++x) - { - float4 v = X.Get4(n, y, x, c4); - mean += v; - mean2 += v * v; - } - } - - mean /= (X.height * X.width); - mean2 /= (X.height * X.width); - - if (h == 0) - return mean; - else if (h == 1) - return mean2; - else - return 0; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgVariancePool2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgVariancePool2D.shader.meta deleted file mode 100644 index 8912715..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalAvgVariancePool2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 750dc44b5188a0047915538013c7fafa -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalMaxPool2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalMaxPool2D.shader deleted file mode 100644 index daa120b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalMaxPool2D.shader +++ /dev/null @@ -1,47 +0,0 @@ -Shader "Barracuda/GlobalMaxPool2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 maxV4 = -FLT_MAX; - for (uint y = 0; y < X.height; ++y) - for (uint x = 0; x < X.width; ++x) - { - float4 v = X.Get4(n, y, x, c4); - maxV4.x = max(v.x, maxV4.x); - maxV4.y = max(v.y, maxV4.y); - maxV4.z = max(v.z, maxV4.z); - maxV4.w = max(v.w, maxV4.w); - } - - return maxV4; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalMaxPool2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalMaxPool2D.shader.meta deleted file mode 100644 index 832e0e3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/GlobalMaxPool2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: ef5a86e12013d444fb3b1abdd0f52de4 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/HardSigmoid.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/HardSigmoid.shader deleted file mode 100644 index 6c0fd91..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/HardSigmoid.shader +++ /dev/null @@ -1,54 +0,0 @@ -Shader "Barracuda/Sigmoid" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - float _Alpha; - float _Beta; - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - float4 v = X.Get4(n, h, w, c4); - - v.x = max(0.0f, min(1.0f, _Alpha * v.x + _Beta)); - v.y = max(0.0f, min(1.0f, _Alpha * v.y + _Beta)); - v.z = max(0.0f, min(1.0f, _Alpha * v.z + _Beta)); - v.w = max(0.0f, min(1.0f, _Alpha * v.w + _Beta)); - - if (4 * c4 >= X.channels) - v.x = 0.0f; - if (4 * c4 + 1 >= X.channels) - v.y = 0.0f; - if (4 * c4 + 2 >= X.channels) - v.z = 0.0f; - if (4 * c4 + 3 >= X.channels) - v.w = 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/HardSigmoid.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/HardSigmoid.shader.meta deleted file mode 100644 index 81e2006..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/HardSigmoid.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 2791212921327144d8248dfe5f9b79da -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/InstanceNorm.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/InstanceNorm.shader deleted file mode 100644 index 9424423..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/InstanceNorm.shader +++ /dev/null @@ -1,61 +0,0 @@ -Shader "Barracuda/InstanceNorm" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(W) - TENSOR_DECL(B) - - float _Epsilon; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS4(X, W, B, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 gamma = W.Get4(0, 0, 0, c4); - float4 beta = B.Get4(0, 0, 0, c4); - - float4 alpha = X.Get4(n, 0, 0, c4); - - uint y, x; - - float4 sum = 0, sumSq = 0; - for (y = 0; y < X.height; ++y) - for (x = 0; x < X.width; ++x) - { - float4 delta = X.Get4(n, y, x, c4) - alpha; - sum += delta; - sumSq += delta * delta; - } - - float4 mean = alpha + sum / (X.width * X.height); - float4 var = (sumSq - (sum * sum) / (X.width * X.height)) / (X.width * X.height); - - float4 v = X.Get4(n, h, w, c4); - v = gamma * (v - mean) / sqrt(var + _Epsilon) + beta; - return ApplyFusedActivation(v); - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/InstanceNorm.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/InstanceNorm.shader.meta deleted file mode 100644 index afe1359..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/InstanceNorm.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 250538bd780e0484c82352bcefb68f4d -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LRN.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LRN.shader deleted file mode 100644 index 1b71067..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LRN.shader +++ /dev/null @@ -1,74 +0,0 @@ -Shader "Barracuda/LRN" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - float _Alpha; - float _Beta; - float _Epsilon; - uint _Axis; - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - float signed_pow(float f, float e) - { - // handle negative f - float v = pow(abs(f), e); - float s = (e % 2 == 1) ? - sign(f): // exponent is odd => sign(f) * pow(abs(f), e) - 1; // exponent is even => pow(abs(f), e) - return v * s; - } - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float bias = _Epsilon; - float sizef = (float)_Axis; - - float regionCenter = (sizef - 1.0f) / 2.0f; - - float4 v = X.Get4(n, h, w, c4); - [unroll] - for (uint cc = 0; cc < 4; cc++) - { - uint c = 4 * c4 + cc; - uint regionStart = max(0, c - (uint)floor(regionCenter)); - uint regionEnd = min(X.channels, c + (uint)ceil(regionCenter) + 1); - float sumOfSquared = 0.0f; - - for (uint ci = regionStart; ci < regionEnd; ++ci) - { - float regionValue = X.Get(n, h, w, ci); - sumOfSquared += regionValue * regionValue; - } - - v[cc] /= signed_pow(bias + _Alpha * sumOfSquared / sizef, _Beta); - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LRN.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LRN.shader.meta deleted file mode 100644 index 2597ec0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LRN.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 5038389ba3277cf43b4844f5520eb231 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LogSoftmax.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LogSoftmax.shader deleted file mode 100644 index cbaa5f0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LogSoftmax.shader +++ /dev/null @@ -1,124 +0,0 @@ -Shader "Barracuda/LogSoftmax" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile ReduceN ReduceH ReduceW ReduceC - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - uint _Axis; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 maxV = -FLT_MAX; - - uint j = 0; - #ifdef ReduceN - for (j = 0; j < X.batch; j++) - #endif - #ifdef ReduceH - for (j = 0; j < X.height; j++) - #endif - #ifdef ReduceW - for (j = 0; j < X.width; j++) - #endif - #ifdef ReduceC - for (j = 0; j < X.channels4; j++) - #endif - { - float4 v = 0.0f; - #ifdef ReduceN - v = X.SafeGet4(j, uint2(w, h), c4, uint2(0, 0), -FLT_MAX); - #endif - #ifdef ReduceH - v = X.SafeGet4(n, uint2(w, j), c4, uint2(0, 0), -FLT_MAX); - #endif - #ifdef ReduceW - v = X.SafeGet4(n, uint2(j, h), c4, uint2(0, 0), -FLT_MAX); - #endif - #ifdef ReduceC - v = X.SafeGet4(n, uint2(w, h), j, uint2(0, 0), -FLT_MAX); - #endif - - maxV = max(maxV, v); - } - #ifdef ReduceC - maxV = max(maxV.x, max(maxV.y, max(maxV.z, maxV.w))); - #endif - - float4 acc = 0.0f; - #ifdef ReduceN - for (j = 0; j < X.batch; j++) - #endif - #ifdef ReduceH - for (j = 0; j < X.height; j++) - #endif - #ifdef ReduceW - for (j = 0; j < X.width; j++) - #endif - #ifdef ReduceC - for (j = 0; j < X.channels4; j++) - #endif - { - float4 v = 0.0f; - #ifdef ReduceN - v = X.Get4(j, h, w, c4); - #endif - #ifdef ReduceH - v = X.Get4(n, j, w, c4); - #endif - #ifdef ReduceW - v = X.Get4(n, h, j, c4); - #endif - #ifdef ReduceC - v = X.Get4(n, h, w, j); - #endif - - #ifdef ReduceC - if (4 * j + 0 < X.channels) - acc.x += exp(v.x - maxV.x); - if (4 * j + 1 < X.channels) - acc.y += exp(v.y - maxV.y); - if (4 * j + 2 < X.channels) - acc.z += exp(v.z - maxV.z); - if (4 * j + 3 < X.channels) - acc.w += exp(v.w - maxV.w); - #else - acc += exp(v - maxV); - #endif - } - #ifdef ReduceC - acc = acc.x + acc.y + acc.z + acc.w; - #endif - - float4 v = X.Get4(n, h, w, c4); - v = (v - maxV) - log(acc); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LogSoftmax.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LogSoftmax.shader.meta deleted file mode 100644 index 32a4104..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/LogSoftmax.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 3a0431d0fc2c43c468a2b6c7e67de5d0 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MatMul.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MatMul.shader deleted file mode 100644 index 126f716..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MatMul.shader +++ /dev/null @@ -1,86 +0,0 @@ -Shader "Barracuda/MatMul" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile xTranspose_OFF xTranspose_ON - #pragma multi_compile yTranspose_OFF yTranspose_ON - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(Y) - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_O(O); - TENSOR_ARG(X); - TENSOR_ARG(Y); - - uint n, h, w, k4; - O.GetPositionFromUV(i.uv, n, h, w, k4); - - float4 acc4 = 0.0f; - for (uint c4 = 0; c4 < X.channels4; c4++) - { - float4 a = X.Get4(n, 0, 0, c4); - #ifdef xTranspose_ON - a.x = X.Get(4 * c4 + 0, 0, 0, n); - a.y = X.Get(4 * c4 + 1, 0, 0, n); - a.z = X.Get(4 * c4 + 2, 0, 0, n); - a.w = X.Get(4 * c4 + 3, 0, 0, n); - #endif - - float4 b0 = Y.Get4(4 * c4 + 0, 0, 0, k4); - float4 b1 = Y.Get4(4 * c4 + 1, 0, 0, k4); - float4 b2 = Y.Get4(4 * c4 + 2, 0, 0, k4); - float4 b3 = Y.Get4(4 * c4 + 3, 0, 0, k4); - #ifdef yTranspose_ON - b0.x = Y.Get(4 * k4 + 0, 0, 0, 4 * c4 + 0); - b0.y = Y.Get(4 * k4 + 1, 0, 0, 4 * c4 + 0); - b0.z = Y.Get(4 * k4 + 2, 0, 0, 4 * c4 + 0); - b0.w = Y.Get(4 * k4 + 3, 0, 0, 4 * c4 + 0); - - b1.x = Y.Get(4 * k4 + 0, 0, 0, 4 * c4 + 1); - b1.y = Y.Get(4 * k4 + 1, 0, 0, 4 * c4 + 1); - b1.z = Y.Get(4 * k4 + 2, 0, 0, 4 * c4 + 1); - b1.w = Y.Get(4 * k4 + 3, 0, 0, 4 * c4 + 1); - - b2.x = Y.Get(4 * k4 + 0, 0, 0, 4 * c4 + 2); - b2.y = Y.Get(4 * k4 + 1, 0, 0, 4 * c4 + 2); - b2.z = Y.Get(4 * k4 + 2, 0, 0, 4 * c4 + 2); - b2.w = Y.Get(4 * k4 + 3, 0, 0, 4 * c4 + 2); - - b3.x = Y.Get(4 * k4 + 0, 0, 0, 4 * c4 + 3); - b3.y = Y.Get(4 * k4 + 1, 0, 0, 4 * c4 + 3); - b3.z = Y.Get(4 * k4 + 2, 0, 0, 4 * c4 + 3); - b3.w = Y.Get(4 * k4 + 3, 0, 0, 4 * c4 + 3); - #endif - - - acc4.x += dot(a, float4(b0.x, b1.x, b2.x, b3.x)); - acc4.y += dot(a, float4(b0.y, b1.y, b2.y, b3.y)); - acc4.z += dot(a, float4(b0.z, b1.z, b2.z, b3.z)); - acc4.w += dot(a, float4(b0.w, b1.w, b2.w, b3.w)); - } - - return acc4; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MatMul.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MatMul.shader.meta deleted file mode 100644 index a77d473..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MatMul.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: a85eb55355defae4dbd68f698857c3c7 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MaxPool2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MaxPool2D.shader deleted file mode 100644 index a41c925..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MaxPool2D.shader +++ /dev/null @@ -1,49 +0,0 @@ -Shader "Barracuda/MaxPool2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - uint4 _Pool; - uint4 _Pad; - uint4 _Stride; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 maxV = -FLT_MAX; - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint2 pos = uint2(w, h) * _Stride.xy + uint2(dx, dy); - float4 v = X.SafeGet4(n, pos, c4, _Pad.xy, -FLT_MAX); - maxV = max(v, maxV); - } - - return maxV; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MaxPool2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MaxPool2D.shader.meta deleted file mode 100644 index 4932b58..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/MaxPool2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 0b2b645e73217f040a1c5a56938e1a5f -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/OneHot.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/OneHot.shader deleted file mode 100644 index 335fb67..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/OneHot.shader +++ /dev/null @@ -1,77 +0,0 @@ -Shader "Barracuda/OneHot" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile Input1D Input2D Input3D - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - float _Alpha; - float _Beta; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 v = 0.0f; - #ifdef Input1D - // O = (X.flatHeight, 1, 1, depth) - uint index = (uint)(X.Get(n, 0, 0, 0)); - v.x = ((4 * c4 + 0) == index) ? _Alpha : _Beta; - v.y = ((4 * c4 + 1) == index) ? _Alpha : _Beta; - v.z = ((4 * c4 + 2) == index) ? _Alpha : _Beta; - v.w = ((4 * c4 + 3) == index) ? _Alpha : _Beta; - #endif - #ifdef Input2D - // O = (X.flatHeight, 1, depth, X.flatWidth) - uint4 index = (uint4)(X.Get4(n, 0, 0, c4)); - v.x = (w == index.x) ? _Alpha : _Beta; - v.y = (w == index.y) ? _Alpha : _Beta; - v.z = (w == index.z) ? _Alpha : _Beta; - v.w = (w == index.w) ? _Alpha : _Beta; - #endif - #ifdef Input3D - // O = (X.batch, X.height, depth, X.channels - uint4 index = (uint4)(X.Get4(n, 0, w, c4)); - v.x = (w == index.x) ? _Alpha : _Beta; - v.y = (w == index.y) ? _Alpha : _Beta; - v.z = (w == index.z) ? _Alpha : _Beta; - v.w = (w == index.w) ? _Alpha : _Beta; - #endif - - if (4 * c4 >= O.channels) - v.x = 0.0f; - if (4 * c4 + 1 >= O.channels) - v.y = 0.0f; - if (4 * c4 + 2 >= O.channels) - v.z = 0.0f; - if (4 * c4 + 3 >= O.channels) - v.w = 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/OneHot.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/OneHot.shader.meta deleted file mode 100644 index 0ff3380..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/OneHot.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 6eee405438c886740828f17d72b93324 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/PRelu.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/PRelu.shader deleted file mode 100644 index 7960403..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/PRelu.shader +++ /dev/null @@ -1,54 +0,0 @@ -Shader "Barracuda/PRelu" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(W) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS3(X, W, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - float4 v = X.Get4(n, h, w, c4); - float4 slope = W.BroadcastGet4(n, h, w, c4); - - v.x = max(0.0f, v.x) + slope.x * min(0.0f, v.x); - v.y = max(0.0f, v.y) + slope.y * min(0.0f, v.y); - v.z = max(0.0f, v.z) + slope.z * min(0.0f, v.z); - v.w = max(0.0f, v.w) + slope.w * min(0.0f, v.w); - - if (4 * c4 >= X.channels) - v.x = 0.0f; - if (4 * c4 + 1 >= X.channels) - v.y = 0.0f; - if (4 * c4 + 2 >= X.channels) - v.z = 0.0f; - if (4 * c4 + 3 >= X.channels) - v.w = 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/PRelu.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/PRelu.shader.meta deleted file mode 100644 index 931e39b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/PRelu.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 3f5bce070d34bc745bdaaf312ec25ae9 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DEdge.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DEdge.shader deleted file mode 100644 index 1fecece..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DEdge.shader +++ /dev/null @@ -1,54 +0,0 @@ -Shader "Barracuda/Pad2DEdge" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pad; - - void ClampHWToTensorShape(uint2 shape, inout int height, inout int width) - { - width = clamp(width, 0, (int)shape.x - 1); - height = clamp(height, 0, (int)shape.y - 1); - } - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - int readX = w - _Pad.x; - int readY = h - _Pad.y; - uint2 Xshape = uint2(X.width, X.height); - - //clamp read indices to source - ClampHWToTensorShape(Xshape, readY, readX); - - float4 v = X.Get4(n, readY, readX, c4); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DEdge.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DEdge.shader.meta deleted file mode 100644 index 7a80e88..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DEdge.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 952ecd58e11f99f469813b5206eb4cf4 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DReflect.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DReflect.shader deleted file mode 100644 index 2830fc9..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DReflect.shader +++ /dev/null @@ -1,68 +0,0 @@ -Shader "Barracuda/Pad2DReflect" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pad; - - void ClampHWToTensorShape(uint2 shape, inout int height, inout int width) - { - width = clamp(width, 0, (int)shape.x - 1); - height = clamp(height, 0, (int)shape.y - 1); - } - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - int readX = w - _Pad.x; - int readY = h - _Pad.y; - uint2 Xshape = uint2(X.width, X.height); - - int lastXIndex = Xshape.x - 1; - int lastYIndex = Xshape.y - 1; - - //x reflect indexing - if (readX < 0) - readX = -readX; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex); - - //y reflect indexing - if (readY < 0) - readY = -readY; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex); - - //clamp read indices to source - ClampHWToTensorShape(Xshape, readY, readX); - - float4 v = X.Get4(n, readY, readX, c4); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DReflect.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DReflect.shader.meta deleted file mode 100644 index eed7f68..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DReflect.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 906a377749414ef428e310032b093876 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DSymmetric.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DSymmetric.shader deleted file mode 100644 index 056b537..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DSymmetric.shader +++ /dev/null @@ -1,69 +0,0 @@ -Shader "Barracuda/Pad2DSymmetric" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pad; - - void ClampHWToTensorShape(uint2 shape, inout int height, inout int width) - { - width = clamp(width, 0, (int)shape.x - 1); - height = clamp(height, 0, (int)shape.y - 1); - } - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - int readX = w - _Pad.x; - int readY = h - _Pad.y; - uint2 Xshape = uint2(X.width, X.height); - - int lastXIndex = Xshape.x - 1; - int lastYIndex = Xshape.y - 1; - - //x symmetric indexing - if (readX < 0) - readX = -readX - 1; - else if (readX > lastXIndex) - readX = lastXIndex - (readX - lastXIndex) + 1; - - //y symmetric indexing - if (readY < 0) - readY = -readY - 1; - else if (readY > lastYIndex) - readY = lastYIndex - (readY - lastYIndex) + 1; - - //clamp read indices to source - ClampHWToTensorShape(Xshape, readY, readX); - - float4 v = X.Get4(n, readY, readX, c4); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DSymmetric.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DSymmetric.shader.meta deleted file mode 100644 index ac150be..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Pad2DSymmetric.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 0b9ecd638f6c8f545ad360a14390b661 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Reduce.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Reduce.shader deleted file mode 100644 index c97184e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Reduce.shader +++ /dev/null @@ -1,240 +0,0 @@ -Shader "Barracuda/Reduce" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile ArgMax ArgMin ReduceMin ReduceMax ReduceSum ReduceMean ReduceProd - #pragma multi_compile ReduceN ReduceH ReduceW ReduceC - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - uint _Axis; - - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - #ifdef ArgMin - uint4 minIdx = uint4(0, 1, 2, 3); - #endif - #ifdef ArgMax - uint4 maxIdx = uint4(0, 1, 2, 3); - #endif - - float defaultValue = 0.0f; - #ifdef ArgMin - defaultValue = FLT_MAX; - #endif - #ifdef ArgMax - defaultValue = -FLT_MAX; - #endif - #ifdef ReduceMin - defaultValue = FLT_MAX; - #endif - #ifdef ReduceMax - defaultValue = -FLT_MAX; - #endif - #ifdef ReduceProd - defaultValue = 1.0f; - #endif - - float4 acc4 = defaultValue; - - #ifdef ReduceN - for (uint j = 0; j < X.batch; j++) - #endif - #ifdef ReduceH - for (uint j = 0; j < X.height; j++) - #endif - #ifdef ReduceW - for (uint j = 0; j < X.width; j++) - #endif - #ifdef ReduceC - for (uint j = 0; j < X.channels4; j++) - #endif - { - float4 v = 0.0f; - #ifdef ReduceN - v = X.SafeGet4(j, uint2(w, h), c4, uint2(0, 0), defaultValue); - #endif - #ifdef ReduceH - v = X.SafeGet4(n, uint2(w, j), c4, uint2(0, 0), defaultValue); - #endif - #ifdef ReduceW - v = X.SafeGet4(n, uint2(j, h), c4, uint2(0, 0), defaultValue); - #endif - #ifdef ReduceC - v = X.SafeGet4(n, uint2(w, h), j, uint2(0, 0), defaultValue); - #endif - - #ifdef ArgMin - uint4 index = j; - #ifdef ReduceC - index = uint4(0, 1, 2, 3) + 4 * j; - #endif - if (v.x < acc4.x) - { - acc4.x = v.x; - minIdx.x = index.x; - } - if (v.y < acc4.y) - { - acc4.y = v.y; - minIdx.y = index.y; - } - if (v.z < acc4.z) - { - acc4.z = v.z; - minIdx.z = index.z; - } - if (v.w < acc4.w) - { - acc4.w = v.w; - minIdx.w = index.w; - } - #endif - #ifdef ArgMax - uint4 index = j; - #ifdef ReduceC - index = uint4(0, 1, 2, 3) + 4 * j; - #endif - if (v.x > acc4.x) - { - acc4.x = v.x; - maxIdx.x = index.x; - } - if (v.y > acc4.y) - { - acc4.y = v.y; - maxIdx.y = index.y; - } - if (v.z > acc4.z) - { - acc4.z = v.z; - maxIdx.z = index.z; - } - if (v.w > acc4.w) - { - acc4.w = v.w; - maxIdx.w = index.w; - } - #endif - #ifdef ReduceMin - acc4 = min(acc4, v); - #endif - #ifdef ReduceMax - acc4 = max(acc4, v); - #endif - #ifdef ReduceSum - acc4 = acc4 + v; - #endif - #ifdef ReduceMean - acc4 = acc4 + v; - #endif - #ifdef ReduceProd - acc4 = acc4 * v; - #endif - } - - #ifdef ReduceC - #ifdef ArgMin - if (acc4[1] < acc4[0]) - { - acc4[0] = acc4[1]; - minIdx[0] = minIdx[1]; - } - if (acc4[2] < acc4[0]) - { - acc4[0] = acc4[2]; - minIdx[0] = minIdx[2]; - } - if (acc4[3] < acc4[0]) - { - acc4[0] = acc4[3]; - minIdx[0] = minIdx[3]; - } - acc4.x = minIdx.x; - acc4.yzw = 0; - #endif - #ifdef ArgMax - if (acc4[1] > acc4[0]) - { - acc4[0] = acc4[1]; - maxIdx[0] = maxIdx[1]; - } - if (acc4[2] > acc4[0]) - { - acc4[0] = acc4[2]; - maxIdx[0] = maxIdx[2]; - } - if (acc4[3] > acc4[0]) - { - acc4[0] = acc4[3]; - maxIdx[0] = maxIdx[3]; - } - acc4.x = maxIdx.x; - acc4.yzw = 0; - #endif - #ifdef ReduceMin - acc4.x = min(acc4.x, min(acc4.y, min(acc4.z, acc4.w))); - acc4.yzw = 0; - #endif - #ifdef ReduceMax - acc4.x = max(acc4.x, max(acc4.y, max(acc4.z, acc4.w))); - acc4.yzw = 0; - #endif - #ifdef ReduceSum - acc4.x = acc4.x + acc4.y + acc4.z + acc4.w; - acc4.yzw = 0; - #endif - #ifdef ReduceMean - acc4.x = acc4.x + acc4.y + acc4.z + acc4.w; - acc4.yzw = 0; - #endif - #ifdef ReduceProd - acc4.x = acc4.x * acc4.y * acc4.z * acc4.w; - acc4.yzw = 0; - #endif - #endif - - #ifdef ReduceMean - #ifdef ReduceN - acc4 /= X.batch; - #endif - #ifdef ReduceH - acc4 /= X.height; - #endif - #ifdef ReduceW - acc4 /= X.width; - #endif - #ifdef ReduceC - acc4 /= X.channels; - #endif - #endif - - return acc4; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Reduce.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Reduce.shader.meta deleted file mode 100644 index d51306b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Reduce.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 591a3c0612d3fd443a48e5f8d1524490 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Resample2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Resample2D.shader deleted file mode 100644 index de3a3fc..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Resample2D.shader +++ /dev/null @@ -1,46 +0,0 @@ -Shader "Barracuda/Resample2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pool; - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float2 dstSize = float2(O.width, O.height); - float2 srcSize = float2(X.width, X.height); - float2 dstPos = float2(w, h); - float2 srcPos = floor(dstPos / (dstSize / srcSize)); - - float4 v = X.ClampGet4(n, srcPos, c4); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Resample2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Resample2D.shader.meta deleted file mode 100644 index 17ecf9a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Resample2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: bf44d2b8d8011c044b0c279769b8f106 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ResampleBilinear2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ResampleBilinear2D.shader deleted file mode 100644 index c1f7639..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ResampleBilinear2D.shader +++ /dev/null @@ -1,55 +0,0 @@ -Shader "Barracuda/ResampleBilinear2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pool; - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - - float2 dstSize = float2(O.width, O.height); - float2 srcSize = float2(X.width, X.height); - float2 dstPos = float2(w, h); - float2 srcPos = (dstPos + 0.5) * (srcSize / dstSize) - 0.5; - - float4 p00 = X.ClampGet4(n, floor(srcPos) + float2(0, 0), c4); - float4 p01 = X.ClampGet4(n, floor(srcPos) + float2(0, 1), c4); - float4 p10 = X.ClampGet4(n, floor(srcPos) + float2(1, 0), c4); - float4 p11 = X.ClampGet4(n, floor(srcPos) + float2(1, 1), c4); - - float v = p00 * (1 - frac(srcPos.x)) * (1 - frac(srcPos.y)) + - p01 * (1 - frac(srcPos.x)) * frac(srcPos.y) + - p10 * frac(srcPos.x) * (1 - frac(srcPos.y)) + - p11 * frac(srcPos.x) * frac(srcPos.y); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ResampleBilinear2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ResampleBilinear2D.shader.meta deleted file mode 100644 index 8fd831b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ResampleBilinear2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: ce42c26f8d395eb4fb5f60ddca0049e1 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScaleBias.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScaleBias.shader deleted file mode 100644 index 692c878..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScaleBias.shader +++ /dev/null @@ -1,44 +0,0 @@ -Shader "Barracuda/ScaleBias" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(W) - TENSOR_DECL(B) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS4(X, W, B, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 scale = W.Get4(0,0,0,c4); - float4 bias = B.Get4(0,0,0,c4); - - float4 v = X.Get4(n, h, w, c4); - - return scale * v + bias; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScaleBias.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScaleBias.shader.meta deleted file mode 100644 index 915db9a..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScaleBias.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: fa97a13e61738ef418102c0bdf7e9a40 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScatterND.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScatterND.shader deleted file mode 100644 index 8a4f15f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScatterND.shader +++ /dev/null @@ -1,121 +0,0 @@ -Shader "Barracuda/ScatterND" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile ReduceNone ReduceAdd ReduceMul - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - TENSOR_DECL(K) - TENSOR_DECL(W) - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS4(X, K, W, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 v = X.Get4(n, h, w, c4); - - for (uint idx = 0; idx < K.GetFlatWidth(); idx++) - { - uint cK = idx % K.channels; - uint wK = (idx / K.channels) % K.width; - uint hK = (idx / K.channels / K.width) % K.height; - - uint indexRemap = (uint)(K.Get(0, hK, wK, cK)); - - if (4 * c4 + 0 == indexRemap) - { - float vw = W.Get(n, h, w, idx); - - #ifdef ReduceNone - v[0] = vw; - #endif - #ifdef ReduceAdd - v[0] += vw; - #endif - #ifdef ReduceMul - v[0] += vw; - #endif - } - - if (4 * c4 + 1 == indexRemap) - { - float vw = W.Get(n, h, w, idx); - - #ifdef ReduceNone - v[1] = vw; - #endif - #ifdef ReduceAdd - v[1] += vw; - #endif - #ifdef ReduceMul - v[1] += vw; - #endif - } - - if (4 * c4 + 2 == indexRemap) - { - float vw = W.Get(n, h, w, idx); - - #ifdef ReduceNone - v[2] = vw; - #endif - #ifdef ReduceAdd - v[2] += vw; - #endif - #ifdef ReduceMul - v[2] += vw; - #endif - } - - if (4 * c4 + 3 == indexRemap) - { - float vw = W.Get(n, h, w, idx); - - #ifdef ReduceNone - v[3] = vw; - #endif - #ifdef ReduceAdd - v[3] += vw; - #endif - #ifdef ReduceMul - v[3] += vw; - #endif - } - } - - if (4 * c4 >= O.channels) - v.x = 0.0f; - if (4 * c4 + 1 >= O.channels) - v.y = 0.0f; - if (4 * c4 + 2 >= O.channels) - v.z = 0.0f; - if (4 * c4 + 3 >= O.channels) - v.w = 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScatterND.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScatterND.shader.meta deleted file mode 100644 index c2dff47..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/ScatterND.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 5083906475a3be346a7828801c6bfbe6 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Softmax.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Softmax.shader deleted file mode 100644 index 532ebe2..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Softmax.shader +++ /dev/null @@ -1,125 +0,0 @@ -Shader "Barracuda/Softmax" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma multi_compile ReduceN ReduceH ReduceW ReduceC - - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - uint _Axis; - - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 maxV = -FLT_MAX; - - uint j = 0; - #ifdef ReduceN - for (j = 0; j < X.batch; j++) - #endif - #ifdef ReduceH - for (j = 0; j < X.height; j++) - #endif - #ifdef ReduceW - for (j = 0; j < X.width; j++) - #endif - #ifdef ReduceC - for (j = 0; j < X.channels4; j++) - #endif - { - float4 v = 0.0f; - #ifdef ReduceN - v = X.SafeGet4(j, uint2(w, h), c4, uint2(0, 0), -FLT_MAX); - #endif - #ifdef ReduceH - v = X.SafeGet4(n, uint2(w, j), c4, uint2(0, 0), -FLT_MAX); - #endif - #ifdef ReduceW - v = X.SafeGet4(n, uint2(j, h), c4, uint2(0, 0), -FLT_MAX); - #endif - #ifdef ReduceC - v = X.SafeGet4(n, uint2(w, h), j, uint2(0, 0), -FLT_MAX); - #endif - - maxV = max(maxV, v); - } - #ifdef ReduceC - maxV = max(maxV.x, max(maxV.y, max(maxV.z, maxV.w))); - #endif - - float4 acc = 0.0f; - #ifdef ReduceN - for (j = 0; j < X.batch; j++) - #endif - #ifdef ReduceH - for (j = 0; j < X.height; j++) - #endif - #ifdef ReduceW - for (j = 0; j < X.width; j++) - #endif - #ifdef ReduceC - for (j = 0; j < X.channels4; j++) - #endif - { - float4 v = 0.0f; - #ifdef ReduceN - v = X.Get4(j, h, w, c4); - #endif - #ifdef ReduceH - v = X.Get4(n, j, w, c4); - #endif - #ifdef ReduceW - v = X.Get4(n, h, j, c4); - #endif - #ifdef ReduceC - v = X.Get4(n, h, w, j); - #endif - - #ifdef ReduceC - if (4 * j + 0 < X.channels) - acc.x += exp(v.x - maxV.x); - if (4 * j + 1 < X.channels) - acc.y += exp(v.y - maxV.y); - if (4 * j + 2 < X.channels) - acc.z += exp(v.z - maxV.z); - if (4 * j + 3 < X.channels) - acc.w += exp(v.w - maxV.w); - #else - acc += exp(v - maxV); - #endif - } - #ifdef ReduceC - acc = acc.x + acc.y + acc.z + acc.w; - #endif - - float4 v = X.Get4(n, h, w, c4); - v = exp(v - maxV) / acc; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Softmax.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Softmax.shader.meta deleted file mode 100644 index 0a333d9..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Softmax.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 7df61c7c6d39e284788b0e957cdcceb7 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/SpaceToDepth.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/SpaceToDepth.shader deleted file mode 100644 index 322d625..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/SpaceToDepth.shader +++ /dev/null @@ -1,56 +0,0 @@ -Shader "Barracuda/SpaceToDepth" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - uint4 _Pool; - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, y, x, c4; - O.GetPositionFromUV(i.uv, n, y, x, c4); - - uint bsX = _Pool.x; - uint bsY = _Pool.y; - - float4 v = 0; - [unroll] - for (uint cc = 0; cc < 4; cc++) - { - uint c = 4 * c4 + cc; - int ic = c % X.channels; - int bx = c / X.channels % bsX; - int by = c / X.channels / bsX; - int ix = x * bsX + bx; - int iy = y * bsY + by; - - if (c < O.channels) - v[cc] = X.Get(n, iy, ix, ic); - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/SpaceToDepth.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/SpaceToDepth.shader.meta deleted file mode 100644 index 2a8c421..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/SpaceToDepth.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 85eeabcf392639b449cf6daab4e02211 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/StridedSlice.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/StridedSlice.shader deleted file mode 100644 index a4b74ad..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/StridedSlice.shader +++ /dev/null @@ -1,52 +0,0 @@ -Shader "Barracuda/StridedSlice" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Starts; - int4 _Stride; - - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 v = 0; - - v.x = X.Get(_Starts.x + n * _Stride.x, _Starts.y + h * _Stride.y, _Starts.z + w * _Stride.z, _Starts.w + (4 * c4 + 0) * _Stride.w); - v.y = X.Get(_Starts.x + n * _Stride.x, _Starts.y + h * _Stride.y, _Starts.z + w * _Stride.z, _Starts.w + (4 * c4 + 1) * _Stride.w); - v.z = X.Get(_Starts.x + n * _Stride.x, _Starts.y + h * _Stride.y, _Starts.z + w * _Stride.z, _Starts.w + (4 * c4 + 2) * _Stride.w); - v.w = X.Get(_Starts.x + n * _Stride.x, _Starts.y + h * _Stride.y, _Starts.z + w * _Stride.z, _Starts.w + (4 * c4 + 3) * _Stride.w); - - v.x = 4 * c4 + 0 < X.channels ? v.x : 0.0f; - v.y = 4 * c4 + 1 < X.channels ? v.y : 0.0f; - v.z = 4 * c4 + 2 < X.channels ? v.z : 0.0f; - v.w = 4 * c4 + 3 < X.channels ? v.w : 0.0f; - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/StridedSlice.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/StridedSlice.shader.meta deleted file mode 100644 index d96db00..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/StridedSlice.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: dce9cbe29a165a94fad431491552a39d -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorTexture.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorTexture.cginc deleted file mode 100644 index 110613f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorTexture.cginc +++ /dev/null @@ -1,253 +0,0 @@ -#pragma multi_compile BATCHTILLING_OFF BATCHTILLING_ON -#define ACTIVATION_NONE 0 -#define ACTIVATION_RELU 1 - -int _ActivationMode; -float4 ApplyFusedActivation(float4 v) -{ - if (_ActivationMode == ACTIVATION_RELU) - { - v.x = max(v.x, 0.0f); - v.y = max(v.y, 0.0f); - v.z = max(v.z, 0.0f); - v.w = max(v.w, 0.0f); - } - return v; -} - -struct Tensor -{ - uint batch; - uint height; - uint width; - uint channels; - -#if BATCHTILLING_ON - uint batchw; - uint batchh; -#endif - - uint channels4; - uint channels4w; - uint channels4h; - - void Init(uint4 nhwc) - { - batch = nhwc.x; - height = nhwc.y; - width = nhwc.z; - channels = nhwc.w; - - - channels4 = (channels + 4 - 1) / 4; - channels4w = channels4; - channels4h = 1; - - if (channels4w * width > 16384) - { - channels4w = floor(16384 / ((float)width)); - channels4h = (channels4 + channels4w - 1) / channels4w; - } - -#if BATCHTILLING_ON - batchh = batch; - batchw = 1; - - if (batchh * channels4h * height > 16384) - { - batchh = floor(16384 / ((float)(channels4h * height))); - batchw = (batch + batchh - 1) / batchh; - } -#endif - } - - void GetPositionFromUV(float2 uv, out int n, out uint h, out uint w, out uint c4) - { -#if BATCHTILLING_ON - uint2 tid2 = (uint2)(floor(uv * float2(width * channels4w * batchw, channels4h * height * batchh))); -#else - uint2 tid2 = (uint2)(floor(uv * float2(width * channels4w, channels4h * height * batch))); -#endif - w = tid2.x % width; - uint c4w = tid2.x / width; - - - h = tid2.y % height; - uint c4h = (tid2.y / height) % channels4h; - -#if BATCHTILLING_ON - uint bw = (tid2.x / width) / channels4w; - uint bh = (tid2.y / height) / channels4h; - n = bw + batchw * bh; -#else - n = (tid2.y / height) / channels4h; -#endif - - c4 = c4w + channels4w * c4h; - } - - uint4 Dims() - { - return uint4(batch, height, width, channels); - } - uint GetFlatHeight() - { - return batch; - } - uint GetFlatWidth() - { - return height * width * channels; - } - uint GetKernelHeight() - { - // kernels storage: {kernel_width * kernel_height * kernel_channels * kernel_count} - uint kernelHeight = batch; - return kernelHeight; - } - uint GetKernelWidth() - { - // kernels storage: {kernel_width * kernel_height * kernel_channels * kernel_count} - uint kernelWidth = height; - return kernelWidth; - } - uint GetKernelDepth() - { - // kernels storage: {kernel_width * kernel_height * kernel_channels * kernel_count} - uint kernelDepth = width; - return kernelDepth; - } - uint GetKernelCount() - { - // kernels storage: {kernel_width * kernel_height * kernel_channels * kernel_count} - uint kernelCount = channels; - return kernelCount; - } - uint GetLength() - { - return batch * height * width * channels; - } -}; - -struct ReadonlyTensor : Tensor -{ - Texture2D data; - - void Init(uint4 nhwc, Texture2D data_) - { - Tensor::Init(nhwc); - data = data_; - } - - float4 FastGet4(float2 uv) - { - return data.Load(uint3(uv.x * channels4w * width, uv.y * channels4h * height * batch, 0)); - } - - float4 Get4(uint n, uint h, uint w, uint c4) - { - int c4w = clamp(0, c4 % channels4w, channels4w); - int c4h = clamp(0, c4 / channels4w, channels4h); - -#if BATCHTILLING_ON - int bw = clamp(0, n % batchw, batchw); - int bh = clamp(0, n / batchw, batchh); - - uint2 tid = uint2(bw * width * channels4w + c4w * width + w, bh * channels4h * height + c4h * height + h); -#else - uint2 tid = uint2(c4w * width + w, n * channels4h * height + c4h * height + h); -#endif - - return data.Load(uint3(tid.x, tid.y, 0)); - } - - float Get(uint n, uint h, uint w, uint c) - { - uint c4 = c / 4; - uint cr4 = c % 4; - return Get4(n, h, w, c4)[cr4]; - } - - float Get(uint b, uint2 pos, uint c) - { - return Get(b, pos.y, pos.x, c); - } - - float4 Get4(uint b, uint2 pos, uint c) - { - return Get4(b, pos.y, pos.x, c); - } - - float BroadcastGet(uint b, uint h, uint w, uint c) - { - return Get(b % batch, h % height, w % width, c % channels); - } - - float4 BroadcastGet4(uint b, uint h, uint w, uint c4) - { - float4 v = Get4(b % batch, h % height, w % width, c4 % channels4); - // v.x = Get(b % batch, h % height, w % width, (4 * c4 + 0) % channels); - // v.y = Get(b % batch, h % height, w % width, (4 * c4 + 1) % channels); - // v.z = Get(b % batch, h % height, w % width, (4 * c4 + 2) % channels); - // v.w = Get(b % batch, h % height, w % width, (4 * c4 + 3) % channels); - v[1] = v[((4 * c4 + 1) % channels) % 4]; - v[2] = v[((4 * c4 + 2) % channels) % 4]; - v[3] = v[((4 * c4 + 3) % channels) % 4]; - - return v; - } - - float4 ClampGet4(int b, int2 pos, int ch, int2 pad = int2(0, 0)) - { - b = clamp(b, 0, (int)batch - 1); - pos = clamp(pos, pad, int2(width, height) + pad - 1); - ch = clamp(ch, 0, (int)channels - 1); - - pos -= pad; - return Get4(b, pos.y, pos.x, ch); - } - - float4 ClampGet4(int b, int h, int w, int ch, int2 pad = int2(0, 0)) - { - return ClampGet4(b, int2(w, h), ch, pad); - } - - float SafeGetHW(uint b, uint h, uint w, uint c, float def = 0.0f) - { - return (h >= height || w >= width) ? def : Get(b, min(h, height - 1), min(w, width - 1), c); - } - - float4 SafeGet4(uint b, uint2 pos, uint c4, uint2 pad, float def = 0) - { - if (b >= batch || - any(pos < pad) || - any(pos >= uint2(width, height) + pad)) - return def; - - float4 v = Get4(b, pos - pad, c4); - v.x = 4 * c4 + 0 >= channels ? def : v.x; - v.y = 4 * c4 + 1 >= channels ? def : v.y; - v.z = 4 * c4 + 2 >= channels ? def : v.z; - v.w = 4 * c4 + 3 >= channels ? def : v.w; - - return v; - } - - float SafeGet(uint b, uint2 pos, uint c, uint2 pad, float def = 0) - { - uint cr4 = (int)c % 4; - return SafeGet4(b, pos, c, pad, def = 0)[cr4]; - } -}; - -#define TENSOR_DECL(X) uint4 X##declShape; Texture2D X##data; -#define TENSOR_ARG(X) ReadonlyTensor X; X.Init(X##declShape, X##data); - -#define TENSOR_DECL_O(X) uint4 X##declShape; -#define TENSOR_O(X) Tensor X; X.Init(X##declShape); - -#define TENSOR_ARGS2(X, O) TENSOR_ARG(X); TENSOR_O(O); -#define TENSOR_ARGS3(X, A, O) TENSOR_ARG(X); TENSOR_ARG(A); TENSOR_O(O); -#define TENSOR_ARGS4(X, A, B, O) TENSOR_ARG(X); TENSOR_ARG(A); TENSOR_ARG(B); TENSOR_O(O); - -#define FLT_MAX 3.402823466e+38F -#define FLT_EPSILON 1e-6 diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorTexture.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorTexture.cginc.meta deleted file mode 100644 index 41c2c09..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorTexture.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 391b49d6add42884d9e52d450d7231d6 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToBuffer.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToBuffer.shader deleted file mode 100644 index d8851b8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToBuffer.shader +++ /dev/null @@ -1,50 +0,0 @@ -Shader "Barracuda/TensorToBuffer" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL(X) - - uint _OutputHeight; - uint _OutputWidth; - - fixed frag (v2f i) : SV_Target - { - TENSOR_ARG(X); - - uint x = floor(i.uv.x * _OutputWidth); - uint y = floor(i.uv.y * _OutputHeight); - - uint index = x + y * _OutputWidth; - - uint c = index % X.channels; - uint w = (index / X.channels) % X.width; - uint h = (index / (X.channels * X.width)) % X.height; - uint n = (index / (X.channels * X.width * X.height)) % X.batch; - - uint c4 = c / 4; - uint c0 = c % 4; - - float4 v = X.Get4(n, h, w, c4); - - return v[c0]; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToBuffer.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToBuffer.shader.meta deleted file mode 100644 index 06c2749..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToBuffer.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: bc344ba7ad8b57b4d918a9f7d029cb1b -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToTexture.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToTexture.shader deleted file mode 100644 index 7b2abff..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToTexture.shader +++ /dev/null @@ -1,74 +0,0 @@ -Shader "Barracuda/TensorToTexture" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL(X) - - uint _OutputHeight; - uint _OutputWidth; - - float4 _Scale; - float4 _Bias; - uint4 _Pad; - int _FlipY; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARG(X); - - uint b = _Pad.x; - uint x = floor(i.uv.x * _OutputWidth); - uint y = floor(i.uv.y * _OutputHeight); - - if (_FlipY == 1) - y = floor((1 - i.uv.y) * _OutputHeight); - - float4 v = 0; - - uint c = _Pad.y; - uint c4 = c / 4; - - int channelRemainder = X.channels - c; - if (channelRemainder == 1) - { - // broadcast to all channels - v = _Scale.x * X.Get4(b, y, x, c4).x + _Bias.x; - } - else if (channelRemainder == 2) - { - v = _Scale * X.Get4(b, y, x, c4) + _Bias; - v.b = 0; - v.a = 1; - } - else if (channelRemainder == 3) - { - v = _Scale * X.Get4(b, y, x, c4) + _Bias; - v.a = 1; - } - else if (channelRemainder >= 4) - { - v = _Scale * X.Get4(b, y, x, c4) + _Bias; - } - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToTexture.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToTexture.shader.meta deleted file mode 100644 index 6c7f9c6..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TensorToTexture.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 31e4af92ef99f5644970af330b92f11f -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TextureToTensor.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TextureToTensor.shader deleted file mode 100644 index bca2791..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TextureToTensor.shader +++ /dev/null @@ -1,133 +0,0 @@ -Shader "Barracuda/TextureToTensor" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - - float4 _Scale; - float4 _Bias; - bool _FlipY; - int4 _ChannelReadMap; - int4 _ChannelWriteMask; - int4 _ChannelWriteMap; - uint2 _Pool; - - Texture2D Xtex2D; - SamplerState samplerXtex2D { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_O(O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float2 uv = float2(w, h) + float2(0.5f, 0.5f); - uv.xy /= _Pool.xy; - - if (_FlipY) - uv.y = 1 - uv.y; - - float4 v = Xtex2D.SampleLevel(samplerXtex2D, uv.xy, 0); - - bool specialCaseWhenChannelMaskIsEmptyStoresAverage = true; - - float4 value = 0; - if (_ChannelWriteMask.x == 1) - { - float v0 = 0.0f; - if (_ChannelReadMap.x >= 0) - v0 = _Scale[_ChannelReadMap.x] * v[_ChannelReadMap.x] + _Bias[_ChannelReadMap.x]; - - if (_ChannelWriteMap.x == 0) - value[0] = v0; - else if (_ChannelWriteMap.x == 1) - value[1] = v0; - else if (_ChannelWriteMap.x == 2) - value[2] = v0; - else if (_ChannelWriteMap.x == 3) - value[3] = v0; - - specialCaseWhenChannelMaskIsEmptyStoresAverage = false; - } - if (_ChannelWriteMask.y == 1) - { - float v1 = 0.0f; - if (_ChannelReadMap.y >= 0) - v1 = _Scale[_ChannelReadMap.y] * v[_ChannelReadMap.y] + _Bias[_ChannelReadMap.y]; - - if (_ChannelWriteMap.y == 0) - value[0] = v1; - else if (_ChannelWriteMap.y == 1) - value[1] = v1; - else if (_ChannelWriteMap.y == 2) - value[2] = v1; - else if (_ChannelWriteMap.y == 3) - value[3] = v1; - - specialCaseWhenChannelMaskIsEmptyStoresAverage = false; - } - if (_ChannelWriteMask.z == 1) - { - float v2 = 0.0f; - if (_ChannelReadMap.z >= 0) - v2 = _Scale[_ChannelReadMap.z] * v[_ChannelReadMap.z] + _Bias[_ChannelReadMap.z]; - - if (_ChannelWriteMap.z == 0) - value[0] = v2; - else if (_ChannelWriteMap.z == 1) - value[1] = v2; - else if (_ChannelWriteMap.z == 2) - value[2] = v2; - else if (_ChannelWriteMap.z == 3) - value[3] = v2; - - specialCaseWhenChannelMaskIsEmptyStoresAverage = false; - } - if (_ChannelWriteMask.w == 1) - { - float v3 = 1.0f; - if (_ChannelReadMap.w >= 0) - v3 = _Scale[_ChannelReadMap.w] * v[_ChannelReadMap.w] + _Bias[_ChannelReadMap.w]; - - if (_ChannelWriteMap.w == 0) - value[0] = v3; - else if (_ChannelWriteMap.w == 1) - value[1] = v3; - else if (_ChannelWriteMap.w == 2) - value[2] = v3; - else if (_ChannelWriteMap.w == 3) - value[3] = v3; - - specialCaseWhenChannelMaskIsEmptyStoresAverage = false; - } - - if (specialCaseWhenChannelMaskIsEmptyStoresAverage) - { - v = _Scale * v + _Bias; - float avg = (v.r + v.g + v.b) / 3.0f; - value = avg; - } - - return value; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TextureToTensor.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TextureToTensor.shader.meta deleted file mode 100644 index 0d8f64f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/TextureToTensor.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 0cd09682d2723d04e957d229dfa41bbb -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Tile.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Tile.shader deleted file mode 100644 index 9b02f74..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Tile.shader +++ /dev/null @@ -1,40 +0,0 @@ -Shader "Barracuda/Tile" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pool; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - float4 v = X.BroadcastGet4(n, h, w, c4); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Tile.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Tile.shader.meta deleted file mode 100644 index d03d1e9..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Tile.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 7a0c372ea4d290d46a859e226f3f0db5 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Transpose.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Transpose.shader deleted file mode 100644 index 0a27463..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Transpose.shader +++ /dev/null @@ -1,46 +0,0 @@ -Shader "Barracuda/Transpose" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pool; - - fixed4 frag (v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - uint4 index = uint4(n, h, w, c4); - - float4 v = 0; - v.x = X.Get(index[_Pool.x], index[_Pool.y], index[_Pool.z], index[4 * _Pool.w + 0]); - v.y = X.Get(index[_Pool.x], index[_Pool.y], index[_Pool.z], index[4 * _Pool.w + 1]); - v.z = X.Get(index[_Pool.x], index[_Pool.y], index[_Pool.z], index[4 * _Pool.w + 2]); - v.w = X.Get(index[_Pool.x], index[_Pool.y], index[_Pool.z], index[4 * _Pool.w + 3]); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Transpose.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Transpose.shader.meta deleted file mode 100644 index dcde1ec..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Transpose.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 525964304d390c24da0f0bf4f8f06869 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Upsample2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Upsample2D.shader deleted file mode 100644 index e9196ee..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Upsample2D.shader +++ /dev/null @@ -1,41 +0,0 @@ -Shader "Barracuda/Upsample2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pool; - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float4 v = X.Get4(n, h / _Pool.y, w / _Pool.x, c4); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Upsample2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Upsample2D.shader.meta deleted file mode 100644 index fb2f303..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/Upsample2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 64e4f2a303cfa50469c37dba086b386a -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/UpsampleBilinear2D.shader b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/UpsampleBilinear2D.shader deleted file mode 100644 index c325389..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/UpsampleBilinear2D.shader +++ /dev/null @@ -1,58 +0,0 @@ -Shader "Barracuda/UpsampleBilinear2D" -{ - Properties - { - } - SubShader - { - // No culling or depth - Cull Off ZWrite Off ZTest Always - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - - #include "CommonVertexShader.cginc" - - #include "TensorTexture.cginc" - - - TENSOR_DECL_O(O) - TENSOR_DECL(X) - - int4 _Pool; - - float4 BilinearInterpolation(float fracSrcPosX, float fracSrcPosY, float4 p00, float4 p01, float4 p10, float4 p11) - { - float4 v = p00 * (1.0f - fracSrcPosX) * (1.0f - fracSrcPosY) + - p01 * (1.0f - fracSrcPosX) * fracSrcPosY + - p10 * fracSrcPosX * (1.0f - fracSrcPosY) + - p11 * fracSrcPosX * fracSrcPosY; - return v; - } - - fixed4 frag(v2f i) : SV_Target - { - TENSOR_ARGS2(X, O); - - uint n, h, w, c4; - O.GetPositionFromUV(i.uv, n, h, w, c4); - - float2 dstPos = float2(w, h); - float2 srcPos = (dstPos + 0.5) / _Pool.xy - 0.5; - - float4 p00 = X.ClampGet4(n, floor(srcPos) + float2(0, 0), c4); - float4 p01 = X.ClampGet4(n, floor(srcPos) + float2(0, 1), c4); - float4 p10 = X.ClampGet4(n, floor(srcPos) + float2(1, 0), c4); - float4 p11 = X.ClampGet4(n, floor(srcPos) + float2(1, 1), c4); - - float4 v = BilinearInterpolation(frac(srcPos.x), frac(srcPos.y), p00, p01, p10, p11); - - return v; - } - ENDCG - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/UpsampleBilinear2D.shader.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/UpsampleBilinear2D.shader.meta deleted file mode 100644 index 2d226fc..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/PixelShaders/UpsampleBilinear2D.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 43b323cac05bcfa419e2745d7f0ef147 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool.cginc deleted file mode 100644 index e864f58..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool.cginc +++ /dev/null @@ -1,521 +0,0 @@ -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL(W) -TENSOR_DECL(B) -TENSOR_DECL(WBK) -TENSOR_DECL_RW(O) - -uint4 _Pool; -uint4 _Stride; -uint4 _Pad; - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(MaxPool2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float maxV = -FLT_MAX; - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint oy = y * _Stride.y + dy; - uint ox = x * _Stride.x + dx; - - bool mask = (oy >= _Pad.y) && (ox >= _Pad.x) && (oy - _Pad.y < X.height) && (ox - _Pad.x < X.width); - float v = (mask)? X.Get(n, min(oy - _Pad.y, X.height-1), min(ox - _Pad.x, X.width-1), c): -FLT_MAX; - - maxV = max(v, maxV); - } - - O.Set(n, y, x, c, maxV); - } -} - -NUMTHREADS((4,8,8), (4,8,4), (4,4,4)) -void KERNEL_FUNC(AvgPool2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= O.channels) return; - if (x >= O.width) return; - if (y >= O.height) return; - - for (uint n = 0; n < X.batch; ++n) - { - float acc = 0; - float counter = 0; - for (uint dy = 0; dy < _Pool.y; ++dy) - for (uint dx = 0; dx < _Pool.x; ++dx) - { - uint oy = y * _Stride.y + dy; - uint ox = x * _Stride.x + dx; - - bool mask = (oy >= _Pad.y) && (ox >= _Pad.x) && (oy - _Pad.y < X.height) && (ox - _Pad.x < X.width); - acc += (mask)? X.Get(n, min(oy - _Pad.y, X.height-1), min(ox - _Pad.x, X.width-1), c): 0; - counter += (mask)? 1: 0; - } - - acc /= counter; - O.Set(n, y, x, c, acc); - } -} - -#undef POOL_SIZE -#define POOL_SIZE 8 - -groupshared float AvPool2D_PartialSum[POOL_SIZE*POOL_SIZE]; - -inline void AvgPoolInternalReduce(uint gtz, uint s) -{ - if (gtz < s) - { - AvPool2D_PartialSum[gtz] += AvPool2D_PartialSum[gtz + s]; - } - GroupMemoryBarrierWithGroupSync(); -} - -[numthreads(1, POOL_SIZE, POOL_SIZE)] -void KERNEL_FUNC(AvgPool2DReduce)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint3 groupId : SV_GroupID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - - uint gtx = groupThreadID.y; - uint gty = groupThreadID.z; - - uint gx = groupId.y; - uint gy = groupId.z; - - // https://developer.download.nvidia.com/assets/cuda/files/reduction.pdf - // half the number of blocks (x and y) replaced with 4 loads - uint x = gx * POOL_SIZE * 2 + gtx; - uint y = gy * POOL_SIZE * 2 + gty; - - // 2D -> 1D indexing - uint gtz = POOL_SIZE * gty + gtx; - - for (uint n = 0; n < X.batch; ++n) - { - float v0 = X.SafeGetHW(n, y, x, c); - float v1 = X.SafeGetHW(n, y + POOL_SIZE, x, c); - float v2 = X.SafeGetHW(n, y, x + POOL_SIZE, c); - float v3 = X.SafeGetHW(n, y + POOL_SIZE, x + POOL_SIZE, c); - AvPool2D_PartialSum[gtz] = v0 + v1 + v2 + v3; - - GroupMemoryBarrierWithGroupSync(); - - // sequential addressing - // mem = [x0...xn y0..yn] - // = [x0+y0...xn+yn ...] - // last sum saved for last - // following code is unrolled: - // for s = (POOL_SIZE*POOL_SIZE) / 2; s > 1; s >>= 1 - AvgPoolInternalReduce(gtz, 32); - AvgPoolInternalReduce(gtz, 16); - AvgPoolInternalReduce(gtz, 8); - AvgPoolInternalReduce(gtz, 4); - AvgPoolInternalReduce(gtz, 2); - - - if (gtz == 0) - { - float v = AvPool2D_PartialSum[0] + AvPool2D_PartialSum[1]; - O.Set(n, gy, gx, c, v); - } - } -} - -#undef POOL_SIZE -#define POOL_SIZE 8 - -groupshared float GlobalAvgPool2D_PartialSum[POOL_SIZE*POOL_SIZE]; - -inline void GlobalAvgPoolInternalReduce(uint gtz, uint s) -{ - if (gtz < s) - { - GlobalAvgPool2D_PartialSum[gtz] += GlobalAvgPool2D_PartialSum[gtz + s]; - } - GroupMemoryBarrierWithGroupSync(); -} - -[numthreads(1, POOL_SIZE, POOL_SIZE)] -void KERNEL_FUNC(GlobalAvgPool2D)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint3 groupId : SV_GroupID) -{ - //DISPATCH ARGS(O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - - uint gtx = groupThreadID.y; - uint gty = groupThreadID.z; - - uint gx = groupId.y; - uint gy = groupId.z; - - uint x = gx * POOL_SIZE * 2 + gtx; - uint y = gy * POOL_SIZE * 2 + gty; - - // 2D -> 1D indexing - uint gtz = POOL_SIZE * gty + gtx; - - for (uint n = 0; n < X.batch; ++n) - { - float v0 = X.SafeGetHW(n, y, x, c); - float v1 = X.SafeGetHW(n, y + POOL_SIZE, x, c); - float v2 = X.SafeGetHW(n, y, x + POOL_SIZE, c); - float v3 = X.SafeGetHW(n, y + POOL_SIZE, x + POOL_SIZE, c); - GlobalAvgPool2D_PartialSum[gtz] = v0 + v1 + v2 + v3; - GroupMemoryBarrierWithGroupSync(); - - // sequential addressing - // mem = [x0...xn y0..yn] - // = [x0+y0...xn+yn ...] - // last sum saved for last - // following code is unrolled: - // for s = (POOL_SIZE*POOL_SIZE) / 2; s > 1; s >>= 1 - GlobalAvgPoolInternalReduce(gtz, 32); - GlobalAvgPoolInternalReduce(gtz, 16); - GlobalAvgPoolInternalReduce(gtz, 8); - GlobalAvgPoolInternalReduce(gtz, 4); - GlobalAvgPoolInternalReduce(gtz, 2); - - - if (gtz == 0) - { - float v = GlobalAvgPool2D_PartialSum[0] + GlobalAvgPool2D_PartialSum[1]; - float poolSize = (_Pool[0] * _Pool[1]); - v /= poolSize; - O.Set(n, 0, 0, c, v); - } - } -} - - -#undef POOL_SIZE -#define POOL_SIZE 8 - -groupshared float MaxPool2D_PartialSum[POOL_SIZE*POOL_SIZE]; - -inline void MaxPoolInternalReduce(uint gtz, uint s) -{ - if (gtz < s) - { - MaxPool2D_PartialSum[gtz] = max(MaxPool2D_PartialSum[gtz], MaxPool2D_PartialSum[gtz + s]); - } - GroupMemoryBarrierWithGroupSync(); -} - -[numthreads(1, POOL_SIZE, POOL_SIZE)] -void KERNEL_FUNC(MaxPool2DReduce)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint3 groupId : SV_GroupID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - - uint gtx = groupThreadID.y; - uint gty = groupThreadID.z; - - uint gx = groupId.y; - uint gy = groupId.z; - - // https://developer.download.nvidia.com/assets/cuda/files/reduction.pdf - // half the number of blocks (x and y) replaced with 4 loads - uint x = gx * POOL_SIZE * 2 + gtx; - uint y = gy * POOL_SIZE * 2 + gty; - - // 2D -> 1D indexing - uint gtz = POOL_SIZE * gty + gtx; - - for (uint n = 0; n < X.batch; ++n) - { - float v0 = X.SafeGetHW(n, y, x, c, -FLT_MAX); - float v1 = X.SafeGetHW(n, y + POOL_SIZE, x, c, -FLT_MAX); - float v2 = X.SafeGetHW(n, y, x + POOL_SIZE, c, -FLT_MAX); - float v3 = X.SafeGetHW(n, y + POOL_SIZE, x + POOL_SIZE, c, -FLT_MAX); - MaxPool2D_PartialSum[gtz] = max(max(max(v0, v1), v2), v3); - - GroupMemoryBarrierWithGroupSync(); - - // sequential addressing - // mem = [x0...xn y0..yn] - // = [x0+y0...xn+yn ...] - // last sum saved for last - // following code is unrolled: - // for s = (POOL_SIZE*POOL_SIZE) / 2; s > 1; s >>= 1 - MaxPoolInternalReduce(gtz, 32); - MaxPoolInternalReduce(gtz, 16); - MaxPoolInternalReduce(gtz, 8); - MaxPoolInternalReduce(gtz, 4); - MaxPoolInternalReduce(gtz, 2); - - if (gtz == 0) - { - float v = max(MaxPool2D_PartialSum[0], MaxPool2D_PartialSum[1]); - O.Set(n, gy, gx, c, v); - } - } -} - -#undef POOL_SIZE -#define POOL_SIZE 8 - -groupshared float GlobalMaxPool2D_PartialMax[POOL_SIZE*POOL_SIZE]; - -inline void GlobalMaxPoolInternalReduce(uint gtz, uint s) -{ - if (gtz < s) - { - GlobalMaxPool2D_PartialMax[gtz] = max(GlobalMaxPool2D_PartialMax[gtz], GlobalMaxPool2D_PartialMax[gtz + s]); - } - GroupMemoryBarrierWithGroupSync(); -} - -[numthreads(1, POOL_SIZE, POOL_SIZE)] -void KERNEL_FUNC(GlobalMaxPool2D)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint3 groupId : SV_GroupID) -{ - //DISPATCH ARGS(O.channels, 1, 1); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - - uint gtx = groupThreadID.y; - uint gty = groupThreadID.z; - - uint gx = groupId.y; - uint gy = groupId.z; - - uint x = gx * POOL_SIZE * 2 + gtx; - uint y = gy * POOL_SIZE * 2 + gty; - - // 2D -> 1D indexing - uint gtz = POOL_SIZE * gty + gtx; - - for (uint n = 0; n < X.batch; ++n) - { - float v0 = X.SafeGetHW(n, y, x, c, -FLT_MAX); - float v1 = X.SafeGetHW(n, y + POOL_SIZE, x, c, -FLT_MAX); - float v2 = X.SafeGetHW(n, y, x + POOL_SIZE, c, -FLT_MAX); - float v3 = X.SafeGetHW(n, y + POOL_SIZE, x + POOL_SIZE, c, -FLT_MAX); - GlobalMaxPool2D_PartialMax[gtz] = max(max(max(v0, v1), v2), v3); - GroupMemoryBarrierWithGroupSync(); - - // sequential addressing - // mem = [x0...xn y0..yn] - // = [x0+y0...xn+yn ...] - // last sum saved for last - // following code is unrolled: - // for s = (POOL_SIZE*POOL_SIZE) / 2; s > 1; s >>= 1 - GlobalMaxPoolInternalReduce(gtz, 32); - GlobalMaxPoolInternalReduce(gtz, 16); - GlobalMaxPoolInternalReduce(gtz, 8); - GlobalMaxPoolInternalReduce(gtz, 4); - GlobalMaxPoolInternalReduce(gtz, 2); - - if (gtz == 0) - { - float maxV = max(GlobalMaxPool2D_PartialMax[0], GlobalMaxPool2D_PartialMax[1]); - O.Set(n, 0, 0, c, maxV); - } - } -} - -int _IsFirstDispatch; - -#undef POOL_SIZE -#define POOL_SIZE 8 - -TENSOR_DECL(X2) -TENSOR_DECL_RW(O2) - -groupshared float AvgVariancePool2D_PartialSum[POOL_SIZE*POOL_SIZE]; -groupshared float AvgVariancePool2D_PartialSumSq[POOL_SIZE*POOL_SIZE]; - -inline void AvgVarianceInternalReduce(uint gtz, uint s) -{ - if (gtz < s) - { - AvgVariancePool2D_PartialSum[gtz] += AvgVariancePool2D_PartialSum[gtz + s]; - AvgVariancePool2D_PartialSumSq[gtz] += AvgVariancePool2D_PartialSumSq[gtz + s]; - } - GroupMemoryBarrierWithGroupSync(); -} - - -[numthreads(1, POOL_SIZE, POOL_SIZE)] -void KERNEL_FUNC(AvgVariancePool2DReduce)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint3 groupId : SV_GroupID) -{ - //DISPATCH ARGS(O.channels, O.width, O.height); - TENSOR_ARG(X); TENSOR_ARG(X2); TENSOR_ARG_RW(O); TENSOR_ARG_RW(O2); - - uint c = dispatchThreadID.x; - - uint gtx = groupThreadID.y; - uint gty = groupThreadID.z; - - uint gx = groupId.y; - uint gy = groupId.z; - - // https://developer.download.nvidia.com/assets/cuda/files/reduction.pdf - // half the number of blocks (x and y) replaced with 4 loads - uint x = gx * POOL_SIZE * 2 + gtx; - uint y = gy * POOL_SIZE * 2 + gty; - - // 2D -> 1D indexing - uint gtz = POOL_SIZE * gty + gtx; - - for (uint n = 0; n < X.batch; ++n) - { - float v0 = X.SafeGetHW(n, y, x, c); - float v1 = X.SafeGetHW(n, y + POOL_SIZE, x, c); - float v2 = X.SafeGetHW(n, y, x + POOL_SIZE, c); - float v3 = X.SafeGetHW(n, y + POOL_SIZE, x + POOL_SIZE, c); - AvgVariancePool2D_PartialSum[gtz] = v0 + v1 + v2 + v3; - - float w0 = X2.SafeGetHW(n, y, x, c); - float w1 = X2.SafeGetHW(n, y + POOL_SIZE, x, c); - float w2 = X2.SafeGetHW(n, y, x + POOL_SIZE, c); - float w3 = X2.SafeGetHW(n, y + POOL_SIZE, x + POOL_SIZE, c); - if (_IsFirstDispatch) - { - // to avoid X^2 dispatch, first call squares X inplace - AvgVariancePool2D_PartialSumSq[gtz] = w0 * w0 + w1 * w1 + w2 * w2 + w3 * w3; - } - else - { - AvgVariancePool2D_PartialSumSq[gtz] = w0 + w1 + w2 + w3; - } - GroupMemoryBarrierWithGroupSync(); - - // sequential addressing - // mem = [x0...xn y0..yn] - // = [x0+y0...xn+yn ...] - // last sum saved for last - // following code is unrolled: - // for s = (POOL_SIZE*POOL_SIZE) / 2; s > 1; s >>= 1 - AvgVarianceInternalReduce(gtz, 32); - AvgVarianceInternalReduce(gtz, 16); - AvgVarianceInternalReduce(gtz, 8); - AvgVarianceInternalReduce(gtz, 4); - AvgVarianceInternalReduce(gtz, 2); - - - if (gtz == 0) - { - float v = AvgVariancePool2D_PartialSum[0] + AvgVariancePool2D_PartialSum[1]; - float v2 = AvgVariancePool2D_PartialSumSq[0] + AvgVariancePool2D_PartialSumSq[1]; - - O.Set(n, gy, gx, c, v); - O2.Set(n, gy, gx, c, v2); - } - } -} - -#undef POOL_SIZE -#define POOL_SIZE 8 - -groupshared float GlobalAvgVariancePool2D_PartialSum[POOL_SIZE*POOL_SIZE]; -groupshared float GlobalAvgVariancePool2D_PartialSumSq[POOL_SIZE*POOL_SIZE]; - -inline void GlobalAvgVarianceInternalReduce(uint gtz, uint s) -{ - if (gtz < s) - { - GlobalAvgVariancePool2D_PartialSum[gtz] += GlobalAvgVariancePool2D_PartialSum[gtz + s]; - GlobalAvgVariancePool2D_PartialSumSq[gtz] += GlobalAvgVariancePool2D_PartialSumSq[gtz + s]; - } - GroupMemoryBarrierWithGroupSync(); -} - -[numthreads(1, POOL_SIZE, POOL_SIZE)] -void KERNEL_FUNC(GlobalAvgVariancePool2D)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint3 groupId : SV_GroupID) -{ - //DISPATCH ARGS(O.channels, 1, 1); - TENSOR_TWOINPUTS(X, X2, O); - - uint c = dispatchThreadID.x; - - uint gtx = groupThreadID.y; - uint gty = groupThreadID.z; - - uint gx = groupId.y; - uint gy = groupId.z; - - uint x = gx * POOL_SIZE * 2 + gtx; - uint y = gy * POOL_SIZE * 2 + gty; - - // 2D -> 1D indexing - uint gtz = POOL_SIZE * gty + gtx; - - for (uint n = 0; n < X.batch; ++n) - { - float v0 = X.SafeGetHW(n, y, x, c); - float v1 = X.SafeGetHW(n, y + POOL_SIZE, x, c); - float v2 = X.SafeGetHW(n, y, x + POOL_SIZE, c); - float v3 = X.SafeGetHW(n, y + POOL_SIZE, x + POOL_SIZE, c); - GlobalAvgVariancePool2D_PartialSum[gtz] = v0 + v1 + v2 + v3; - - float w0 = X2.SafeGetHW(n, y, x, c); - float w1 = X2.SafeGetHW(n, y + POOL_SIZE, x, c); - float w2 = X2.SafeGetHW(n, y, x + POOL_SIZE, c); - float w3 = X2.SafeGetHW(n, y + POOL_SIZE, x + POOL_SIZE, c); - if (_IsFirstDispatch) - { - // to avoid X^2 dispatch, first call squares X inplace - GlobalAvgVariancePool2D_PartialSumSq[gtz] = w0 * w0 + w1 * w1 + w2 * w2 + w3 * w3; - } - else - { - GlobalAvgVariancePool2D_PartialSumSq[gtz] = w0 + w1 + w2 + w3; - } - GroupMemoryBarrierWithGroupSync(); - - // sequential addressing - // mem = [x0...xn y0..yn] - // = [x0+y0...xn+yn ...] - // last sum saved for last - // following code is unrolled: - // for s = (POOL_SIZE*POOL_SIZE) / 2; s > 1; s >>= 1 - GlobalAvgVarianceInternalReduce(gtz, 32); - GlobalAvgVarianceInternalReduce(gtz, 16); - GlobalAvgVarianceInternalReduce(gtz, 8); - GlobalAvgVarianceInternalReduce(gtz, 4); - GlobalAvgVarianceInternalReduce(gtz, 2); - - - if (gtz == 0) - { - float v = GlobalAvgVariancePool2D_PartialSum[0] + GlobalAvgVariancePool2D_PartialSum[1]; - float v2 = GlobalAvgVariancePool2D_PartialSumSq[0] + GlobalAvgVariancePool2D_PartialSumSq[1]; - - float poolSize = (_Pool[0] * _Pool[1]); - v /= poolSize; - v2 /= poolSize; - - float mean = v; - float variance = v2 - mean * mean; - O.Set(n, 0, 0, c, mean); - O.Set(n, 1, 0, c, variance); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool.cginc.meta deleted file mode 100644 index 0da5cc2..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 27b3eac072f404f6696b286d4f4a9693 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NCHW.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NCHW.compute deleted file mode 100644 index 3f4c4a7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NCHW.compute +++ /dev/null @@ -1,10 +0,0 @@ -#pragma kernel AvgPool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel MaxPool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel AvgPool2DReduce_NCHW CHANNELS_FIRST=1 -#pragma kernel MaxPool2DReduce_NCHW CHANNELS_FIRST=1 -#pragma kernel GlobalAvgPool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel GlobalMaxPool2D_NCHW CHANNELS_FIRST=1 -#pragma kernel AvgVariancePool2DReduce_NCHW CHANNELS_FIRST=1 -#pragma kernel GlobalAvgVariancePool2D_NCHW CHANNELS_FIRST=1 - -#include "Pool.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NCHW.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NCHW.compute.meta deleted file mode 100644 index 683a81e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NCHW.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ecffd49f953b24e70a82b21054705d9d -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NHWC.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NHWC.compute deleted file mode 100644 index 2103b2e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NHWC.compute +++ /dev/null @@ -1,10 +0,0 @@ -#pragma kernel AvgPool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel MaxPool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel AvgPool2DReduce_NHWC CHANNELS_FIRST=0 -#pragma kernel MaxPool2DReduce_NHWC CHANNELS_FIRST=0 -#pragma kernel GlobalAvgPool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel GlobalMaxPool2D_NHWC CHANNELS_FIRST=0 -#pragma kernel AvgVariancePool2DReduce_NHWC CHANNELS_FIRST=0 -#pragma kernel GlobalAvgVariancePool2D_NHWC CHANNELS_FIRST=0 - -#include "Pool.cginc" diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NHWC.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NHWC.compute.meta deleted file mode 100644 index 05b2920..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Pool_NHWC.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f4ba73c7ac8774dfd9d39afed6f457b1 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 2164736 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Random.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Random.cginc deleted file mode 100644 index 2263f68..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Random.cginc +++ /dev/null @@ -1,70 +0,0 @@ - -// Based on: https://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader -// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive. -// Author: Michael Pohoreski -// Copyright: Copyleft 2012 :-) -float RandomUsingCos(float4 seed) -{ - float4 K1 = float4( // Transcendental numbers: - 0.64341054629, // (Cahen's constant) - 23.14069263277926, // e^pi (Gelfond's constant) - 2.665144142690225, // 2^sqrt(2) (Gelfond-Schneider constant) - 3.14159265359 // pi - ); - return frac(cos(dot(seed, K1)) * 12345.6789); -} - -// Based on: https://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl -// Author: Spatial -// 05 July 2013 - -// A single iteration of Bob Jenkins' One-At-A-Time hashing algorithm. -uint hash(uint x) -{ - x += ( x << 10u ); - x ^= ( x >> 6u ); - x += ( x << 3u ); - x ^= ( x >> 11u ); - x += ( x << 15u ); - return x; -} -uint hash( uint2 v ) { return hash( v.x ^ hash(v.y) ); } -uint hash( uint3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ); } -uint hash( uint4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); } - -// Construct a float with half-open range [0:1] using low 23 bits. -// All zeroes yields 0.0, all ones yields the next smallest representable value below 1.0. -float floatConstruct(uint m) -{ - const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask - const uint ieeeOne = 0x3F800000u; // 1.0 in IEEE binary32 - - m &= ieeeMantissa; // Keep only mantissa bits (fractional part) - m |= ieeeOne; // Add fractional part to 1.0 - - float f = asfloat(m); // Range [1:2] - return f - 1.0; // Range [0:1] -} - -// Pseudo-random value in half-open range [0:1]. -float RandomUsingHash(float4 seed) -{ - return floatConstruct(hash(asuint(seed))); -} - - -// More alternatives: -// https://github.com/ashima/webgl-noise -// https://www.shadertoy.com/view/4djSRW - -// ------------------------------------------------------------------------------------------ - -float Random(float4 seed) -{ - return RandomUsingCos(seed); -} - -float Bernoulli(float4 seed, float p) -{ - return Random(seed) <= p ? 1: 0; -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Random.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Random.cginc.meta deleted file mode 100644 index 572d47b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Random.cginc.meta +++ /dev/null @@ -1,10 +0,0 @@ -fileFormatVersion: 2 -guid: 5a17e0b3943a74564a02a8ed0a41228b -timeCreated: 1520855309 -licenseType: Pro -ShaderImporter: - externalObjects: {} - defaultTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Reduce.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Reduce.compute deleted file mode 100644 index 15cdeec..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Reduce.compute +++ /dev/null @@ -1,334 +0,0 @@ -// TODO fast ArgMax -#pragma kernel PartialReduceMin LOOP=0 REDUCEMIN PARTIALSUFFIX=PartialReduceMin -#pragma kernel PartialReduceMin_Loop LOOP=1 REDUCEMIN PARTIALSUFFIX=PartialReduceMin -#pragma kernel GlobalReduceMin LOOP=0 REDUCEMIN GLOBALSUFFIX=GlobalReduceMin -#pragma kernel GlobalReduceMin_Loop LOOP=1 REDUCEMIN GLOBALSUFFIX=GlobalReduceMin - -#pragma kernel PartialReduceMax LOOP=0 REDUCEMAX PARTIALSUFFIX=PartialReduceMax -#pragma kernel PartialReduceMax_Loop LOOP=1 REDUCEMAX PARTIALSUFFIX=PartialReduceMax -#pragma kernel GlobalReduceMax LOOP=0 REDUCEMAX GLOBALSUFFIX=GlobalReduceMax -#pragma kernel GlobalReduceMax_Loop LOOP=1 REDUCEMAX GLOBALSUFFIX=GlobalReduceMax - -#pragma kernel PartialReduceSum LOOP=0 REDUCESUM PARTIALSUFFIX=PartialReduceSum -#pragma kernel PartialReduceSum_Loop LOOP=1 REDUCESUM PARTIALSUFFIX=PartialReduceSum -#pragma kernel GlobalReduceSum LOOP=0 REDUCESUM GLOBALSUFFIX=GlobalReduceSum -#pragma kernel GlobalReduceSum_Loop LOOP=1 REDUCESUM GLOBALSUFFIX=GlobalReduceSum - -#pragma kernel PartialReduceMean LOOP=0 REDUCEMEAN PARTIALSUFFIX=PartialReduceMean -#pragma kernel PartialReduceMean_Loop LOOP=1 REDUCEMEAN PARTIALSUFFIX=PartialReduceMean -#pragma kernel GlobalReduceMean LOOP=0 REDUCEMEAN GLOBALSUFFIX=GlobalReduceMean -#pragma kernel GlobalReduceMean_Loop LOOP=1 REDUCEMEAN GLOBALSUFFIX=GlobalReduceMean - -#pragma kernel PartialReduceProd LOOP=0 REDUCEPROD PARTIALSUFFIX=PartialReduceProd -#pragma kernel PartialReduceProd_Loop LOOP=1 REDUCEPROD PARTIALSUFFIX=PartialReduceProd -#pragma kernel GlobalReduceProd LOOP=0 REDUCEPROD GLOBALSUFFIX=GlobalReduceProd -#pragma kernel GlobalReduceProd_Loop LOOP=1 REDUCEPROD GLOBALSUFFIX=GlobalReduceProd - -#pragma kernel PartialReduceExpBias LOOP=0 REDUCEEXPBIAS PARTIALSUFFIX=PartialReduceExpBias -#pragma kernel PartialReduceExpBias_Loop LOOP=1 REDUCEEXPBIAS PARTIALSUFFIX=PartialReduceExpBias -#pragma kernel GlobalReduceExpBias LOOP=0 REDUCEEXPBIAS GLOBALSUFFIX=GlobalReduceExpBias -#pragma kernel GlobalReduceExpBias_Loop LOOP=1 REDUCEEXPBIAS GLOBALSUFFIX=GlobalReduceExpBias - -#include "Tensor.cginc" -#include "Random.cginc" - -TENSOR_DECL(X) -TENSOR_DECL(B) -TENSOR_DECL_RW(O) - -uint _ReducedDim; -uint3 _Pool; -uint _UnrolledH; -uint _UnrolledW; -int _IsFirstDispatch; - - -#undef REDUCE_FUNC_NAME -#undef REDUCE_FUNC_NAME_CALL -#if LOOP -#define REDUCE_FUNC_NAME_CALL(KERNEL) KERNEL##_Loop -#else -#define REDUCE_FUNC_NAME_CALL(KERNEL) KERNEL -#endif -#define REDUCE_FUNC_NAME(KERNEL) REDUCE_FUNC_NAME_CALL(KERNEL) - -inline float ReduceDefaultValue() -{ -#ifdef ARGMAX - return -FLT_MAX; -#endif -#ifdef ARGMIN - return FLT_MAX; -#endif -#ifdef REDUCEMIN - return FLT_MAX; -#endif -#ifdef REDUCEMAX - return -FLT_MAX; -#endif -#ifdef REDUCEPROD - return 1.0; -#endif - return 0.0; -} - - -inline float ReduceOp(float v, float x) -{ -#ifdef ARGMAX - return max(v, x); -#endif -#ifdef ARGMIN - return min(v, x); -#endif -#ifdef REDUCEMIN - return min(v, x); -#endif -#ifdef REDUCEMAX - return max(v, x); -#endif -#ifdef REDUCESUM - return v + x; -#endif -#ifdef REDUCEMEAN - return v + x; -#endif -#ifdef REDUCEPROD - return v * x; -#endif -#ifdef REDUCEEXPBIAS - return v + x; -#endif - return v; -} - -#undef POOL_SIZE -#define POOL_SIZE 64 - -groupshared float Reduce_PartialSum[POOL_SIZE]; - -inline void PartialReduceInternalReduce(uint gty, uint s) -{ - if (gty < s) - { - Reduce_PartialSum[gty] = ReduceOp(Reduce_PartialSum[gty], Reduce_PartialSum[gty + s]); - } - GroupMemoryBarrierWithGroupSync(); -} - -[numthreads(1, POOL_SIZE, 1)] -void REDUCE_FUNC_NAME(PARTIALSUFFIX)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint3 groupId : SV_GroupID) -{ - //DISPATCH ARGS(1, O.batch, O.flatwidth); - TENSOR_ARGS3(X, B, O); - - uint flatHeight = dispatchThreadID.x; - uint flatWidth = dispatchThreadID.z; - - uint strideFlatHeight = _Pool[0]; - uint strideFlatWidth = _Pool[1]; - uint baseReducedLength = _Pool[2]; - - uint strideReducedDim = _ReducedDim; - -#if LOOP - uint strideFlatHeightUnroll = _UnrolledH; - uint strideFlatWidthUnroll = _UnrolledW; -#endif - - - - uint gty = groupThreadID.y; - uint gy = groupId.y; - - // https://developer.download.nvidia.com/assets/cuda/files/reduction.pdf - // half the number of blocks (x) replaced with 4 loads - uint y = gy * POOL_SIZE * 4 + gty; - - float defaultValue = ReduceDefaultValue(); - -#if LOOP - for (uint fhUnrolled = 0; fhUnrolled < strideFlatHeightUnroll; fhUnrolled++) - for (uint fwUnrolled = 0; fwUnrolled < strideFlatWidthUnroll; fwUnrolled++) -#endif - { - #if LOOP - uint flatHeightIdx = (flatHeight * strideFlatHeightUnroll + fhUnrolled); - uint flatWidthIdx = (flatWidth * strideFlatWidthUnroll + fwUnrolled); - float v0 = X.MaskedGet((flatHeightIdx < strideFlatHeight) && ((y + 0 * POOL_SIZE) < baseReducedLength) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth * baseReducedLength + (y + 0 * POOL_SIZE) * strideFlatWidth + flatWidthIdx, defaultValue); - float v1 = X.MaskedGet((flatHeightIdx < strideFlatHeight) && ((y + 1 * POOL_SIZE) < baseReducedLength) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth * baseReducedLength + (y + 1 * POOL_SIZE) * strideFlatWidth + flatWidthIdx, defaultValue); - float v2 = X.MaskedGet((flatHeightIdx < strideFlatHeight) && ((y + 2 * POOL_SIZE) < baseReducedLength) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth * baseReducedLength + (y + 2 * POOL_SIZE) * strideFlatWidth + flatWidthIdx, defaultValue); - float v3 = X.MaskedGet((flatHeightIdx < strideFlatHeight) && ((y + 3 * POOL_SIZE) < baseReducedLength) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth * baseReducedLength + (y + 3 * POOL_SIZE) * strideFlatWidth + flatWidthIdx, defaultValue); - #else - float v0 = X.MaskedGet((y + 0 * POOL_SIZE) < baseReducedLength, flatHeight * strideFlatWidth * baseReducedLength + (y + 0 * POOL_SIZE) * strideFlatWidth + flatWidth, defaultValue); - float v1 = X.MaskedGet((y + 1 * POOL_SIZE) < baseReducedLength, flatHeight * strideFlatWidth * baseReducedLength + (y + 1 * POOL_SIZE) * strideFlatWidth + flatWidth, defaultValue); - float v2 = X.MaskedGet((y + 2 * POOL_SIZE) < baseReducedLength, flatHeight * strideFlatWidth * baseReducedLength + (y + 2 * POOL_SIZE) * strideFlatWidth + flatWidth, defaultValue); - float v3 = X.MaskedGet((y + 3 * POOL_SIZE) < baseReducedLength, flatHeight * strideFlatWidth * baseReducedLength + (y + 3 * POOL_SIZE) * strideFlatWidth + flatWidth, defaultValue); - #endif - #ifdef REDUCEEXPBIAS - if (_IsFirstDispatch) - { - #if LOOP - bool maskv0 = (flatHeightIdx < strideFlatHeight) && ((y + 0 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth); - bool maskv1 = (flatHeightIdx < strideFlatHeight) && ((y + 1 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth); - bool maskv2 = (flatHeightIdx < strideFlatHeight) && ((y + 2 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth); - bool maskv3 = (flatHeightIdx < strideFlatHeight) && ((y + 3 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth); - float m0 = B.MaskedGet((flatHeightIdx < strideFlatHeight) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth + flatWidthIdx, defaultValue); - #else - bool maskv0 = (y + 0 * POOL_SIZE) < baseReducedLength; - bool maskv1 = (y + 1 * POOL_SIZE) < baseReducedLength; - bool maskv2 = (y + 2 * POOL_SIZE) < baseReducedLength; - bool maskv3 = (y + 3 * POOL_SIZE) < baseReducedLength; - float m0 = B.FastGet(flatHeight * strideFlatWidth + flatWidth); - #endif - v0 = maskv0 ? exp(v0 - m0) : defaultValue; - v1 = maskv1 ? exp(v1 - m0) : defaultValue; - v2 = maskv2 ? exp(v2 - m0) : defaultValue; - v3 = maskv3 ? exp(v3 - m0) : defaultValue; - } - #endif - Reduce_PartialSum[gty] = ReduceOp(v0, ReduceOp(v1, ReduceOp(v2, v3))); - - GroupMemoryBarrierWithGroupSync(); - - // sequential addressing - // mem = [x0...xn y0..yn] - // = [x0+y0...xn+yn ...] - // last sum saved for last - // following code is unrolled: - // for s = (POOL_SIZE*POOL_SIZE) / 2; s > 1; s >>= 1 - PartialReduceInternalReduce(gty, 32); - PartialReduceInternalReduce(gty, 16); - PartialReduceInternalReduce(gty, 8); - PartialReduceInternalReduce(gty, 4); - PartialReduceInternalReduce(gty, 2); - - if (gty == 0) - { - float v = ReduceOp(Reduce_PartialSum[0], Reduce_PartialSum[1]); - #if LOOP - if ((flatHeightIdx < strideFlatHeight) && (flatWidthIdx < strideFlatWidth)) - O.FastSet(flatHeightIdx * strideFlatWidth * strideReducedDim + gy * strideFlatWidth + flatWidthIdx, v); - #else - O.FastSet(flatHeight * strideFlatWidth * strideReducedDim + gy * strideFlatWidth + flatWidth, v); - #endif - } - } -} - -#undef POOL_SIZE -#define POOL_SIZE 64 - -groupshared float GlobalReduce_PartialSum[POOL_SIZE]; - -inline void GlobalReduceInternalReduce(uint gty, uint s) -{ - if (gty < s) - { - GlobalReduce_PartialSum[gty] = ReduceOp(GlobalReduce_PartialSum[gty], GlobalReduce_PartialSum[gty + s]); - } - GroupMemoryBarrierWithGroupSync(); -} - -[numthreads(1, POOL_SIZE, 1)] -void REDUCE_FUNC_NAME(GLOBALSUFFIX)(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID, uint3 groupId : SV_GroupID) -{ - //DISPATCH ARGS(1, O.batch, O.flatwidth); - TENSOR_ARGS3(X, B, O); - - uint flatHeight = dispatchThreadID.x; - uint flatWidth = dispatchThreadID.z; - - uint strideFlatHeight = _Pool[0]; - uint strideFlatWidth = _Pool[1]; - uint baseReducedLength = _Pool[2]; - -#if LOOP - uint strideFlatHeightUnroll = _UnrolledH; - uint strideFlatWidthUnroll = _UnrolledW; -#endif - - uint strideReducedDim = _ReducedDim; - - - uint gty = groupThreadID.y; - uint gy = groupId.y; - - // https://developer.download.nvidia.com/assets/cuda/files/reduction.pdf - // half the number of blocks (x) replaced with 4 loads - uint y = gy * POOL_SIZE * 4 + gty; - - float defaultValue = ReduceDefaultValue(); - -#if LOOP - for (uint fhUnrolled = 0; fhUnrolled < strideFlatHeightUnroll; fhUnrolled++) - for (uint fwUnrolled = 0; fwUnrolled < strideFlatWidthUnroll; fwUnrolled++) -#endif - { - #if LOOP - uint flatHeightIdx = (flatHeight * strideFlatHeightUnroll + fhUnrolled); - uint flatWidthIdx = (flatWidth * strideFlatWidthUnroll + fwUnrolled); - float v0 = X.MaskedGet((flatHeightIdx < strideFlatHeight) && ((y + 0 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth * strideReducedDim + (y + 0 * POOL_SIZE) * strideFlatWidth + flatWidthIdx, defaultValue); - float v1 = X.MaskedGet((flatHeightIdx < strideFlatHeight) && ((y + 1 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth * strideReducedDim + (y + 1 * POOL_SIZE) * strideFlatWidth + flatWidthIdx, defaultValue); - float v2 = X.MaskedGet((flatHeightIdx < strideFlatHeight) && ((y + 2 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth * strideReducedDim + (y + 2 * POOL_SIZE) * strideFlatWidth + flatWidthIdx, defaultValue); - float v3 = X.MaskedGet((flatHeightIdx < strideFlatHeight) && ((y + 3 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth * strideReducedDim + (y + 3 * POOL_SIZE) * strideFlatWidth + flatWidthIdx, defaultValue); - #else - float v0 = X.MaskedGet((y + 0 * POOL_SIZE) < strideReducedDim, flatHeight * strideFlatWidth * strideReducedDim + (y + 0 * POOL_SIZE) * strideFlatWidth + flatWidth, defaultValue); - float v1 = X.MaskedGet((y + 1 * POOL_SIZE) < strideReducedDim, flatHeight * strideFlatWidth * strideReducedDim + (y + 1 * POOL_SIZE) * strideFlatWidth + flatWidth, defaultValue); - float v2 = X.MaskedGet((y + 2 * POOL_SIZE) < strideReducedDim, flatHeight * strideFlatWidth * strideReducedDim + (y + 2 * POOL_SIZE) * strideFlatWidth + flatWidth, defaultValue); - float v3 = X.MaskedGet((y + 3 * POOL_SIZE) < strideReducedDim, flatHeight * strideFlatWidth * strideReducedDim + (y + 3 * POOL_SIZE) * strideFlatWidth + flatWidth, defaultValue); - #endif - #ifdef REDUCEEXPBIAS - if (_IsFirstDispatch) - { - #if LOOP - bool maskv0 = (flatHeightIdx < strideFlatHeight) && ((y + 0 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth); - bool maskv1 = (flatHeightIdx < strideFlatHeight) && ((y + 1 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth); - bool maskv2 = (flatHeightIdx < strideFlatHeight) && ((y + 2 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth); - bool maskv3 = (flatHeightIdx < strideFlatHeight) && ((y + 3 * POOL_SIZE) < strideReducedDim) && (flatWidthIdx < strideFlatWidth); - float m0 = B.MaskedGet((flatHeightIdx < strideFlatHeight) && (flatWidthIdx < strideFlatWidth), flatHeightIdx * strideFlatWidth + flatWidthIdx, defaultValue); - #else - bool maskv0 = (y + 0 * POOL_SIZE) < baseReducedLength; - bool maskv1 = (y + 1 * POOL_SIZE) < baseReducedLength; - bool maskv2 = (y + 2 * POOL_SIZE) < baseReducedLength; - bool maskv3 = (y + 3 * POOL_SIZE) < baseReducedLength; - float m0 = B.FastGet(flatHeight * strideFlatWidth + flatWidth); - #endif - v0 = maskv0 ? exp(v0 - m0) : defaultValue; - v1 = maskv1 ? exp(v1 - m0) : defaultValue; - v2 = maskv2 ? exp(v2 - m0) : defaultValue; - v3 = maskv3 ? exp(v3 - m0) : defaultValue; - } - #endif - GlobalReduce_PartialSum[gty] = ReduceOp(v0, ReduceOp(v1, ReduceOp(v2, v3))); - - GroupMemoryBarrierWithGroupSync(); - - // sequential addressing - // mem = [x0...xn y0..yn] - // = [x0+y0...xn+yn ...] - // last sum saved for last - // following code is unrolled: - // for s = (POOL_SIZE*POOL_SIZE) / 2; s > 1; s >>= 1 - GlobalReduceInternalReduce(gty, 32); - GlobalReduceInternalReduce(gty, 16); - GlobalReduceInternalReduce(gty, 8); - GlobalReduceInternalReduce(gty, 4); - GlobalReduceInternalReduce(gty, 2); - - if (gty == 0) - { - float v = ReduceOp(GlobalReduce_PartialSum[0], GlobalReduce_PartialSum[1]); -#ifdef REDUCEMEAN - // TODO: if stability issues / baseReducedLength at every step - v /= baseReducedLength; -#endif - #if LOOP - if((flatHeightIdx < strideFlatHeight) && (flatWidthIdx < strideFlatWidth)) - O.FastSet(flatHeightIdx * strideFlatWidth + flatWidthIdx, v); - #else - O.FastSet(flatHeight * strideFlatWidth + flatWidth, v); - #endif - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Reduce.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Reduce.compute.meta deleted file mode 100644 index 7cca593..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Reduce.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 6547c1c44abec4a4da178e1eb8ee7d98 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 4 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ReduceSlow.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ReduceSlow.compute deleted file mode 100644 index adf96a7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ReduceSlow.compute +++ /dev/null @@ -1,78 +0,0 @@ -// TODO fast ArgMax -#pragma kernel ArgMax_NHWC CHANNELS_FIRST=0 -#pragma kernel ArgMax_NCHW CHANNELS_FIRST=1 -#pragma kernel ArgMin_NHWC CHANNELS_FIRST=0 -#pragma kernel ArgMin_NCHW CHANNELS_FIRST=1 - -#include "Tensor.cginc" -#include "Random.cginc" - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SUFFIX) KERNEL##SUFFIX##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SUFFIX) KERNEL##SUFFIX##_NHWC -#endif -#define FUNC_NAME(KERNEL, SUFFIX) FUNC_NAME_CALL(KERNEL, SUFFIX) - -TENSOR_DECL(X) -TENSOR_DECL_RW(O) - -[numthreads(4,4,1)] -void KERNEL_FUNC(ArgMax)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height, 1); - TENSOR_ARGS2_8D(X, O); - - uint w = dispatchThreadID.x; uint h = dispatchThreadID.y; - if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - int maxIdx = 0; - float maxV = X.Get8D(s,r,n,t,d,h,w,0); - for (uint c = 1; c < X.channels; ++c) - { - float v = X.Get8D(s,r,n,t,d,h,w,c); - if (v > maxV) - { - maxV = v; - maxIdx = c; - } - } - O.Set8D(s,r,n,t,d,h,w,0,maxIdx); - } -} - -[numthreads(4,4,1)] -void KERNEL_FUNC(ArgMin)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.width, O.height, 1); - TENSOR_ARGS2_8D(X, O); - - uint w = dispatchThreadID.x; uint h = dispatchThreadID.y; - if (w >= O.width) return; if (h >= O.height) return; - - for (uint s = 0; s < O.sequenceLength; ++s) - for (uint r = 0; r < O.numberOfDirections; ++r) - for (uint n = 0; n < O.batch; ++n) - for (uint t = 0; t < O.extraDimension; ++t) - for (uint d = 0; d < O.depth; ++d) - { - int minIdx = 0; - float minV = X.Get8D(s,r,n,t,d,h,w,0); - for (uint c = 1; c < X.channels; ++c) - { - float v = X.Get8D(s,r,n,t,d,h,w,c); - if (v < minV) - { - minV = v; - minIdx = c; - } - } - O.Set8D(s,r,n,t,d,h,w,0,minIdx); - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ReduceSlow.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ReduceSlow.compute.meta deleted file mode 100644 index 98a400e..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/ReduceSlow.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 114b7898ee808d04a90194a4cabce1e2 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 4 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Tensor.cginc b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Tensor.cginc deleted file mode 100644 index e2dabac..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Tensor.cginc +++ /dev/null @@ -1,862 +0,0 @@ -#include "DebugUtils.cginc" - -#define BARRACUDA_MAX_THREAD_COUNT 64 -#if (BARRACUDA_MAX_THREAD_COUNT>=256) -#define NUMTHREADS(t256,t128,t64) [numthreads t256] -#define NUMTHREAD(t256, t128, t64) t256 -#elif (BARRACUDA_MAX_THREAD_COUNT>=128) -#define NUMTHREADS(t256,t128,t64) [numthreads t128] -#define NUMTHREAD(t256,t128,t64) t128 -#elif (BARRACUDA_MAX_THREAD_COUNT>=64) -#define NUMTHREADS(t256,t128,t64) [numthreads t64] -#define NUMTHREAD(t256,t128,t64) t64 -#endif - - -//Keep in sync with Model.cs enum Layer.FusedActivation -#define ACTIVATION_NONE 0 -#define ACTIVATION_RELU 1 - -int _ActivationMode; -float ApplyFusedActivation(float v) -{ - if (_ActivationMode == ACTIVATION_RELU) - v = max(v, 0.0f); - return v; -} - -struct Tensor -{ - // @TODO: actually uint seems not like a good idea anymore, consider going to int - uint batch, height, width, channels; - - void Init(uint4 nhwc) - { - batch = nhwc.x; - height = nhwc.y; - width = nhwc.z; - channels = nhwc.w; - } - - uint4 Dims() - { - return uint4(batch, height, width, channels); - } - uint GetFlatHeight() - { - return batch; - } - uint GetFlatWidth() - { - return height * width * channels; - } - uint GetKernelHeight() - { - // kernels storage: {kernel_width * kernel_height * kernel_channels * kernel_count} - uint kernelHeight = batch; - return kernelHeight; - } - uint GetKernelWidth() - { - // kernels storage: {kernel_width * kernel_height * kernel_channels * kernel_count} - uint kernelWidth = height; - return kernelWidth; - } - uint GetKernelDepth() - { - // kernels storage: {kernel_width * kernel_height * kernel_channels * kernel_count} - uint kernelDepth = width; - return kernelDepth; - } - uint GetKernelCount() - { - // kernels storage: {kernel_width * kernel_height * kernel_channels * kernel_count} - uint kernelCount = channels; - return kernelCount; - } - uint GetLength() - { - return batch * height * width * channels; - } - - uint IndexCHW(uint b, uint h, uint w, uint c) - { - uint index = - b * channels * height * width + - c * height * width + - h * width + - w; - return index; - } - - uint IndexCHW(uint b, uint i, uint c) - { - uint index = - b * channels * height * width + - c * height * width + - i; - return index; - } - - uint IndexHWC(uint b, uint h, uint w, uint c) - { - uint index = - b * height * width * channels + - h * width * channels + - w * channels + - c; - return index; - } - - uint IndexHWC(uint b, uint i, uint c) - { - uint index = - b * height * width * channels + - i * channels + - c; - return index; - } - - uint Index(uint b, uint i) - { - uint index = - b * height * width * channels + - i; - return index; - } - - void GetPositionFromIndexNCHW(uint index, out uint n, out uint h, out uint w, out uint c) - { - w = index % width; - h = (index / width) % height; - c = (index / (width * height)) % channels; - n = (index / (width * height * channels)) % batch; - } - - void GetPositionFromIndexNHWC(uint index, out uint n, out uint h, out uint w, out uint c) - { - c = index % channels; - w = (index / channels) % width; - h = (index / (channels * width)) % height; - n = (index / (channels * width * height)) % batch; - } -}; - -struct ReadonlyTensor : Tensor -{ - StructuredBuffer data; - - void Init(uint4 nhwc, StructuredBuffer data_) - { - Tensor::Init(nhwc); - data = data_; - } - - float Get(uint b, uint h, uint w, uint ch) - { - #if CHANNELS_FIRST - uint index = IndexCHW(b,h,w,ch); - #else - uint index = IndexHWC(b,h,w,ch); - #endif - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_READONLY_READ); - return value; - } - float Get(uint b, uint2 pos, uint ch) - { - return Get(b, pos.y, pos.x, ch); - } - float Get(uint b, uint i, uint ch) - { - #if CHANNELS_FIRST - uint index = IndexCHW(b, i, ch); - #else - uint index = IndexHWC(b, i, ch); - #endif - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_READONLY_READ); - return value; - } - float Get(uint b, uint i) - { - uint index = Index(b,i); - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_READONLY_READ); - return value; - } - float FastGet(uint i) - { - float value; - TENSOR_READ(value, i, KERNEL_ASSERT_CONTEXT_READONLY_READ); - return value; - } - - float BroadcastGet(uint b, uint h, uint w, uint ch) - { - return Get(b % batch, h % height, w % width, ch % channels); - } - float BroadcastGet(uint b, uint2 pos, uint ch) - { - return BroadcastGet(b, pos.y, pos.x, ch); - } - float BroadcastGet(uint b, uint i) - { - return Get(b % GetFlatHeight(), i % GetFlatWidth()); - } - - float ClampGet(int b, int2 pos, int ch, int2 pad = int2(0,0)) - { - b = clamp(b, 0, (int)batch - 1); - pos = clamp(pos, pad, int2(width, height) + pad - 1); - ch = clamp(ch, 0, (int)channels - 1); - - pos -= pad; - return Get(b, pos.y, pos.x, ch); - } - float ClampGet(int b, int h, int w, int ch, int2 pad = int2(0,0)) - { - return ClampGet(b, int2(w, h), ch, pad); - } - float ClampGet(int b, int i) - { - b = clamp(b, 0, (int)batch - 1); - i = clamp(i, 0, (int)(height * width * channels) - 1); - return Get(b,i); - } - float ClampGet(int i) - { - i = clamp(i, 0, (int)(batch * height * width * channels) - 1); - return FastGet(i); - } - - float SafeGetHW(uint b, uint h, uint w, uint c, float def = 0.0f) - { - return (h >= height || w >= width) ? def : Get(b, min(h, height-1), min(w, width-1), c); - } - float SafeGet(uint b, uint2 pos, uint ch, uint2 pad, float def = 0) - { - bool cond = - (b >= batch || ch >= channels || - any(pos < pad) || - any(pos >= uint2(width, height) + pad)); - - if (cond) - return def; - else - return Get(b, pos - pad, ch); - } - float SafeGet(uint b, uint2 pos, uint ch, float def = 0) - { - bool cond = - (b >= batch || ch >= channels || - any(pos >= uint2(width, height))); - - if (cond) - return def; - else - return Get(b, pos, ch); - } - float SafeGet(uint b, uint h, uint w, uint ch, uint2 pad, float def = 0) - { - return SafeGet(b, uint2(w, h), ch, pad, def); - } - float SafeGet(uint b, uint h, uint w, uint ch, float def = 0) - { - return SafeGet(b, uint2(w, h), ch, def); - } - float SafeGet(uint b, uint i, float def = 0) - { - if (b >= batch || i >= height * width * channels) - return def; - else - return Get(b,i); - } - float SafeGet(uint i, float def = 0) - { - if (i >= batch * height * width * channels) - return def; - else - return FastGet(i); - } - - float MaskedGet(bool cond, uint i, float def = 0) - { - if (cond) - return FastGet(i); - else - return def; - } - - uint GetChannelFromIndex(uint index) - { - #if CHANNELS_FIRST - index /= height*width; - #endif - return index % channels; - } -}; - -struct ReadWriteTensor : Tensor -{ - RWStructuredBuffer data; - - void Init(int4 nhwc, RWStructuredBuffer data_) - { - Tensor::Init(nhwc); - data = data_; - } - - float Get(uint b, uint h, uint w, uint ch) - { - #if CHANNELS_FIRST - uint index = IndexCHW(b,h,w,ch); - #else - uint index = IndexHWC(b,h,w,ch); - #endif - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_READWRITE_READ); - return value; - } - float Get(uint b, uint2 pos, uint ch) - { - return Get(b, pos.y, pos.x, ch); - } - float Get(uint b, uint i) - { - uint index = Index(b,i); - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_READWRITE_READ); - return value; - } - float FastGet(uint i) - { - float value; - TENSOR_READ(value, i, KERNEL_ASSERT_CONTEXT_READWRITE_READ); - return value; - } - - float BroadcastGet(uint b, uint h, uint w, uint ch) - { - return Get(b % batch, h % height, w % width, ch % channels); - } - float BroadcastGet(uint b, uint2 pos, uint ch) - { - return BroadcastGet(b, pos.y, pos.x, ch); - } - float BroadcastGet(uint b, uint i) - { - return Get(b % GetFlatHeight(), i % GetFlatWidth()); - } - - float SafeGet(uint b, uint2 pos, uint ch, uint2 pad, float def = 0) - { - bool cond = - (b >= batch || ch >= channels || - any(pos < pad) || - any(pos >= uint2(width, height) + pad)); - - if (cond) - return def; - else - return Get(b, pos - pad, ch); - } - float SafeGet(uint b, uint h, uint w, uint ch, uint2 pad, float def = 0) - { - return SafeGet(b, uint2(w, h), ch, pad, def); - } - float SafeGet(uint b, uint i, float def = 0) - { - if (b >= batch || i >= height * width * channels) - return def; - else - return Get(b,i); - } - float SafeGet(uint i, float def = 0) - { - if (i >= batch * height * width * channels) - return def; - else - return FastGet(i); - } - - float MaskedGet(bool cond, uint i, float def=0) - { - if (cond) - return FastGet(i); - else - return def; - } - - void Set(uint b, uint h, uint w, uint ch, float v) - { - #if CHANNELS_FIRST - uint index = IndexCHW(b,h,w,ch); - #else - uint index = IndexHWC(b,h,w,ch); - #endif - TENSOR_WRITE(v, index, KERNEL_ASSERT_CONTEXT_READWRITE_WRITE); - } - void Set(uint b, uint2 pos, uint ch, float v) - { - Set(b, pos.y, pos.x, ch, v); - } - void Set(uint b, uint i, uint ch, float v) - { - #if CHANNELS_FIRST - uint index = IndexCHW(b, i, ch); - #else - uint index = IndexHWC(b, i, ch); - #endif - TENSOR_WRITE(v, index, KERNEL_ASSERT_CONTEXT_READWRITE_WRITE); - } - void Set(uint y, uint x, float v) - { - data[Index(y,x)] = v; - } - void FastSet(uint i, float v) - { - TENSOR_WRITE(v, i, KERNEL_ASSERT_CONTEXT_READWRITE_WRITE); - } - - void SetWithActivation(uint b, uint h, uint w, uint ch, float v) - { - v = ApplyFusedActivation(v); - Set(b,h,w,ch,v); - } - void SetWithActivation(uint b, uint2 pos, uint ch, float v) - { - v = ApplyFusedActivation(v); - Set(b,pos,ch,v); - } - void SetWithActivation(uint b, uint i, uint ch, float v) - { - v = ApplyFusedActivation(v); - Set(b,i,ch,v); - } - void SetWithActivation(uint y, uint x, float v) - { - v = ApplyFusedActivation(v); - Set(y,x,v); - } - void FastSetWithActivation(uint i, float v) - { - v = ApplyFusedActivation(v); - FastSet(i,v); - } -}; - -struct SharedTensor : Tensor -{ - StructuredBuffer data; - uint offset; - - void Init(uint4 nhwc, uint4 info, StructuredBuffer data_) - { - Tensor::Init(nhwc); - data = data_; - offset = info.x; - } - - float Get(uint b, uint h, uint w, uint ch) - { - uint index = IndexHWC(b,h,w,ch) + offset; - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_SHARED_READ); - return value; - } - float Get(uint b, uint2 pos, uint ch) - { - return Get(b, pos.y, pos.x, ch); - } - float Get(uint b, uint i) - { - uint index = Index(b,i) + offset; - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_SHARED_READ); - return value; - } - float FastGet(uint i) - { - float value; - TENSOR_READ(value, i + offset, KERNEL_ASSERT_CONTEXT_SHARED_READ); - return value; - } - - float BroadcastGet(uint b, uint h, uint w, uint ch) - { - return Get(b % batch, h % height, w % width, ch % channels); - } - float BroadcastGet(uint b, uint2 pos, uint ch) - { - return BroadcastGet(b, pos.y, pos.x, ch); - } - float BroadcastGet(uint b, uint i) - { - return Get(b % GetFlatHeight(), i % GetFlatWidth()); - } - float FastBroadcastGet(uint i) - { - uint index = i % GetFlatWidth() + offset; - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_SHARED_READ); - return value; - } - - float SafeGet(uint b, uint2 pos, uint ch, uint2 pad, float def = 0) - { - if (b >= batch || ch >= channels || - any(pos < pad) || - any(pos >= uint2(width, height) + pad)) - { - return def; - } - else - return Get(b, pos - pad, ch); - } - float SafeGet(uint b, uint h, uint w, uint ch, uint2 pad, float def = 0) - { - return SafeGet(b, uint2(w, h), ch, pad, def); - } - float SafeGet(uint b, uint i, float def = 0) - { - if (b >= batch || i >= height * width * channels) - return def; - else - return Get(b,i); - } - float SafeGet(uint i, float def = 0) - { - if (i >= batch * height * width * channels) - return def; - else - return FastGet(i); - } - - float MaskedGet(bool cond, uint i, float def=0) - { - if (cond) - return FastGet(i); - else - return def; - } -}; - -#define INDEX_HELPER_5D \ -uint IndexNCDHW(uint n, uint d, uint h, uint w, uint c)\ -{\ - KERNEL_ASSERT(sequenceLength==1);\ - KERNEL_ASSERT(numberOfDirections==1);\ - KERNEL_ASSERT(extraDimension==1);\ - uint index =\ - n * channels * depth * height * width +\ - c * depth * height * width +\ - d * height * width +\ - h * width +\ - w;\ - return index;\ -}\ -uint IndexNDHWC(uint n, uint d, uint h, uint w, uint c)\ -{\ - KERNEL_ASSERT(sequenceLength==1);\ - KERNEL_ASSERT(numberOfDirections==1);\ - KERNEL_ASSERT(extraDimension==1);\ - uint index =\ - n * depth * height * width * channels +\ - d * height * width * channels +\ - h * width * channels +\ - w * channels +\ - c;\ - return index;\ -} - -#define INDEX_HELPER_8D \ -uint IndexSRNCTDHW(uint s, uint r, uint n, uint t, uint d, uint h, uint w, uint c)\ -{\ - uint index =\ - s * numberOfDirections * batch * channels * extraDimension * depth * height * width +\ - r * batch * channels * extraDimension * depth * height * width +\ - n * channels * extraDimension * depth * height * width +\ - c * extraDimension * depth * height * width +\ - t * depth * height * width +\ - d * height * width +\ - h * width +\ - w;\ -\ - return index;\ -}\ -uint IndexSRNTDHWC(uint s, uint r, uint n, uint t, uint d, uint h, uint w, uint c)\ -{\ - uint index =\ - s * numberOfDirections * batch * extraDimension * depth * height * width * channels +\ - r * batch * extraDimension * depth * height * width * channels +\ - n * extraDimension * depth * height * width * channels +\ - t * depth * height * width * channels +\ - d * height * width * channels +\ - h * width * channels +\ - w * channels +\ - c;\ -\ - return index;\ -}\ -uint GetFlatWidth8D()\ -{\ - return extraDimension * depth * height * width * channels;\ -} - -struct SharedTensor8D : SharedTensor -{ - uint sequenceLength, numberOfDirections, extraDimension, depth; - - void Init(uint4 nhwc, uint4 srtd, uint4 info, StructuredBuffer data_) - { - SharedTensor::Init(nhwc, info, data_); - sequenceLength = srtd.x; - numberOfDirections = srtd.y; - extraDimension = srtd.z; - depth = srtd.w; - } - - uint GetKernelSpatialDepth() - { - // kernels storage: {1,kernelSpatialDepth,kernel_width,1,1,kernel_height,kernel_channels,kernel_count} - uint kernelSpatialDepth = numberOfDirections; - return kernelSpatialDepth; - } - - uint GetLength5D() - { - return GetKernelSpatialDepth()*GetLength(); - } - - float GetKernel5D(uint d, uint w, uint h, uint c, uint k) - { - KERNEL_ASSERT(sequenceLength==1); - KERNEL_ASSERT(extraDimension==1); - KERNEL_ASSERT(depth==1); - // kernels storage: {1,kernelSpatialDepth,kernel_width,1,1,kernel_height,kernel_channels,kernel_count} - uint index = d * batch * height * width * channels + IndexHWC(w,h,c,k) + offset; - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_SHARED_READ); - return value; - } - - float Get8D(uint s, uint r, uint n, uint t, uint d, uint h, uint w, uint c) - { - uint index = IndexSRNTDHWC(s,r,n,t,d,h,w,c) + offset; - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_SHARED_READ); - return value; - } - - float BroadcastGet8D(uint s, uint r, uint n, uint t, uint d, uint h, uint w, uint c) - { - return Get8D(s % sequenceLength, r % numberOfDirections, n % batch, t % extraDimension, d % depth, h % height, w % width, c % channels); - } - - INDEX_HELPER_8D -}; - -struct ReadonlyTensor8D : ReadonlyTensor -{ - //8D memory layout SRNTDHWC (channelLast) or SRNCTDHW (channelFirst) - uint sequenceLength, numberOfDirections, extraDimension, depth; - - void Init(uint4 nhwc, uint4 srtd, StructuredBuffer data_) - { - ReadonlyTensor::Init(nhwc, data_); - sequenceLength = srtd.x; - numberOfDirections = srtd.y; - extraDimension = srtd.z; - depth = srtd.w; - } - - float SafeGet5D(uint b, uint3 pos, uint ch, uint3 pad, float def = 0) - { - KERNEL_ASSERT(sequenceLength==1); - KERNEL_ASSERT(numberOfDirections==1); - KERNEL_ASSERT(extraDimension==1); - bool cond = - (b >= batch || ch >= channels || - any(pos < pad) || - any(pos >= uint3(width, height, depth) + pad)); - - if (cond) - return def; - else - return Get5D(b, pos - pad, ch); - } - - float ClampGet5D(int b, int3 pos, int ch, int3 pad = int3(0,0,0)) - { - KERNEL_ASSERT(sequenceLength==1); - KERNEL_ASSERT(numberOfDirections==1); - KERNEL_ASSERT(extraDimension==1); - b = clamp(b, 0, (int)batch - 1); - pos = clamp(pos, pad, int3(width, height, depth) + pad - 1); - ch = clamp(ch, 0, (int)channels - 1); - - pos -= pad; - return Get5D(b, pos.z, pos.y, pos.x, ch); - } - - float BroadcastGet8D(uint s, uint r, uint n, uint t, uint d, uint h, uint w, uint c) - { - return Get8D(s % sequenceLength, r % numberOfDirections, n % batch, t % extraDimension, d % depth, h % height, w % width, c % channels); - } - - float Get8D(uint s, uint r, uint n, uint t, uint d, uint h, uint w, uint c) - { - #if CHANNELS_FIRST - uint index = IndexSRNCTDHW(s,r,n,t,d,h,w,c); - #else - uint index = IndexSRNTDHWC(s,r,n,t,d,h,w,c); - #endif - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_READONLY_READ); - return value; - } - - float Get8D(uint b, uint i) - { - uint index = b * extraDimension * depth * height * width * channels + i; - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_READONLY_READ); - return value; - } - - float Get5D(uint n, uint3 pos, uint ch) - { - return Get5D(n, pos.z, pos.y, pos.x, ch); - } - - float Get5D(uint n, uint d, uint h, uint w, uint ch) - { - #if CHANNELS_FIRST - uint index = IndexNCDHW(n,d,h,w,ch); - #else - uint index = IndexNDHWC(n,d,h,w,ch); - #endif - float value; - TENSOR_READ(value, index, KERNEL_ASSERT_CONTEXT_READONLY_READ); - return value; - } - - INDEX_HELPER_5D - INDEX_HELPER_8D -}; - -struct ReadWriteTensor8D : ReadWriteTensor -{ - uint sequenceLength, numberOfDirections, extraDimension, depth; - - void Init(int4 nhwc, uint4 srtd, RWStructuredBuffer data_) - { - ReadWriteTensor::Init(nhwc, data_); - sequenceLength = srtd.x; - numberOfDirections = srtd.y; - extraDimension = srtd.z; - depth = srtd.w; - } - - void Set5D(uint n, uint d, uint h, uint w, uint ch, float v) - { - #if CHANNELS_FIRST - uint index = IndexNCDHW(n,d,h,w,ch); - #else - uint index = IndexNDHWC(n,d,h,w,ch); - #endif - TENSOR_WRITE(v, index, KERNEL_ASSERT_CONTEXT_READWRITE_WRITE); - } - - void Set8D(uint s, uint r, uint n, uint t, uint d, uint h, uint w, uint ch, float v) - { - #if CHANNELS_FIRST - uint index = IndexSRNCTDHW(s,r,n,t,d,h,w,ch); - #else - uint index = IndexSRNTDHWC(s,r,n,t,d,h,w,ch); - #endif - TENSOR_WRITE(v, index, KERNEL_ASSERT_CONTEXT_READWRITE_WRITE); - } - - void Set8D(uint b, uint i, float v) - { - uint index = b * GetFlatWidth8D() + i; - TENSOR_WRITE(v, index, KERNEL_ASSERT_CONTEXT_READWRITE_WRITE); - } - - void Set5DWithActivation(uint n, uint d, uint h, uint w, uint ch, float v) - { - v = ApplyFusedActivation(v); - Set5D(n,d,h,w,ch,v); - } - - INDEX_HELPER_5D - INDEX_HELPER_8D -}; - -#if CHANNELS_FIRST - #define KERNEL_FUNC(name) name##_NCHW -#else - #define KERNEL_FUNC(name) name##_NHWC -#endif - -#define TENSOR_DECL(X) uint4 X##declShape; uint4 X##declInfo; StructuredBuffer X##data; uint4 X##declShape8D; -#define TENSOR_DECL_RW(X) uint4 X##declShape; uint4 X##declInfo; RWStructuredBuffer X##data; uint4 X##declShape8D; - -// readonly with channel order support (for inputs). -#define TENSOR_ARG(X) ReadonlyTensor X; X.Init(X##declShape, X##data); -#define TENSOR_ARG_8D(X) ReadonlyTensor8D X; X.Init(X##declShape, X##declShape8D, X##data); -// readonly with offset, no channel order support (for weights and biases). -#define TENSOR_MODEL(X) SharedTensor X; X.Init(X##declShape, X##declInfo, X##data); -#define TENSOR_MODEL_8D(X) SharedTensor8D X; X.Init(X##declShape, X##declShape8D, X##declInfo, X##data); -// read/write with channel order support (for outputs). -#define TENSOR_ARG_RW(X) ReadWriteTensor X; X.Init(X##declShape, X##data); -#define TENSOR_ARG_8D_RW(X) ReadWriteTensor8D X; X.Init(X##declShape, X##declShape8D, X##data); - -#define TENSOR_ARGS2(X, O) TENSOR_ARG(X); TENSOR_ARG_RW(O); -#define TENSOR_ARGS3(X, A, O) TENSOR_ARG(X); TENSOR_MODEL(A); TENSOR_ARG_RW(O); -#define TENSOR_TWOINPUTS(X, X1, O) TENSOR_ARG(X); TENSOR_ARG(X1); TENSOR_ARG_RW(O); -#define TENSOR_THREEINPUTS(X, X1, X2, O) TENSOR_ARG(X); TENSOR_ARG(X1); TENSOR_ARG(X2); TENSOR_ARG_RW(O); -#define TENSOR_ARGS4(X, A, B, O) TENSOR_ARG(X); TENSOR_MODEL(A); TENSOR_MODEL(B); TENSOR_ARG_RW(O); - -#define TENSOR_ARGS2_8D(X, O) TENSOR_ARG_8D(X); TENSOR_ARG_8D_RW(O); -#define TENSOR_ARGS3_8D(X, A, O) TENSOR_ARG_8D(X); TENSOR_MODEL_8D(A); TENSOR_ARG_8D_RW(O); -#define TENSOR_TWOINPUTS_8D(X, X1, O) TENSOR_ARG_8D(X); TENSOR_ARG_8D(X1); TENSOR_ARG_8D_RW(O); -#define TENSOR_THREEINPUTS_8D(X, X1, X2, O) TENSOR_ARG_8D(X); TENSOR_ARG_8D(X1); TENSOR_ARG_8D(X2); TENSOR_ARG_8D_RW(O); -#define TENSOR_ARGS4_8D(X, A, B, O) TENSOR_ARG_8D(X); TENSOR_MODEL_8D(A); TENSOR_MODEL_8D(B); TENSOR_ARG_8D_RW(O); - -// shared model tensors -#define TENSOR_SHARED_MODEL(X, S) SharedTensor X; X.Init(X##declShape, X##declInfo, S##data); -#define TENSOR_SHARED_MODEL_8D(X, S) SharedTensor8D X; X.Init(X##declShape, X##declShape8D, X##declInfo, S##data); -#define TENSOR_SHARED2_ARGS4(X, A, B, S, O) TENSOR_ARG(X); TENSOR_SHARED_MODEL(A, S); TENSOR_SHARED_MODEL(B, S); TENSOR_ARG_RW(O); -#define TENSOR_SHARED2_ARGS4_8D(X, A, B, S, O) TENSOR_ARG_8D(X); TENSOR_SHARED_MODEL_8D(A, S); TENSOR_SHARED_MODEL_8D(B, S); TENSOR_ARG_8D_RW(O); - - -// Purely informational - declares contract between caller of Dispatch() and kernel -// Temporarily disabled due to failure in shader preprocessor in 2020.2 -// @TODO: reenable -//#define DISPATCH_ARGS(threadGroupsX, threadGroupsY, threadGroupsZ) - - -// @TODO: move all code below into a separate and appropriately named file(s) -// -#define FLT_MAX 3.402823466e+38F -#define FLT_EPSILON 1e-6 - -float fastfma(float a, float b, float c) -{ - return dot(float2(a,c), float2(b, 1)); -} - -// Neumaier's improved Kahan–Babuška algorithm for compensated summation -// see: https://en.wikipedia.org/wiki/Kahan_summation_algorithm -float neumaierAdd(float sum, float value, inout float floatingPointAccuracyCompensation) -{ - float newSum = sum + value; - if (abs(sum) >= abs(value)) - floatingPointAccuracyCompensation += (sum - newSum) + value; - else - floatingPointAccuracyCompensation += (value - newSum) + sum; - return newSum; -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Tensor.cginc.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Tensor.cginc.meta deleted file mode 100644 index c611dd0..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Tensor.cginc.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 5761abd87a16940b2a81aaa755787fc9 -timeCreated: 1506540305 -licenseType: Pro -ShaderImporter: - defaultTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/TextureUtils.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/TextureUtils.compute deleted file mode 100644 index 25d04a3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/TextureUtils.compute +++ /dev/null @@ -1,158 +0,0 @@ -#pragma kernel TextureToTensor_NHWC CHANNELS_FIRST=0 -#pragma kernel TextureToTensor_NCHW CHANNELS_FIRST=1 -#pragma kernel TensorToTextureNoLUT_NHWC SUFFIX=NoLUT CHANNELS_FIRST=0 -#pragma kernel TensorToTextureNoLUT_NCHW SUFFIX=NoLUT CHANNELS_FIRST=1 -#pragma kernel TensorToTexture3DLUT_NHWC SUFFIX=3DLUT APPLY_3D_LUT=1 CHANNELS_FIRST=0 -#pragma kernel TensorToTexture3DLUT_NCHW SUFFIX=3DLUT APPLY_3D_LUT=1 CHANNELS_FIRST=1 - -#include "Tensor.cginc" - -#if CHANNELS_FIRST - #define FUNC_NAME_CALL(KERNEL, SUFFIX) KERNEL##SUFFIX##_NCHW -#else - #define FUNC_NAME_CALL(KERNEL, SUFFIX) KERNEL##SUFFIX##_NHWC -#endif -#define FUNC_NAME(KERNEL, SUFFIX) FUNC_NAME_CALL(KERNEL, SUFFIX) - -TENSOR_DECL(X) -TENSOR_DECL(W) -TENSOR_DECL(K) -TENSOR_DECL(B) -TENSOR_DECL_RW(O) - -uint4 _Pad; -uint4 _Pool; -uint4 _Stride; -uint4 _ChannelWriteMask; -uint _Axis; -float _Alpha; -float _Beta; -float _Epsilon; -float _Seed; -int _IsFirstDispatch; - -Texture2D Xtex2D; -Texture3D Xtex3D; -Texture2DArray Xtex2DArray; -SamplerState samplerXtex2D { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; -SamplerState samplerXtex3D { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; AddressW = Clamp; }; -SamplerState samplerXtex2DArray { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; - -RWTexture2D Otex2D; -RWTexture3D Otex3D; -RWTexture2DArray Otex2DArray; - -float4 _Scale; -float4 _Bias; -float2 _LutParams; -bool _FlipY; -int4 _ChannelReadMap; - -// TODO: call TextureToTensor(v, dispatchThreadID) from Tex2DToTensor() { v = Xtex2D.SampleLevel } -[numthreads(8,8,1)] -void KERNEL_FUNC(TextureToTensor)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_ARG_RW(O); - - uint b = _Pad.x; - uint x = dispatchThreadID.x + _Pad.y; - uint y = dispatchThreadID.y + _Pad.z; - uint c = dispatchThreadID.z + _Pad.w; - - if (y >= O.height || x >= O.width) - return; - - // calculate texture coordinates: - // offset by 0.5 to get texel centers - // divide by texture resolution (_Pool) - float3 uvw = (float3)dispatchThreadID + float3(0.5f, 0.5f, 0); - uvw.xy /= _Pool.xy; - if (_FlipY) - uvw.y = 1 - uvw.y; - - float4 v = Xtex2D.SampleLevel(samplerXtex2D, uvw.xy, 0); - //texArray.SampleLevel(smpArray, loc, 0); - - bool specialCaseWhenChannelMaskIsEmptyStoresAverage = true; - for (int i = 0; i < 4; ++i) - { - if (_ChannelWriteMask[i] == 1) - { - int readFrom = _ChannelReadMap[i]; - float value = i < 3 ? 0 : 1; // default values for channels R,G,B=0 and A=1 - float scale = 1.0f; - float bias = 0.0f; - if (readFrom >= 0) - { - value = v[readFrom]; - scale = _Scale[readFrom]; - bias = _Bias[readFrom]; - } - - O.Set(b, y, x, c, scale*value+bias); - specialCaseWhenChannelMaskIsEmptyStoresAverage = false; - c += 1; - } - } - - if (specialCaseWhenChannelMaskIsEmptyStoresAverage) - { - v = _Scale * v + _Bias; - float avg = (v.r + v.g + v.b) / 3.0f; - O.Set(b, y, x, c, avg); - } -} - -[numthreads(8,8,1)] -void FUNC_NAME(TensorToTexture,SUFFIX)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - TENSOR_ARG(X); - - uint b = _Pad.x; - uint x = dispatchThreadID.x + _Pad.y; - uint y = dispatchThreadID.y + _Pad.z; - uint c = dispatchThreadID.z + _Pad.w; - - if (y >= X.height || x >= X.width) - return; - - if (_FlipY) - y = X.height - 1 - y; - - float4 v = 0; - - int channelRemainder = X.channels - c; - if (channelRemainder == 1) - { - // broadcast to all channels - v = _Scale.x * X.Get(b, y, x, c) + _Bias.x; - } - else if (channelRemainder == 2) - { - v.r = _Scale.x * X.Get(b, y, x, c+0) + _Bias.x; - v.g = _Scale.y * X.Get(b, y, x, c+1) + _Bias.y; - v.b = 0; - v.a = 1; - } - else if (channelRemainder == 3) - { - v.r = _Scale.x * X.Get(b, y, x, c+0) + _Bias.x; - v.g = _Scale.y * X.Get(b, y, x, c+1) + _Bias.y; - v.b = _Scale.z * X.Get(b, y, x, c+2) + _Bias.z; - v.a = 1; - } - else if (channelRemainder >= 4) - { - v.r = _Scale.x * X.Get(b, y, x, c+0) + _Bias.x; - v.g = _Scale.y * X.Get(b, y, x, c+1) + _Bias.y; - v.b = _Scale.z * X.Get(b, y, x, c+2) + _Bias.z; - v.a = _Scale.w * X.Get(b, y, x, c+3) + _Bias.w; - } - - #if APPLY_3D_LUT - float3 uvw = v.xyz * _LutParams.yyy * _LutParams.xxx + _LutParams.xxx * 0.5f; - v.xyz = Xtex3D.SampleLevel(samplerXtex3D, uvw, 0).xyz; - #endif - - Otex2D[dispatchThreadID.xy] = v; -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/TextureUtils.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/TextureUtils.compute.meta deleted file mode 100644 index 2729805..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/TextureUtils.compute.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: c79221c743684e04962aa31deb5e14b7 -timeCreated: 1607532036 \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Transpose.compute b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Transpose.compute deleted file mode 100644 index 9e5d6db..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Transpose.compute +++ /dev/null @@ -1,113 +0,0 @@ -#pragma kernel Transpose2D_NHWC CHANNELS_FIRST=0 -#pragma kernel Transpose2D_NCHW CHANNELS_FIRST=1 -#pragma kernel Transpose_NHWC CHANNELS_FIRST=0 -#pragma kernel Transpose_NCHW CHANNELS_FIRST=1 -#pragma kernel Transpose8D - -#include "Tensor.cginc" - -TENSOR_DECL(X) -TENSOR_DECL_RW(O) - -uint4 _Pool; -uint4 _Stride; -uint4 _Pad; -uint4 _ChannelWriteMask; - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Transpose2D)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH ARGS(O.flatWidth, O.flatHeight, 1); - TENSOR_ARGS2(X, O); - - uint x = dispatchThreadID.x; - uint y = dispatchThreadID.y; - - if (x >= O.GetFlatWidth()) return; - if (y >= O.GetFlatHeight()) return; - - uint readX = y; - uint readY = x; - - float v = X.Get(readY, readX); // transposed - O.Set(y, x, v); -} - -[numthreads(4, 4, 4)] -void Transpose8D(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH_ARGS(X.channels, X.width, X.height); in ChannelLast aka SRNTDHWC - //DISPATCH_ARGS(X.width, X.height, X.depth); in ChannelFirst aka SRNCTDHW - TENSOR_ARGS2(X, O); - - uint d0_size = _Pad.x; - uint d1_size = _Pad.y; - uint d2_size = _Pad.z; - uint d3_size = _Pad.w; - uint d4_size = _Pool.x; - uint d5_size = _Pool.y; - uint d6_size = _Pool.z; - uint d7_size = _Pool.w; - - uint outputStrides[8]; - outputStrides[0] = _Stride.x; - outputStrides[1] = _Stride.y; - outputStrides[2] = _Stride.z; - outputStrides[3] = _Stride.w; - outputStrides[4] = _ChannelWriteMask.x; - outputStrides[5] = _ChannelWriteMask.y; - outputStrides[6] = _ChannelWriteMask.z; - outputStrides[7] = _ChannelWriteMask.w; - - uint d7 = dispatchThreadID.x; - uint d6 = dispatchThreadID.y; - uint d5 = dispatchThreadID.z; - if (d7 >= d7_size) return; - if (d6 >= d6_size) return; - if (d5 >= d5_size) return; - - uint d5_7offset = d5 * d6_size * d7_size + d6 * d7_size + d7; - uint d0_4stride = d5_size * d6_size * d7_size; - uint d0_4offset = 0; - - for (uint d0 = 0; d0 < d0_size; ++d0) - for (uint d1 = 0; d1 < d1_size; ++d1) - for (uint d2 = 0; d2 < d2_size; ++d2) - for (uint d3 = 0; d3 < d3_size; ++d3) - for (uint d4 = 0; d4 < d4_size; ++d4) - { - float value = X.FastGet(d0_4offset + d5_7offset); - O.FastSet(d0 * outputStrides[0] + - d1 * outputStrides[1] + - d2 * outputStrides[2] + - d3 * outputStrides[3] + - d4 * outputStrides[4] + - d5 * outputStrides[5] + - d6 * outputStrides[6] + - d7 * outputStrides[7], value); - - d0_4offset += d0_4stride; - } -} - -[numthreads(4, 4, 4)] -void KERNEL_FUNC(Transpose)(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - //DISPATCH_ARGS(X.channels, X.width, X.height); - TENSOR_ARGS2(X, O); - - uint c = dispatchThreadID.x; - uint x = dispatchThreadID.y; - uint y = dispatchThreadID.z; - - if (c >= X.channels) return; - if (x >= X.width) return; - if (y >= X.height) return; - - for (uint b = 0; b < X.batch; ++b) - { - float v = X.Get(b, y, x, c); - uint4 index = uint4(b, y, x, c); - O.Set(index[_Pool.x], index[_Pool.y], index[_Pool.z], index[_Pool.w], v); - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Transpose.compute.meta b/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Transpose.compute.meta deleted file mode 100644 index 2b22f02..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Resources/Barracuda/Transpose.compute.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 6d7c2d1819c6e4522ae6a9021481e846 -ComputeShaderImporter: - externalObjects: {} - currentAPIMask: 65536 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Tensor.cs b/Packages/com.unity.barracuda/Runtime/Core/Tensor.cs deleted file mode 100644 index afd2f1b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Tensor.cs +++ /dev/null @@ -1,2854 +0,0 @@ -using UnityEngine.Assertions; -using System; -using System.Runtime.InteropServices; -using System.Text; -using Unity.Collections.LowLevel.Unsafe; -using UnityEngine; - -namespace Unity.Barracuda { - -/// -/// TensorShape are immutable representation of a Tensor dimensions and rank. -/// Depending on which constructor is used, the TensorShape will either be rank 8 and channels last (ie NHWC) or actual -/// rank with unnamed tensor dimensions when using the constructor that takes int[]. -/// With legacy use (explicit named constructors) of TensorShape an axis can be of size 1. For example, a tensor -/// without spatial information will be N,1,1,C. With the use of TensorShape via the int[] constructor, then axes can -/// have values of 0. -/// -[Serializable] -public unsafe struct TensorShape -{ - /// - /// Max rank - /// - public const int MaxRank = 8; - - // The following dimension names are based on ONNX Dimension Denotation. - // see: https://github.com/onnx/onnx/blob/master/docs/DimensionDenotation.md - - /// - /// Data channel dimension index number - /// - public const int DataChannel = 7; - /// - /// Channels dimension index number - /// - public const int C = DataChannel; - - /// - /// Data feature 0 dimension index number - /// - public const int DataFeature0 = 6; - /// - /// Width dimension index number - /// - public const int W = DataFeature0; - - /// - /// Data feature 1 dimension index number - /// - public const int DataFeature1 = 5; - /// - /// Height dimension index number - /// - public const int H = DataFeature1; - - /// - /// Data feature 2 dimension index number - /// - public const int DataFeature2 = 4; - /// - /// Depth dimension index number - /// - public const int D = DataFeature2; - - /// - /// Data feature 3 dimension index number - /// - public const int DataFeature3 = 3; - /// - /// Batch dimension index number - /// - public const int DataBatch = 2; - - /// - /// Sequence length dimension index number - /// - public const int NumberOfDirections = 1; - - /// - /// Sequence length dimension index number - /// - public const int SequenceLength = 0; - - /// - /// Data features - /// - public static readonly int[] DataFeatures = { W, H, D, DataFeature3 }; - - /// - /// Kernel input channel dimension - /// - public const int KernelInChannel = 6; - - /// - /// Kernel output channel dimension - /// - public const int KernelOutChannel = 7; - - /// - /// Kernel spatial dimension 0 - /// - public const int KernelSpatial0 = 5; - - /// - /// Kernel spatial dimension 1 - /// - public const int KernelSpatial1 = DataBatch; // NOTE: maps to batch - - /// - /// Kernel spatial dimension 2 - /// - public const int KernelSpatial2 = DataBatch-1; // NOTE: maps to numDirections - - /// - /// Kernel spatial dimension 3 - /// - public const int KernelSpatial3 = SequenceLength; // NOTE: maps to sequenceLength - - /// - /// Kernel spatial dimensions - /// - public static readonly int[] KernelSpatials = { KernelSpatial0, KernelSpatial1, KernelSpatial2, KernelSpatial3 }; - - /// - /// Return the number of sequence. - /// - public int sequenceLength - { - get - { - if (hasNamedDimensions) - { - fixed (int* shape = &d0) - { - int value = shape[SequenceLength]; - return value; - } - } - - return 1; - } - } - - /// - /// Return the number of direction. - /// - public int numberOfDirections - { - get - { - if (hasNamedDimensions) - { - fixed (int* shape = &d0) - { - int value = shape[NumberOfDirections]; - return value; - } - } - - return 1; - } - } - - /// - /// Return the number of batch. - /// - public int batch - { - get - { - if (hasNamedDimensions) - { - fixed (int* shape = &d0) - { - int value = shape[DataBatch]; - return value; - } - } - - return this[0]; - } - } - - /// - /// Return the size of 3rd spatial dimension (axis is DataFeature3) - /// Internal for now, please use myTensorShape[DataFeature3] instead. - /// - internal int extraDimension - { - get - { - if (hasNamedDimensions) - { - fixed (int* shape = &d0) - { - int value = shape[DataFeature3]; - return value; - } - } - - return 1; - } - } - - /// - /// Return the spatial depth (axis is DataFeature2). - /// - public int depth - { - get - { - if (hasNamedDimensions) - { - fixed (int* shape = &d0) - { - int value = shape[DataFeature2]; - return value; - } - } - - return 1; - } - } - - /// - /// Return the spatial height (axis is DataFeature1). - /// - public int height - { - get - { - if (hasNamedDimensions) - { - fixed (int* shape = &d0) - { - int value = shape[DataFeature1]; - return value; - } - } - - return this[1]; - } - } - - /// - /// Return the spatial width (axis is DataFeature0). - /// - public int width - { - get - { - if (hasNamedDimensions) - { - fixed (int* shape = &d0) - { - int value = shape[DataFeature0]; - return value; - } - } - - return this[2]; - } - } - - /// - /// Return the number of channels. - /// - public int channels - { - get - { - if (hasNamedDimensions) - { - fixed (int* shape = &d0) - { - int value = shape[DataChannel]; - return value; - } - } - - return this[3]; - } - } - - // TODO: Use `fixed int m_Shape[MaxRank];` when debugger display works - int d0; - int d1; - int d2; - int d3; - int d4; - int d5; - int d6; - int d7; - - #region Constructors - /// - /// Create a TensorShape of shape [S,R,N,T,D,H,W,C]. - /// Currently seqLen must be 1. - /// - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - public TensorShape(int s, int r, int n, int t, int d, int h, int w, int c) - : this() - { - m_UsesNamedDimensions = NamedDimension.All; - m_Rank = MaxRank; - fixed (int* shape = &d0) - { - shape[SequenceLength] = s > 0 ? s : 1; - shape[NumberOfDirections] = r > 0 ? r : 1; - shape[DataBatch] = n > 0 ? n : 1; - shape[DataFeature3] = t > 0 ? t : 1; - shape[DataFeature2] = d > 0 ? d : 1; - shape[DataFeature1] = h > 0 ? h : 1; - shape[DataFeature0] = w > 0 ? w : 1; - shape[DataChannel] = c > 0 ? c : 1; - } - } - - /// - /// Create a TensorShape of shape [1,1,N,1,D,H,W,C]. - /// - /// batch - /// depth - /// height - /// width - /// channels - public TensorShape(int n, int d, int h, int w, int c) - : this(1, 1, n, 1, d, h, w, c) - { - m_UsesNamedDimensions = NamedDimension.N | NamedDimension.D | NamedDimension.H | NamedDimension.W | NamedDimension.C; - } - - /// - /// Create a TensorShape of shape [1,1,N,1,1,H,W,C]. - /// - /// batch - /// height - /// width - /// channels - public TensorShape(int n, int h, int w, int c) - : this(n, 1, h, w, c) - { - m_UsesNamedDimensions = NamedDimension.N | NamedDimension.H | NamedDimension.W | NamedDimension.C; - } - - /// - /// Create a TensorShape of shape [1,1,N,1,1,1,W,C]. - /// - /// batch - /// width - /// channels - public TensorShape(int n, int w, int c) - : this(n, 1, w, c) - { - m_UsesNamedDimensions = NamedDimension.N | NamedDimension.W | NamedDimension.C; - } - /// - /// Create a TensorShape of shape [1,1,N,1,1,1,1,C]. - /// - /// batch - /// channels - public TensorShape(int n, int c) - : this(n, 1, c) - { - m_UsesNamedDimensions = NamedDimension.N | NamedDimension.C; - } - - /// - /// Create a TensorShape of shape [1,1,N,1,1,1,1,1]. - /// - /// batch - public TensorShape(int n) - : this(n, 1) - { - m_UsesNamedDimensions = NamedDimension.N; - } - - /// - /// Create a TensorShape of arbitrary `shape`. - /// - /// shape as int array - /// create the shape with no specific, named layout - public TensorShape(int[] shape, bool unnamedDimensions = false) - : this() - { - Assert.IsTrue(shape.Length <= MaxRank, $"Only shapes up to a maximum rank of {MaxRank} are supported."); - - if (unnamedDimensions) - { - m_UsesNamedDimensions = NamedDimension.None; - m_Rank = shape.Length; - - if (m_Rank > 0) - { - fixed (int* dst = &d0, src = &shape[0]) - { - UnsafeUtility.MemCpy(dst, src, shape.Length * sizeof(int)); - UnsafeUtility.MemSet(dst + shape.Length, 0, (MaxRank - shape.Length) * sizeof(int)); - } - } - else - { - // Treat a scalar as a rank-1 tensor - m_Rank = 1; - fixed (int* dst = &d0) - { - UnsafeUtility.MemSet(dst, 0, MaxRank * sizeof(int)); - dst[0] = 1; - } - } - } - else - { - TensorShape copy; - - switch (shape.Length) - { - case 0: - // Treat a scalar as a rank-1 tensor - copy = new TensorShape(1); - break; - - case 1: - copy = new TensorShape(shape[0]); - break; - - case 2: - copy = new TensorShape(shape[0], shape[1]); - break; - - case 3: - copy = new TensorShape(shape[0], shape[1], shape[2]); - break; - - case 4: - copy = new TensorShape(shape[0], shape[1], shape[2], shape[3]); - break; - - case 5: - copy = new TensorShape(shape[0], shape[1], shape[2], shape[3], shape[4]); - break; - -#if UNITY_EDITOR - // Restricting this to editor-only since Burst cannot have exceptions, but this code should also not be - // run since there are no rank-6/7 named tensor constructors - case 6: - case 7: - throw new ArgumentException($"Must use unnamedDimensions = true for a rank {shape.Length} tensor"); -#endif - - case 8: - default: - copy = new TensorShape(shape[0], shape[1], shape[2], shape[3], shape[4], shape[5], shape[6], shape[7]); - break; - } - - fixed (TensorShape* dst = &this) - { - UnsafeUtility.CopyStructureToPtr(ref copy, dst); - } - } - } - - #endregion - - #region Properties - - [Flags] - enum NamedDimension : byte - { - S = 1 << SequenceLength, - R = 1 << NumberOfDirections, - N = 1 << DataBatch, - T = 1 << DataFeature3, - D = 1 << DataFeature2, - H = 1 << DataFeature1, - W = 1 << DataFeature0, - C = 1 << DataChannel, - - None = 0, - All = S | R | N | T | D | H | W | C - } - - /// - /// Whether this shape makes use of named dimensions or is nameless. - /// - public bool hasNamedDimensions => m_UsesNamedDimensions != 0; - NamedDimension m_UsesNamedDimensions; - - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel intermediate dimension 0. - /// - public int kernelSpatialDepth => numberOfDirections; - - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel height. - /// - public int kernelHeight => batch; //Use .batch so HWCK weight use 4D constructor for backward compatibility with 4D tensorShape. - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel width. - /// - public int kernelWidth => height; - - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel depth (aka the number of input channels of the associated operator). - /// - public int kernelDepth => width; - - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel count (aka the number of output channels of the associated operator). - /// - public int kernelCount => channels; - - /// - /// Return the number of batch. - /// - public int flatHeight => batch; - - /// - /// Return the T*D*H*W*C. - /// - public int flatWidth - { - get - { - int w = 1; - if (hasNamedDimensions) - { - w = extraDimension * depth * height * width * channels; - return w; - } - - for (int i = 1; i < rank; i++) - { - w *= this[i]; - } - - return w; - } - } - - /// - /// Return the total number of elements represented by this shape. - /// - public int length - { - get - { - int l = 1; - if (hasNamedDimensions) - { - l = sequenceLength * numberOfDirections * flatHeight * flatWidth; - return l; - } - - for (int i = 0; i < rank; i++) - { - l *= this[i]; - } - - return l; - } - } - - /// - /// Always 8 if legacy, named constructors are used otherwise the actual rank. - /// Look also at the `dimensions` property. - /// - public int rank => m_Rank; - int m_Rank; - - /// - /// Return the count of non-unit dimension of this shape. - /// For example [N,1,1,C] dimensions is 2. - /// - public int dimensions - { - get - { - if (hasNamedDimensions) // legacy - return (sequenceLength > 1 ? 1 : 0) + - (numberOfDirections > 1 ? 1 : 0) + - (batch > 1 ? 1 : 0) + - (extraDimension > 1 ? 1 : 0) + - (depth > 1 ? 1 : 0) + - (height > 1 ? 1 : 0) + - (width > 1 ? 1 : 0) + - (channels > 1 ? 1 : 0); - - return rank; - } - } - - #endregion - - #region Helpers - /// - /// Allow to use negative axis to access tensorShape backward. - /// `axis` should be from -rank to rank (exclusive). - /// - /// axis - /// adjusted axis - public int Axis(int axis) - { - Assert.IsTrue(axis > -rank && axis < rank); - return axis >= 0 ? axis: rank + axis; - } - - /// - /// Given an offset in memory return the dimensions indices of the element as [_,_,N,_,_,H,W,C]. - /// - /// one dimensional index (offset) in the memory - /// batch - /// height - /// width - /// channels - public void GetPositionsFromIndex(int index, ref int n, ref int h, ref int w, ref int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - c = index % shape.channels; - w = (index / shape.channels) % shape.width; - h = (index / (shape.channels * shape.width)) % shape.height; - n = (index / (shape.channels * shape.width * shape.height * shape.depth * shape.extraDimension)) % shape.batch; - } - - /// - /// Given an offset in memory return the dimensions indices of the element as [S,R,N,T,D,H,W,C]. - /// - /// one dimensional index (offset) in the memory - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - public void GetPositionsFromIndex(int index, ref int s, ref int r, ref int n, ref int t, ref int d, ref int h, ref int w, ref int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - c = index % shape.channels; - w = (index / shape.channels) % shape.width; - h = (index / (shape.channels * shape.width)) % shape.height; - d = (index / (shape.channels * shape.width * shape.height)) % shape.depth; - t = (index / (shape.channels * shape.width * shape.height * shape.depth)) % shape.extraDimension; - n = (index / (shape.channels * shape.width * shape.height * shape.depth * shape.extraDimension)) % shape.batch; - r = (index / (shape.channels * shape.width * shape.height * shape.depth * shape.extraDimension * shape.batch)) % shape.numberOfDirections; - s = (index / (shape.channels * shape.width * shape.height * shape.depth * shape.extraDimension * shape.batch * shape.numberOfDirections)) % shape.sequenceLength; - } - - /// - /// Given an offset in memory return the dimensions indices of the element as [S,R,N,T,D,H,W,C] in ChannelFirst memory layout. - /// - /// one dimensional index (offset) in the memory - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - internal void GetPositionsFromIndexChannelFirst(int index, ref int s, ref int r, ref int n, ref int t, ref int d, ref int h, ref int w, ref int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - w = index % shape.width; - h = (index / shape.width) % shape.height; - d = (index / (shape.width * shape.height)) % shape.depth; - t = (index / (shape.width * shape.height * shape.depth)) % shape.extraDimension; - c = (index / (shape.width * shape.height * shape.depth * shape.extraDimension)) % shape.channels; - n = (index / (shape.width * shape.height * shape.depth * shape.extraDimension * shape.channels)) % shape.batch; - r = (index / (shape.width * shape.height * shape.depth * shape.extraDimension * shape.channels * shape.batch)) % shape.numberOfDirections; - s = (index / (shape.width * shape.height * shape.depth * shape.extraDimension * shape.channels * shape.batch * shape.numberOfDirections)) % shape.sequenceLength; - } - - /// - /// Given an offset in memory return the dimensions indices of the element as [_,_,N,_,_,H,W,C] in ChannelFirst format. - /// - /// one dimensional index (offset) in the memory - /// batch - /// height - /// width - /// channels - internal void GetPositionsFromIndexChannelFirst(int index, ref int n, ref int h, ref int w, ref int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - w = index % shape.width; - h = (index / shape.width) % shape.height; - c = (index / (shape.width * shape.height * shape.depth * shape.extraDimension)) % shape.channels; - n = (index / (shape.width * shape.height * shape.depth * shape.extraDimension * shape.channels)) % shape.batch; - } - - /// - /// Given an element dimensions indices [0,0,N,0,0,H,W,C] with broadcast support, return this element offset in memory. - /// - /// batch - /// height - /// width - /// channels - /// - public int IndexWithBroadcast(int n, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - n %= shape.batch; - h %= shape.height; - w %= shape.width; - c %= shape.channels; - return Index(n, h, w, c); - } - - /// - /// Given an element dimensions indices [S,R,N,T,D,H,W,C] with broadcast support, return this element offset in memory. - /// - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - public int IndexWithBroadcast(int s, int r, int n, int t, int d, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - s %= shape.sequenceLength; - r %= shape.numberOfDirections; - n %= shape.batch; - t %= shape.extraDimension; - d %= shape.depth; - h %= shape.height; - w %= shape.width; - c %= shape.channels; - return Index(s, r, n, t, d, h, w, c); - } - - /// - /// Given an element dimensions indices [1,N,1,1,1,H,W,C] return this element offset in memory, clamping indices to tensor dimensions. - /// - /// batch - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - public int IndexWithClamp(int n, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - n = Math.Max(n, 0); - h = Math.Max(h, 0); - w = Math.Max(w, 0); - c = Math.Max(c, 0); - n = Math.Min(n, shape.batch - 1); - h = Math.Min(h, shape.height - 1); - w = Math.Min(w, shape.width - 1); - c = Math.Min(c, shape.channels - 1); - return Index(n, h, w, c); - } - - /// - /// Given an element dimensions indices [1,N,1,1,D,H,W,C] return this element offset in memory, clamping indices to tensor dimensions. - /// - /// batch - /// depth - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - public int IndexWithClamp(int n, int d, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - n = Math.Max(n, 0); - d = Math.Max(d, 0); - h = Math.Max(h, 0); - w = Math.Max(w, 0); - c = Math.Max(c, 0); - n = Math.Min(n, shape.batch - 1); - d = Math.Min(d, shape.depth - 1); - h = Math.Min(h, shape.height - 1); - w = Math.Min(w, shape.width - 1); - c = Math.Min(c, shape.channels - 1); - return Index(n, d, h, w, c); - } - - /// - /// Given an element dimensions indices [S,R,N,T,D,H,W,C] return this element offset in memory, clamping indices to tensor dimensions. - /// - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - public int IndexWithClamp(int s, int r, int n, int t, int d, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - s = Math.Max(s, 0); - r = Math.Max(r, 0); - n = Math.Max(n, 0); - t = Math.Max(t, 0); - d = Math.Max(d, 0); - h = Math.Max(h, 0); - w = Math.Max(w, 0); - c = Math.Max(c, 0); - s = Math.Min(s, shape.sequenceLength - 1); - r = Math.Min(r, shape.numberOfDirections - 1); - n = Math.Min(n, shape.batch - 1); - t = Math.Min(t, shape.extraDimension - 1); - d = Math.Min(d, shape.depth - 1); - h = Math.Min(h, shape.height - 1); - w = Math.Min(w, shape.width - 1); - c = Math.Min(c, shape.channels - 1); - return Index(s,r,n,t,d,h,w,c); - } - - /// - /// Given an element dimensions indices [S,R,N,T,D,H,W,C] return this element offset in memory. - /// - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - public int Index(int s, int r, int n, int t, int d, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - int index = - s * shape.numberOfDirections * shape.batch * shape.extraDimension * shape.depth * shape.height * shape.width * shape.channels + - r * shape.batch * shape.extraDimension * shape.depth * shape.height * shape.width * shape.channels + - n * shape.extraDimension * shape.depth * shape.height * shape.width * shape.channels + - t * shape.depth * shape.height * shape.width * shape.channels + - d * shape.height * shape.width * shape.channels + - h * shape.width * shape.channels + - w * shape.channels + - c; - return index; - } - - /// - /// Given an element dimensions indices [0,0,N,0,D,H,W,C] return this element offset in memory. - /// - /// batch - /// depth - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - public int Index(int n, int d, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - int index = - n * shape.extraDimension * shape.depth * shape.height * shape.width * shape.channels + - d * shape.height * shape.width * shape.channels + - h * shape.width * shape.channels + - w * shape.channels + - c; - return index; - } - - /// - /// Given an element dimensions indices [0,0,N,0,0,H,W,C] return this element offset in memory. - /// - /// batch - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - public int Index(int n, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - int index = - n * shape.extraDimension * shape.depth * shape.height * shape.width * shape.channels + - h * shape.width * shape.channels + - w * shape.channels + - c; - return index; - } - - /// - /// Given an element dimensions indices [S,R,N,T,D,H,W,C] return this element offset in memory in ChannelFirst format. - /// - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - internal int IndexChannelFirst(int s, int r, int n, int t, int d, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - int index = - s * shape.numberOfDirections * shape.batch * shape.channels * shape.extraDimension * shape.depth * shape.height * shape.width + - r * shape.batch * shape.channels * shape.extraDimension * shape.depth * shape.height * shape.width + - n * shape.channels * shape.extraDimension * shape.depth * shape.height * shape.width + - c * shape.extraDimension * shape.depth * shape.height * shape.width + - t * shape.depth * shape.height * shape.width + - d * shape.height * shape.width + - h * shape.width + - w; - return index; - } - - /// - /// Given an element dimensions indices [0,0,N,0,0,H,W,C] return this element offset in memory in ChannelFirst format. - /// - /// batch - /// height - /// width - /// channels - /// one dimensional index (offset in the flat memory region) - internal int IndexChannelFirst(int n, int h, int w, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - int index = - n * shape.channels * shape.extraDimension * shape.depth * shape.height * shape.width + - c * shape.extraDimension * shape.depth * shape.height * shape.width + - h * shape.width + - w; - return index; - } - - /// - /// Given an element dimensions indices [0,0,N,0,0,0,0,C] return this element offset in memory. - /// - /// batch - /// channels - /// one dimensional index (offset in the flat memory region) - public int Index(int n, int c) - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - int index = - n * shape.flatWidth + - c; - return index; - } - - /// - /// Indexer to return a dimension of this tensorShape as [S,R,N,T,D,H,W,C] - /// Prefer this over ToArray() to avoid GC allocation/collection. - /// - /// axis - public int this[int axis] - { - get - { - if (axis >= rank) -#if UNITY_EDITOR - throw new IndexOutOfRangeException($"Attempting to access element {axis} from a rank {rank} shape"); -#else - // For Burst we cannot throw exceptions, so just return 0 for now, which will likely cause an error - return 0; -#endif - - // switch case instead of ToArray() avoids GC allocation - if (hasNamedDimensions) - { - switch(axis) - { - case 0: - return sequenceLength; - case 1: - return numberOfDirections; - case 2: - return batch; - case 3: - return extraDimension; - case 4: - return depth; - case 5: - return height; - case 6: - return width; - default: - return channels; - } - } - - fixed (int* shape = &d0) - { - return shape[axis]; - } - } - - internal set - { - if (hasNamedDimensions) - axis = (axis < 0 || axis > 7) ? 7 : axis; - else - axis = Axis(axis); - - if (axis >= rank) -#if UNITY_EDITOR - throw new IndexOutOfRangeException($"Attempting to access element {axis} from a rank {rank} shape"); -#else - // For Burst we cannot throw exceptions - return; -#endif - - fixed (int* shape = &d0) - { - if (hasNamedDimensions) - shape[axis] = value > 0 ? value : 1; - else - shape[axis] = value; - } - } - } - - /// - /// Return an array representation of this tensorShape as [S,R,N,T,D,H,W,C] - /// Prefer tensorShape[x] to avoid GC allocation/collection. - /// - /// shape as int array - public int[] ToArray() - { - int size = rank; - var shape = new int[size]; - if (size > 0) - { - fixed (int* dst = &shape[0], src = &d0) - { - UnsafeUtility.MemCpy(dst, src, size * sizeof(int)); - } - } - else - { - // Treat a scalar as a rank-1 tensor - return new[] { 1 }; - } - - return shape; - } - - /// - /// Remove single-dimensional entries from the shape. - /// [s=1,r=1,b=4,t=1,d=1h=1,w=1,c=128] => [s=1,r=1,b=1,t=1,d=1,h=1,w=4,c=128] - /// - /// new TensorShape - public TensorShape Squeeze() - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - var dims = shape.ToArray(); - - var squeezed = new TensorShape( 1,1,1,1,1,1,1,1 ); - Assert.IsTrue(dims.Length == squeezed.rank); - var index = squeezed.rank; - foreach (var dim in dims) - if (dim > 1) - squeezed[--index] = dim; - return squeezed; - } - - /// - /// Return a TensorShape of dimensions [S,R,N,1,1,1,1,T*D*H*W*C] - /// - /// new TensorShape - public TensorShape Flatten() - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - return new TensorShape(shape.sequenceLength, shape.numberOfDirections, shape.batch, 1, 1, 1, 1, shape.flatWidth); - } - #endregion - - #region Comparison operators - /// - /// Compares two `TensorShape` objects - /// - /// left object - /// right object - /// `true` if contents of the objects `a` and `b` are equal - public static bool operator ==(TensorShape a, TensorShape b) - { - if (a.rank != b.rank) - return false; - - for (var i = 0; i < a.rank; ++i) - { - if (a[i] != b[i]) - return false; - } - - return true; - } - - /// - /// Compares two `TensorShape` objects - /// - /// left object - /// right object - /// `true` if contents of the objects `a` and `b` are not equal - public static bool operator !=(TensorShape a, TensorShape b) - { - return !(a == b); - } - - /// - /// Compares `this` object to other object - /// - /// other object - /// `true` if contents of the objects `a` and `b` are equal - public override bool Equals(System.Object obj) - { - // Check for null values and compare run-time types. - if (obj == null || GetType() != obj.GetType()) - return false; - - return this == (TensorShape)obj; - } - - /// - /// Object hash code - /// - /// object hash code - public override int GetHashCode() - { - var shape = this; - if (!hasNamedDimensions) - shape = AsNamed(); - - return shape.sequenceLength ^ shape.numberOfDirections ^ shape.batch ^ shape.extraDimension ^ shape.depth - ^ shape.height ^ shape.width ^ shape.channels; - } - #endregion - - /// - /// Object summary - /// - /// object summary as a string - public override string ToString() - { - if (rank == 0) - return "()"; - - if (hasNamedDimensions) - { - int b = batch; - int h = height; - int w = width; - int c = channels; - - if (this.Is4D()) - { - return $"(n:{b}, h:{h}, w:{w}, c:{c})"; - } - - int s = sequenceLength; - int r = numberOfDirections; - int t = extraDimension; - int d = depth; - - return $"(s:{s}, r:{r}, n:{b}, t:{t}, d:{d}, h:{h}, w:{w}, c:{c})"; - } - else - { - StringBuilder sb = new StringBuilder(); - sb.Append("("); - for (int i = 0; i < rank; i++) - { - if (i != 0) - sb.Append(", "); - sb.Append(this[i]); - } - sb.Append(")"); - return sb.ToString(); - } - } - - public TensorShape AsNamed() - { - if (hasNamedDimensions) -#if UNITY_EDITOR - throw new InvalidOperationException("TensorShape is already in the layout of named dimensions"); -#else - // For Burst we cannot throw exceptions, but this code should not execute anyway - return this; -#endif - - - TensorShape shape; - switch (rank) - { - case 0: - // Treat a scalar as a rank-1 tensor - shape = new TensorShape(1); - break; - - case 1: - shape = new TensorShape(this[0]); - break; - - case 2: - shape = new TensorShape(this[0], this[1]); - break; - - case 3: - shape = new TensorShape(this[0], this[1], this[2]); - break; - - case 4: - shape = new TensorShape(this[0], this[1], this[2], this[3]); - break; - - case 5: - shape = new TensorShape(this[0], this[1], this[2], this[3], this[4]); - break; - -#if UNITY_EDITOR - // Restricting this to editor-only since Burst cannot have exceptions, but this code should also not be - // run since there are no rank-6/7 named tensor constructors - case 6: - case 7: - throw new ArgumentException($"Converting from rank {rank} not supported."); -#endif - - case 8: - default: - shape = new TensorShape(this[0], this[1], this[2], this[3], this[4], this[5], this[6], this[7]); - break; - } - - return shape; - } - - public TensorShape AsUnnamed() - { - if (!hasNamedDimensions) -#if UNITY_EDITOR - throw new InvalidOperationException("TensorShape is already in the layout of unnamed dimensions"); -#else - // For Burst we cannot throw exceptions, but this code should not execute anyway - return this; -#endif - - int size = Burst.Intrinsics.X86.Popcnt.popcnt_u32((UInt32)m_UsesNamedDimensions); - var shape = new int[size]; - - int s = 0; - for (int i = 0; i < MaxRank; i++) - { - if (m_UsesNamedDimensions.HasFlag((NamedDimension)(1 << i))) - shape[s++] = this[i]; - } - - return new TensorShape(shape, true); - } -} -/// -/// Helper structure to iterate over tensor shape -/// -public struct TensorIterator -{ - /// - /// Tensor shape - /// - public readonly TensorShape shape; - private readonly int m_shapeLength; - - /// - /// Index - /// - public int index; - - /// - /// dimension 0 - /// - public int d0; - - /// - /// dimension 1 - /// - public int d1; - - /// - /// dimension 2 - /// - public int d2; - - /// - /// dimension 3 - /// - public int d3; - - /// - /// dimension 4 - /// - public int d4; - - /// - /// dimension 5 - /// - public int d5; - - /// - /// dimension 6 - /// - public int d6; - - /// - /// dimension 7 - /// - public int d7; - - /// - /// Constructs Tensor shape iterator - /// - /// shape - /// starting index - public TensorIterator(TensorShape shape, int index = 0) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - this.shape = shape; - m_shapeLength = shape.length; - this.index = index; - d0 = 0; d1 = 0; d2 = 0; d3 = 0; d4 = 0; d5 = 0; d6 = 0; d7 = 0; - AssignIndexAndInvalidateDimensions(index); - } - - /// - /// Constructs Tensor shape iterator - /// - /// Tensor - /// starting index - public TensorIterator(Tensor tensor, int index = 0) : this(tensor.shape, index) - { - } - - internal void AssignIndexAndInvalidateDimensions(int index) - { - this.index = index; - d0 = 0; d1 = 0; d2 = 0; d3 = 0; d4 = 0; d5 = 0; d6 = 0; d7 = 0; - if (index != 0) - shape.GetPositionsFromIndex(index, - ref d0, ref d1, ref d2, ref d3, ref d4, ref d5, ref d6, ref d7); - } - - /// - /// Next element in the Tensor shape space - /// - public void Next() - { - ++index; - ++d7; - // carry-over chain - if (d7 < shape[7]) return; d7 = 0; ++d6; - if (d6 < shape[6]) return; d6 = 0; ++d5; - if (d5 < shape[5]) return; d5 = 0; ++d4; - if (d4 < shape[4]) return; d4 = 0; ++d3; - if (d3 < shape[3]) return; d3 = 0; ++d2; - if (d2 < shape[2]) return; d2 = 0; ++d1; - if (d1 < shape[1]) return; d1 = 0; ++d0; - } - - /// - /// Advance iterator by `step` - /// - /// step count - public void Advance(int step) - { - index += step; - d7 += step; - Assert.IsTrue(index >= 0); - if (d7 >= shape[7] * 2 || d7 < 0) - { // step is too large and would overflow the carry-over into the next dimension - // or step is negative and would require a borrow from the next dimension - AssignIndexAndInvalidateDimensions(index); - return; - } - - // carry-over chain - if (d7 < shape[7]) return; d7 -= shape[7]; Assert.IsTrue(d7 < shape[7]); ++d6; - if (d6 < shape[6]) return; d6 = 0; ++d5; - if (d5 < shape[5]) return; d5 = 0; ++d4; - if (d4 < shape[4]) return; d4 = 0; ++d3; - if (d3 < shape[3]) return; d3 = 0; ++d2; - if (d2 < shape[2]) return; d2 = 0; ++d1; - if (d1 < shape[1]) return; d1 = 0; ++d0; - } - - /// - /// Is iterator in valid state - /// - /// `true` if iterator is still within shape - public bool IsValid() - { - return index < m_shapeLength; - } - - /// - /// Index in reduced shape - /// - /// reduced shape - /// index - public int IndexInReducedShape(TensorShape reducedShape) - { - int rd0 = Math.Min(d0, reducedShape[0]-1); - int rd1 = Math.Min(d1, reducedShape[1]-1); - int rd2 = Math.Min(d2, reducedShape[2]-1); - int rd3 = Math.Min(d3, reducedShape[3]-1); - int rd4 = Math.Min(d4, reducedShape[4]-1); - int rd5 = Math.Min(d5, reducedShape[5]-1); - int rd6 = Math.Min(d6, reducedShape[6]-1); - int rd7 = Math.Min(d7, reducedShape[7]-1); - return reducedShape.Index(rd0, rd1, rd2, rd3, rd4, rd5, rd6, rd7); - } - - /// - /// Index with replaced `axis` value - /// - /// axis to replace - /// new value for specific axis - /// index - public int IndexWithReplacedAxis(int axis, int newDimensionValue) - { - int nd0 = axis == 0 ? newDimensionValue : d0; - int nd1 = axis == 1 ? newDimensionValue : d1; - int nd2 = axis == 2 ? newDimensionValue : d2; - int nd3 = axis == 3 ? newDimensionValue : d3; - int nd4 = axis == 4 ? newDimensionValue : d4; - int nd5 = axis == 5 ? newDimensionValue : d5; - int nd6 = axis == 6 ? newDimensionValue : d6; - int nd7 = axis == 7 ? newDimensionValue : d7; - return shape.Index(nd0, nd1, nd2, nd3, nd4, nd5, nd6, nd7); - } - - /// - /// Access specific axis value - /// - /// axis - public int this[int axis] - { - get - { - // switch case instead of ToArray() avoids GC allocation - switch(axis) - { - case 0: return d0; - case 1: return d1; - case 2: return d2; - case 3: return d3; - case 4: return d4; - case 5: return d5; - case 6: return d6; - default:return d7; - } - } - } -} - - -// @TODO: most likely Tensor should still be struct - that way passing Tensor as argument into IOps would be safer (no hidden state mods), and Flatten & Reshape could return modified Tensor -// ITensorData & Dispose mechanism should however allow Tensors to share the same ITensorData -/// -/// Multidimensional array-like data storage -/// -public class Tensor : UniqueResourceId, IDisposable, ITensorStatistics -{ - private DataType m_preferredDataType; - private ITensorData m_TensorOnDevice; - private ITensorAllocator m_TensorAllocator; - private float[] m_Cache; - private bool m_CacheIsDirty; - private bool m_Disposed = false; - - public static event Action tensorDisposed; - - #region Debug - - /// - public string name { get; set; } - - /// - /// Return if tensor was already disposed. - /// - internal bool disposed { get { return m_Disposed; } } - #endregion - - /// - /// Return this tensor allocator, see interface `ITensorAllocator`. - /// - public ITensorAllocator allocator { get { return m_TensorAllocator; } } - - #region Shape - - /// - public TensorShape shape { get; private set; } - - /// - public DataType dataType - { - get { - if (m_TensorOnDevice == null) - return m_preferredDataType; - Assert.AreEqual(m_TensorOnDevice.dataType, m_preferredDataType); - return m_TensorOnDevice.dataType; - } - } - - /// - /// Return the number of sequences. - /// - public int sequenceLength { get { return shape.sequenceLength; } } - /// - /// Return the number of directions. - /// - public int numberOfDirections { get { return shape.numberOfDirections; } } - /// - /// Return the number of batches. - /// - public int batch { get { return shape.batch; } } - /// - /// Return the size of 3rd spatial dimension (axis is DataFeature3) - /// Internal for now, please use myTensor.shape[DataFeature3] instead. - /// - internal int extraDimension { get { return shape.extraDimension; } } - /// - /// Return the spatial depth. - /// - public int depth { get { return shape.depth; } } - /// - /// Return the spatial height. - /// - public int height { get { return shape.height; } } - /// - /// Return the spatial width. - /// - public int width { get { return shape.width; } } - /// - /// Return the number of channels. - /// - public int channels { get { return shape.channels; } } - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel spatial depth. - /// - public int kernelSpatialDepth { get { return shape.kernelSpatialDepth; } } - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel spatial width. - /// - public int kernelWidth { get { return shape.kernelWidth; } } - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel spatial height. - /// - public int kernelHeight { get { return shape.kernelHeight; } } - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel depth (aka the number of input channels of the associated operator). - /// - public int kernelDepth { get { return shape.kernelDepth; } } - /// - /// Kernel dimension ordering is [D,H,W,C,K] for efficiency purpose. - /// Return kernel count (aka the number of output channels of the associated operator). - /// - public int kernelCount { get { return shape.kernelCount; } } - /// - /// Return the number of batch. - /// - public int flatHeight { get { return shape.flatHeight; } } - /// - /// Return T*D*H*W*C. - /// - public int flatWidth { get { return shape.flatWidth; } } - /// - /// Return the total number of elements in this tensor. - /// - public int length { get { return shape.length; } } - /// - /// Return the count of non-unit dimension of this tensor shape. - /// For example [1,1,N,1,1,1,1,C] dimensions is 2. - /// - public int dimensions { get { return shape.dimensions; } } - #endregion - - #region Constructors - /// - /// Create a Tensor from a `shape`, an array of data `srcData` and an optional debug `name`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C]. - /// S and R must be 1. - /// `srcData` must be of size `s[0]*s[1]*s[2]*s[3]*s[4]*s[5]*s[6]*s[7]`. - /// - /// shape - /// source data - /// name - public Tensor(int[] shape, float[] srcData, string name = "", bool unnamedDimensions = false) - : this(new TensorShape(shape, unnamedDimensions), srcData, name) {} - - /// - /// Create a Tensor of shape [N,H,W,C], an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `n*h*w*c`. - /// - /// batch - /// height - /// width - /// channels - /// source data - /// name - public Tensor(int n, int h, int w, int c, float[] srcData, string name = "") : this(new TensorShape(n, h, w, c), srcData, name) {} - - /// - /// Create a Tensor of shape [N,1,1,C], an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `n*c`. - /// - /// batch - /// channels - /// source data - /// name - public Tensor(int n, int c, float[] srcData, string name = "") : this(new TensorShape(n, c), srcData, name) {} - - /// - /// Create a Tensor with specified `shape`, an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `shape.length`. - /// - /// shape - /// source data - /// name - public Tensor(TensorShape shape, float[] srcData, string name = "") - { - this.name = name; - this.shape = shape; - tensorOnDevice = new ArrayTensorData(shape); - Assert.IsTrue(srcData.Length >= length); - m_TensorOnDevice.Upload(srcData, shape, 0); - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create a Tensor with specified `shape`, a BarracudaArray of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `shape.length`. - /// - /// shape - /// source data - /// name - public Tensor(TensorShape shape, BarracudaArray srcData, string name = "") - { - this.name = name; - this.shape = shape; - var tensorData = new ArrayTensorData(shape, srcData.Type); - tensorOnDevice = tensorData; - Assert.IsTrue(srcData.Length >= length); - BarracudaArray.Copy(srcData, 0, tensorData.array, 0, shape.length); - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create a Tensor from a `shape`, an array of data `srcData` and an optional name debug `name`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C]. - /// S and R must be 1. - /// `srcData` must be of size `s[0]*s[1]*s[2]*s[3]*s[4]*s[5]*s[6]*s[7]`. - /// - /// shape - /// source data - /// name - public Tensor(int[] shape, float[][] srcData, string name = "", bool unnamedDimensions = false) : this(new TensorShape(shape, unnamedDimensions), srcData, name) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,H,W,C], an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `n*h*w*c`. - /// - /// batch - /// height - /// width - /// channels - /// source data - /// name - public Tensor(int n, int h, int w, int c, float[][] srcData, string name = "") - : this(new TensorShape(n, h, w, c), srcData, name) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,1,1,C], an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `n*c`. - /// - /// batch - /// channels - /// source data - /// name - public Tensor(int n, int c, float[][] srcData, string name = "") : this(new TensorShape(n, c), srcData, name) {} - - /// - /// Create a Tensor with specified `shape`, an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `shape.length`. - /// - /// shape - /// source data - /// name - public Tensor(TensorShape shape, float[][] srcData, string name = "") - { - this.name = name; - this.shape = shape; - var arrayTensorData = new ArrayTensorData(shape); - for (var i = 0; i < Math.Min(flatHeight, srcData.Length); ++i) - { - var src = srcData[i]; - var dstOffset = i * flatWidth; - BarracudaArray.Copy(src, 0, arrayTensorData.array, dstOffset, Math.Min(flatWidth, src.Length)); - } - tensorOnDevice = arrayTensorData; - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - - /// - /// Create a Tensor from a `shape`, an array of data `srcData` and an optional name debug `name`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C]. - /// S and R must be 1. - /// `srcData` must be of size `s[0]*s[1]*s[2]*s[3]*s[4]*s[5]*s[6]*s[7]`. - /// - /// shape - /// source data - /// name - public Tensor(int[] shape, float[,] srcData, string name = "", bool unnamedDimensions = false) - : this(new TensorShape(shape, unnamedDimensions), srcData, name) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,1,1,C], an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `n*c`. - /// - /// batch - /// channels - /// source data - /// name - public Tensor(int n, int c, float[,] srcData, string name = "") : this(new TensorShape(n, c), srcData, name) {} - - /// - /// Create a Tensor with specified `shape`, an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `shape.length`. - /// - /// shape - /// source data - /// name - public Tensor(TensorShape shape, float[,] srcData, string name = "") : this(shape, (Array)srcData, name) {} - - internal Tensor(TensorShape shape, Array srcData, string name = "") - { - this.name = name; - this.shape = shape; - - var numItemToCopy = Math.Min(shape.length, srcData.Length); - float[] tmpArray = new float[numItemToCopy]; - Buffer.BlockCopy(srcData, 0, tmpArray, 0, numItemToCopy*Marshal.SizeOf()); - - var arrayTensorData = new ArrayTensorData(shape); - BarracudaArray.Copy(tmpArray, arrayTensorData.array); - - tensorOnDevice = arrayTensorData; - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create a Tensor from a `shape`, an array of data `srcData` and an optional name debug `name`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C]. - /// S and R must be 1. - /// `srcData` must be of size `s[0]*s[1]*s[2]*s[3]*s[4]*s[5]*s[6]*s[7]`. - /// - /// shape - /// source data - /// name - public Tensor(int[] shape, float[,,,] srcData, string name = "", bool unnamedDimensions = false) - : this(new TensorShape(shape, unnamedDimensions), srcData, name) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,H,W,C], an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `n*h*w*c`. - /// - /// batch - /// height - /// width - /// channels - /// source data - /// name - public Tensor(int n, int h, int w, int c, float[,,,] srcData, string name = "") : this(new TensorShape(n, h, w, c), srcData, name) {} - - /// - /// Create a Tensor with specified `shape`, an array of data `srcData` and an optional debug `name`. - /// `srcData` must be of size `shape.length`. - /// - /// shape - /// source data - /// name - public Tensor(TensorShape shape, float[,,,] srcData, string name = "") : this(shape, (Array)srcData, name) {} - - - /// - /// Create a Tensor from a `shape`, associated ComputeBuffer `srcBuffer` filled with tensor values, and an optional debug `name`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C]. - /// S and R must be 1. - /// `srcBuffer` must be larger than `s[0]*s[1]*s[2]*s[3]*s[4]*s[5]*s[6]*s[7]`. - /// - /// shape - /// source buffer - /// name - public Tensor(int[] shape, ComputeBuffer srcBuffer, string name = "", bool unnamedDimensions = false) - : this(new TensorShape(shape, unnamedDimensions), srcBuffer, name) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,H,W,C], associated ComputeBuffer `srcBuffer` filled with tensor values, and an optional debug `name`. - /// `srcBuffer` must be larger than `n*h*w*c`. - /// - /// batch - /// height - /// width - /// channels - /// source buffer - /// name - public Tensor(int n, int h, int w, int c, ComputeBuffer srcBuffer, string name = "") : this(new TensorShape(n, h, w, c), srcBuffer, name) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,1,1,C], associated ComputeBuffer `srcBuffer` filled with tensor values, and an optional debug `name`. - /// `srcBuffer` must be larger than `n*c`. - /// - /// batch - /// channels - /// source buffer - /// name - public Tensor(int n, int c, ComputeBuffer srcBuffer, string name = "") : this(new TensorShape(n, c), srcBuffer, name) {} - - /// - /// Create a Tensor with specified `shape`, associated ComputeBuffer `srcBuffer` filled with tensor values, and an optional debug `name`. - /// `srcBuffer` must be larger than `shape.length`. - /// - /// shape - /// source buffer - /// name - /// thrown if specified buffer is too small or stride is mismatched - public Tensor(TensorShape shape, ComputeBuffer srcBuffer, string name = "") - { - this.name = name; - this.shape = shape; - if (srcBuffer.count < shape.length) - throw new ArgumentException($"Compute buffer `{name}` capacity is {srcBuffer.count} less than {shape.length} required for shape {shape}"); - if (srcBuffer.stride != 4) - throw new ArgumentException($"Currently only compute buffers with stride of 4 are supported. Compute buffer `{name}` stride is {srcBuffer.stride} instead"); - tensorOnDevice = new ComputeTensorData(srcBuffer, shape, offset:0, name, ComputeInfo.channelsOrder); - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create a Tensor from a texture, shape is [1,1,1,1,1, `texture.height`, `texture.width`, `channels`]. - /// If `channels` is set to -1 (default value), then number of channels in the new Tensor will match the number of channels in the texture. - /// Just like `Texture2D.GetPixels` when reading from LDR texture (RGBA32, ARGB32, RGB24, Alpha8, RG16, R8, etc) this function will remap pixel values from byte values to the range of [0.0 .. 1.0]. Pixel values from HDR textures (such as ARGBFloat or ARGBHalf) will be left unchanged. - /// - /// source texture - /// channels - /// name - public Tensor(Texture srcTexture, int channels = -1, string name = "") : this(new [] { srcTexture }, channels, name) {} - - /// - /// Create a Tensor from multiple texture, shape is [1,1, `srcTextures.length`,1,1, `texture.height`, `texture.width`, `channels`]. - /// If `channels` is set to -1 (default value), then number of channels in the new Tensor will match the number of channels in the texture. - /// Just like `Texture2D.GetPixels` when reading from LDR texture (RGBA32, ARGB32, RGB24, Alpha8, RG16, R8, etc) this function will remap pixel values from byte values to the range of [0.0 .. 1.0]. Pixel values from HDR textures (such as ARGBFloat or ARGBHalf) will be left unchanged. - /// `flipY` flips the texture along the Y direction - /// `scale` and `bias` respectively scale and bias the input texture as so: scale*v+bias - /// - /// source textures - /// flipY - /// scale - /// bias - /// channels - /// name - public Tensor(Texture srcTexture, bool flipY, Vector4 scale, Vector4 bias, int channels = -1, string name = "") : this(new [] { srcTexture }, flipY, false, scale, bias, channels, name) {} - - /// - /// Create a Tensor from multiple texture, shape is [1,1, `srcTextures.length`,1,1, `texture.height`, `texture.width`, `channels`]. - /// If `channels` is set to -1 (default value), then number of channels in the new Tensor will match the number of channels in the texture. - /// All textures must be of the same size and dimension. - /// Just like `Texture2D.GetPixels` when reading from LDR texture (RGBA32, ARGB32, RGB24, Alpha8, RG16, R8, etc) this function will remap pixel values from byte values to the range of [0.0 .. 1.0]. Pixel values from HDR textures (such as ARGBFloat or ARGBHalf) will be left unchanged. - /// - /// source textures - /// channels - /// name - public Tensor(Texture[] srcTextures, int channels = -1, string name = "") - { - this.name = name; - var tensorData = new TextureAsTensorData(srcTextures, channels); - //;;UnityEngine.Debug.Log("Tensor::Tensor " + n + " " + tensorData.shape + " [TEX] " + srcTextures); - shape = tensorData.shape; - Assert.IsTrue(tensorData.maxCapacity >= length); - tensorOnDevice = tensorData; - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create a Tensor from multiple texture, shape is [1,1, `srcTextures.length`,1,1, `texture.height`, `texture.width`, `channels`]. - /// If `channels` is set to -1 (default value), then number of channels in the new Tensor will match the number of channels in the texture. - /// All textures must be of the same size and dimension. - /// Just like `Texture2D.GetPixels` when reading from LDR texture (RGBA32, ARGB32, RGB24, Alpha8, RG16, R8, etc) this function will remap pixel values from byte values to the range of [0.0 .. 1.0]. Pixel values from HDR textures (such as ARGBFloat or ARGBHalf) will be left unchanged. - /// `flipY` flips the texture along the Y direction - /// If `concatOnBatch` is True then the textures are concatenated on the batch dimension : resulting `srcTextures.length`, `texture.height`, `texture.width`, `texture.channels` - /// `scale` and `bias` respectively scale and bias the input texture as so: scale*v+bias - /// - /// source textures - /// flipY - /// concatOnBatch - /// scale - /// bias - /// channels - /// name - public Tensor(Texture[] srcTextures, bool flipY, bool concatOnBatch, Vector4 scale, Vector4 bias, int channels = -1, string name = "") - { - this.name = name; - var tensorData = new TextureAsTensorData(srcTextures, - flipY ? TextureAsTensorData.Flip.Y : TextureAsTensorData.Flip.None, - concatOnBatch ? TextureAsTensorData.InterpretDepthAs.Batch : TextureAsTensorData.InterpretDepthAs.Channels, - TextureAsTensorData.InterpretColorAs.AverageMultipleChannels, - scale, bias, - channels); - //;;UnityEngine.Debug.Log("Tensor::Tensor " + n + " " + tensorData.shape + " [TEX] " + srcTextures); - shape = tensorData.shape; - Assert.IsTrue(tensorData.maxCapacity >= length); - tensorOnDevice = tensorData; - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create a Tensor from a `shape`, an ITensorData `data` and an optional debug `name`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C]. - /// S and R must be 1. - /// - /// shape - /// data - /// name - public Tensor(int[] shape, ITensorData data, string name = "", bool unnamedDimensions = false) - : this(new TensorShape(shape, unnamedDimensions), data, name) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,H,W,C], an ITensorData `data` and an optional debug `name`. - /// `srcData` must be of size `n*h*w*c`. - /// - /// batch - /// height - /// width - /// channels - /// data - /// name - public Tensor(int n, int h, int w, int c, ITensorData data, string name = "") : this(new TensorShape(n, h, w, c), data, name) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,1,1,C], an ITensorData `data` and an optional debug `name`. - /// `srcData` must be of size `n*c`. - /// - /// batch - /// channels - /// data - /// name - public Tensor(int n, int c, ITensorData data, string name = "") : this(new TensorShape(n, c), data, name) {} - - /// - /// Create a Tensor with specified `shape`, an ITensorData `data` and an optional debug `name`. - /// - /// shape - /// data - /// name - public Tensor(TensorShape shape, ITensorData data, string name = "") - { - this.name = name; - this.shape = shape; - tensorOnDevice = data; - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create an uninitialized Tensor with a shape of [1,1,1,1,1,1,1,1] and an optional debug `name`. - /// - /// name - public Tensor(string name = "") : this(new TensorShape(1,1,1,1), name) {} - - /// - /// Create an uninitialized Tensor from a `shape` and an optional debug `name`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C] - /// S and R must be 1. - /// - /// shape - /// name - public Tensor(int[] shape, string name = "", bool unnamedDimensions = false) : this(new TensorShape(shape, unnamedDimensions), name) {} - - /// - /// Create an uninitialized Tensor of shape [1,1,N,1,1,H,W,C] and an optional debug `name`. - /// - /// batch - /// height - /// width - /// channels - /// name - public Tensor(int n, int h, int w, int c, string name = "") : this(new TensorShape(n, h, w, c), name) {} - - /// - /// Create an uninitialized Tensor of shape [1,1,N,1,1,1,1,C] and an optional debug `name`. - /// - /// batch - /// channels - /// name - public Tensor(int n, int c, string name = "") : this(new TensorShape(n, c), name) {} - - /// - /// Create an uninitialized Tensor with specified `shape` and an optional debug `name`. - /// - /// shape - /// name - public Tensor(TensorShape shape, string name = "", DataType dataType = DataType.Float) - { - this.name = name; - this.shape = shape; - m_preferredDataType = dataType; - tensorOnDevice = null; - m_TensorAllocator = null; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create a Tensor from a `shape`, an ITensorData `data` and an ITensorAllocator `allocator`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C]. - /// S and R must be 1. - /// - /// shape - /// data - /// allocator - public Tensor(int[] shape, ITensorData data, ITensorAllocator allocator, bool unnamedDimensions = false) - : this(new TensorShape(shape, unnamedDimensions), data, allocator) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,H,W,C], an ITensorData `data` and an ITensorAllocator `allocator`. - /// `data` must be of size `n*h*w*c`. - /// - /// batch - /// height - /// width - /// channels - /// data - /// allocator - public Tensor(int n, int h, int w, int c, ITensorData data, ITensorAllocator allocator) : this(new TensorShape(n, h, w, c), data, allocator) {} - - /// - /// Create a Tensor of shape [1,1,N,1,1,1,1,C], an ITensorData `data` and an ITensorAllocator `allocator`. - /// `srcData` must be of size `n*c`. - /// - /// batch - /// channels - /// data - /// allocator - public Tensor(int n, int c, ITensorData data, ITensorAllocator allocator) : this(new TensorShape(n, c), data, allocator) {} - - /// - /// Create a Tensor with specified `shape`, an ITensorData `data` and an ITensorAllocator `allocator` - /// - /// shape - /// data - /// allocator - public Tensor(TensorShape shape, ITensorData data, ITensorAllocator allocator, DataType dataType = DataType.Float) - { - Assert.IsTrue(data == null || data.dataType == dataType); - this.name = ""; - this.shape = shape; - m_preferredDataType = dataType; - tensorOnDevice = data; - m_TensorAllocator = allocator; - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Create an uninitialized Tensor with a shape of [1,1,1,1,1,1,1,1] and an ITensorAllocator `allocator`. - /// - /// allocator - public Tensor(ITensorAllocator allocator) : this(new TensorShape(1,1,1,1,1,1,1,1), allocator) {} - - - /// - /// Create an uninitialized Tensor from a `shape` and an ITensorAllocator `allocator`. - /// `shape` must be of size 8, the order is [S,R,N,T,D,H,W,C]. - /// S and R must be 1. - /// - /// shape - /// allocator - public Tensor(int[] shape, ITensorAllocator allocator, bool unnamedDimensions = false) - : this(new TensorShape(shape, unnamedDimensions), allocator) {} - - /// - /// Create an uninitialized Tensor of shape [1,1,N,1,1,H,W,C] and an ITensorAllocator `allocator`. - /// - /// batch - /// height - /// width - /// channels - /// allocator - public Tensor(int n, int h, int w, int c, ITensorAllocator allocator) : this(new TensorShape(n, h, w, c), allocator) {} - - /// - /// Create an uninitialized Tensor of shape [1,1,N,1,1,1,1,C] and an ITensorAllocator `allocator`. - /// - /// batch - /// channels - /// allocator - public Tensor(int n, int c, ITensorAllocator allocator) : this(new TensorShape(n, c), allocator) {} - - /// - /// Create an uninitialized Tensor with specified `shape` and ITensorAllocator `allocator`. - /// - /// shape - /// allocator - public Tensor(TensorShape shape, ITensorAllocator allocator) - { - this.name = ""; - this.shape = shape; - tensorOnDevice = null; - m_TensorAllocator = allocator; - m_Cache = null; - m_CacheIsDirty = false; - } - #endregion - - /// - /// Destructor will also dispose associated memories. - /// - ~Tensor() - { - Dispose(); - } - - private void PinToDevice(ITensorData onDevice, bool disposeUnpinned = true) - { - Assert.IsTrue(onDevice?.maxCapacity >= length || onDevice == null); - - if (m_TensorAllocator != null) - m_TensorAllocator.MoveToDevice(this, onDevice, m_TensorOnDevice, disposeUnpinned); - else if (disposeUnpinned) - m_TensorOnDevice?.Dispose(); - - tensorOnDevice = onDevice; - } - - /// - /// Upload tensor values to the device. - /// This call associates tensor with the uninitialized block of data residing on a device. - /// `destination` should be allocated on a target device. Previous contents of `destination` will be overwritten after this call. - /// By default local cache will be discarded after this call, set `invalidateCacheAfterUpload` to false to keep the cache. - /// - /// destination - /// invalidate cache after upload - public void UploadToDevice(ITensorData destination, bool invalidateCacheAfterUpload = true) - { - if (m_TensorOnDevice == destination && !m_CacheIsDirty) - return; - - PrepareCacheForAccess(); - PinToDevice(destination, disposeUnpinned: true); - - m_CacheIsDirty = true; - if (invalidateCacheAfterUpload) - UploadAndInvalidateCache(); - else - UploadIfDirty(); - } - - /// - /// Upload tensor values to the device. - /// This call allocates `destination` tensor on a target device. Previous contents of `destination` will be overwritten after this call. - /// No content will be copied/initialized from the tensor regardless of the current cache/data on device - /// - /// destination - public void AllocateOnDevice(ITensorData destination) - { - if (m_TensorOnDevice == destination) - return; - - PinToDevice(destination, disposeUnpinned: true); - m_Cache = null; - m_CacheIsDirty = false; - } - - /// - /// Associates tensor with the block of data residing on a device. - /// Tensor values will be downloaded from the `source` upon the first access. - /// `source` should contain initialized and valid data representing tensor values. - /// See also `PrepareCacheForAccess()` to schedule download as soon as possible. - /// - /// source - public void AttachToDevice(ITensorData source) - { - if (m_TensorOnDevice == source && !m_CacheIsDirty) - return; - - UploadIfDirty(); - PinToDevice(source, disposeUnpinned: true); - if (m_Cache != null) - PrepareCacheForAccess(); - } - - /// - /// Remove tensor from device, will first sync the cache with device data. - /// - /// dispose device data - /// Tensor data - public ITensorData DetachFromDevice(bool disposeDeviceData = true) - { - PrepareCacheForAccess(); - - ITensorData unpinned = (disposeDeviceData) ? null : m_TensorOnDevice; - PinToDevice(null, disposeDeviceData); - return unpinned; - } - - private void UploadIfDirty() - { - if (m_CacheIsDirty && m_TensorOnDevice != null) - m_TensorOnDevice.Upload(m_Cache, shape); - m_CacheIsDirty = false; - } - - public void InvalidateCache() - { - // remove cache only, if pinned to device - // otherwise cache holds the only copy of the tensor data and we can not loose it - if (m_TensorOnDevice == null) - return; - - m_Cache = null; - m_CacheIsDirty = false; - } - - private void UploadAndInvalidateCache() - { - UploadIfDirty(); - InvalidateCache(); - } - - /// - /// Populate the cache with on device data. - /// Blocking read if `blocking` is true (default) - /// - /// blocking read if `true` - /// `true` if data is ready - public bool PrepareCacheForAccess(bool blocking = true) - { - // non-blocking, schedule download for later - if (!blocking && m_TensorOnDevice != null && m_Cache == null) - if (!m_TensorOnDevice.ScheduleAsyncDownload(length)) - return false; - - // blocking, have to get data now! - if (m_Cache == null) - { - if (m_TensorOnDevice != null) - m_Cache = m_TensorOnDevice.Download(shape); - else - m_Cache = new float[length]; - m_CacheIsDirty = false; - } - - return true; - } - - /// - /// Upload cache to device memory and delete it. - /// - public void FlushCache(bool uploadCache) - { - if(uploadCache) - UploadAndInvalidateCache(); - else - InvalidateCache(); - } - - // @TODO: choose approach to handle case when tensors after Flatten/Reshape are written into OR taken ownership of - // 1) owns data, copy on PrepareCacheForAccess() and PinForWrite() - // 2) always copy data in Flatten()/Reshape(), remove from Tensor interface - // 2) always copy data in Flatten()/Reshape(), implement ICloneable for GPU ITensorData - - private Tensor ShallowCopy(TensorShape newShape, string newName) - { - Tensor copy; - if (m_TensorAllocator != null) - copy = m_TensorAllocator.Alloc(newShape, m_TensorOnDevice, AllocScope.LayerOutput, dataType); - else - copy = new Tensor(newShape, m_TensorOnDevice, null, dataType); - - copy.name = newName; - copy.m_Cache = m_Cache; - copy.m_CacheIsDirty = m_CacheIsDirty; - - return copy; - } - - /// - /// Create a copy of the current Tensor, sharing data storage with original tensor. - /// - /// new name - /// shallow copy of the Tensor - public Tensor ShallowCopy(string newName = null) - { - return ShallowCopy(shape, newName ?? $"shallowcopy of {name}"); - } - - /// - /// Create a flattened copy of the current Tensor ie of shape [1,1,N,1,1,1,1,T*D*H*W*C] - /// - /// new name - /// shallow copy of the Tensor with new shape - public Tensor Flatten(string newName = null) - { - var newShape = shape.Flatten(); - return ShallowCopy(newShape, newName ?? $"flatten of {name}"); - } - - /// - /// Create a reshaped copy of the current Tensor. - /// `newShape`.length must be equal to this.shape.length. - /// - /// new shape - /// new name - /// shallow copy of the Tensor with new shape and name - public Tensor Reshape(TensorShape newShape, string newName = null) - { - Assert.AreEqual(shape.length, newShape.length); - return ShallowCopy(newShape, newName ?? $"reshape of {name}"); - } - - /// - /// Create a copy of the current Tensor. - /// - /// new copy of the Tensor - public Tensor DeepCopy() - { - // @TODO: use Tensor allocator - var copy = new Tensor(shape, $"clone of {name}"); - if (m_TensorOnDevice is ICloneable) - { - UploadIfDirty(); - var copyOfTensorData = (m_TensorOnDevice as ICloneable).Clone() as ITensorData; - copy.AttachToDevice(copyOfTensorData); - } - else - { - PrepareCacheForAccess(); - copy.PrepareCacheForAccess(); - Array.Copy(m_Cache, 0, copy.m_Cache, 0, length); - } - - return copy; - } - - /// - /// Remove system reference to this tensor, caller assume ownership. - /// - public void TakeOwnership() - { - m_TensorAllocator?.WaiveOwnership(this); - m_TensorAllocator = null; - } - - /// Called from ITensorAllocator, puts Tensor in the ready for reuse state. - internal ITensorData Invalidate() - { - ITensorData unpinned = m_TensorOnDevice; - PinToDevice(null, false); - Assert.AreEqual(m_TensorOnDevice, null); - m_Cache = null; - m_CacheIsDirty = false; - tensorOnDevice = null; - m_TensorAllocator = null; - return unpinned; - } - - internal void Init(TensorShape shape, ITensorData buffer, ITensorAllocator allocator, DataType dataType) - { - Assert.IsTrue(buffer == null || buffer.dataType == dataType); - this.shape = shape; - m_preferredDataType = dataType; - tensorOnDevice = buffer; - m_TensorAllocator = allocator; - m_Disposed = false; - } - - /// - /// Dispose Tensor and associated memories. - /// - public virtual void Dispose() - { - m_Disposing = true; - if (m_TensorAllocator != null) - { - m_TensorAllocator.Release(this, true); - } - else if (m_TensorOnDevice != null) - { - //;;UnityEngine.D.Log("DISPOSE " + name + " " + shape + " @ " + m_TensorOnDevice.GetType().Name); - m_TensorOnDevice.Dispose(); - } - - m_Cache = null; - m_CacheIsDirty = false; - tensorOnDevice = null; - m_TensorAllocator = null; - m_Disposing = false; - m_Disposed = true; - - tensorDisposed?.Invoke(this); - } - - - #region Render Texture - /// - /// Fill a `target` RenderTexture with a portion of the tensor applying `scale` and `bias`. Portion of the target is specified by `batch` and `fromChannel`. - /// `batch` specifies the tensor batch to read values from. - /// `fromChannel` specifies the first tensor channel to start reading values from. - /// Number of channels in the `target` texture specifies how many channels to read from the tensor, starting from index `fromChannel`. - /// Resolution of the `target` must match the spatial dimensions of the tensor. - /// `scale` multiplier and `bias` addition is applied to the values read from the tensor and, if `target` is LDR texture (RGBA32, ARGB32, RGB24, Alpha8, RG16, R8, etc), clamped to the range from 0.0 to 1.0. - /// - /// target RenderTexture - /// batch - /// from channel - /// scale - /// bias - /// lut table - public void ToRenderTexture(RenderTexture target, int batch, int fromChannel, Vector4 scale, Vector4 bias, Texture3D lut = null) - { - if (tensorOnDevice is TextureAsTensorData || !SystemInfo.supportsComputeShaders) - { - var gpuBackend = new PixelShaderOps(null); - gpuBackend.TensorToRenderTexture(this, target, batch, fromChannel, scale, bias, lut); - } - else if (tensorOnDevice is ComputeTensorData) - { - var gpuBackend = new ReferenceComputeOps(null); - gpuBackend.TensorToRenderTexture(this, target, batch, fromChannel, scale, bias, lut); - } - } - - /// - /// Fill a `target` RenderTexture with a portion of the tensor applying `scale` and `bias`. Portion of the target is specified by `batch` and `fromChannel`. - /// `batch` specifies the tensor batch to read values from. - /// `fromChannel` specifies the first tensor channel to start reading values from. - /// Number of channels in the `target` texture specifies how many channels to read from the tensor, starting from index `fromChannel`. - /// Resolution of the `target` must match the spatial dimensions of the tensor. - /// `scale` multiplier and `bias` addition is applied to the values read from the tensor and, if `target` is LDR texture (RGBA32, ARGB32, RGB24, Alpha8, RG16, R8, etc), clamped to the range from 0.0 to 1.0. - /// - /// target RenderTexture - /// batch - /// from channel - /// scale - /// bias - /// lut table - public void ToRenderTexture(RenderTexture target, int batch = 0, int fromChannel = 0, float scale = 1.0f, float bias = 0f, Texture3D lut = null) - { - ToRenderTexture(target, batch, fromChannel, new Vector4(scale,scale,scale,scale), new Vector4(bias,bias,bias,bias), lut); - } - - /// - /// Create new RenderTexture and fill it with a portion of the tensor applying `scale` and `bias`. Portion of the target is specified by `batch` and `fromChannel`. - /// `format` specifies the type of the new RenderTexture. - /// `batch` specifies the tensor batch to read values from. - /// `fromChannel` specifies the first tensor channel to start reading values from. - /// Number of channels in the `target` texture specifies how many channels to read from the tensor, starting from index `fromChannel`. - /// `scale` multiplier and `bias` addition is applied to the values read from the tensor and, if `format` is LDR (RGBA32, ARGB32, RGB24, Alpha8, RG16, R8, etc), clamped to the range from 0.0 to 1.0. - /// - /// RenderTexture format - /// batch - /// from channel - /// scale - /// bias - /// lut table - /// created RenderTexture - public RenderTexture ToRenderTexture(RenderTextureFormat format, int batch = 0, int fromChannel = 0, float scale = 1.0f, float bias = 0f, Texture3D lut = null) - { - var target = new RenderTexture(width, height, 0, format); - ToRenderTexture(target, batch, fromChannel, scale, bias, lut); - return target; - } - - /// - /// Create new RenderTexture and fill it with a portion of the tensor applying `scale` and `bias`. Portion of the target is specified by `batch` and `fromChannel`. - /// `batch` specifies the tensor batch to read values from. - /// `fromChannel` specifies the first tensor channel to start reading values from. - /// Number of channels in the `target` texture specifies how many channels to read from the tensor, starting from index `fromChannel`. - /// Resolution of the `target` must match the spatial dimensions of the tensor. - /// `scale` multiplier and `bias` addition is applied to the values read from the tensor and clamped to the range from 0.0 to 1.0. - /// - /// batch - /// from channel - /// scale - /// bias - /// lut table - /// - public RenderTexture ToRenderTexture(int batch = 0, int fromChannel = 0, float scale = 1.0f, float bias = 0f, Texture3D lut = null) - { - return ToRenderTexture(RenderTextureFormat.Default, batch, fromChannel, scale, bias, lut); - } - #endregion - - - #region Data access - /// - /// Allow to use negative axis to access tensorShape backward. - /// `axis` should be from -rank to rank (exclusive). - /// - /// axis - /// remapped axis - public int Axis(int axis) - { - return shape.Axis(axis); - } - - /// - /// Given an element dimensions indices [0,0,N,0,0,H,W,C] return this element offset in memory. - /// - /// batch - /// height - /// width - /// channels - /// flat index (offset in memory) - public int Index(int b, int h, int w, int ch) - { - return shape.Index(b, h, w, ch); - } - - /// - /// Given an element dimensions indices [0,0,N,0,D,H,W,C] return this element offset in memory. - /// - /// batch - /// depth - /// height - /// width - /// channels - /// - public int Index(int b, int d, int h, int w, int ch) - { - return shape.Index(b, d, h, w, ch); - } - /// - /// Given an element dimensions indices [S,R,N,T,D,H,W,C] return this element offset in memory. - /// - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - /// flat index (offset in memory) - public int Index(int s, int r, int n, int t, int d, int h, int w, int c) - { - return shape.Index(s, r, n, t, d, h, w, c); - } - - /// - /// Given an element dimensions indices [0,0,N,0,0,H,W,C] return this element offset in memory, clamping indices to tensor dimensions. - /// - /// batch - /// height - /// width - /// channels - /// flat index (offset in memory) - public int IndexWithClamp(int n, int h, int w, int c) - { - return shape.IndexWithClamp(n, h, w, c); - } - - /// - /// Given an element dimensions indices [0,0,N,0,D,H,W,C] return this element offset in memory, clamping indices to tensor dimensions. - /// - /// batch - /// depth - /// height - /// width - /// channels - /// flat index (offset in memory) - public int IndexWithClamp(int n, int d, int h, int w, int c) - { - return shape.IndexWithClamp(n, d, h, w, c); - } - /// - /// Given an element dimensions indices[0,0,N,0,0,H,W,C] with broadcast support, return this element offset in memory. - /// - /// batch - /// height - /// width - /// channels - /// flat index (offset in memory) - public int IndexWithBroadcast(int n, int h, int w, int c) - { - return shape.IndexWithBroadcast(n, h, w, c); - } - - /// - /// Given an element dimensions indices [S,R,N,T,D,H,W,C] with broadcast support, return this element offset in memory. - /// - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - /// flat index (offset in memory) - public int IndexWithBroadcast(int s, int r, int n, int t, int d, int h, int w, int c) - { - return shape.IndexWithBroadcast(s,r,n,t,d,h,w,c); - } - /// - /// Given an element dimensions indices [0,0,N,0,0,0,0,C] return this element offset in memory. - /// - /// y - /// x - /// flat index (offset in memory) - public int Index(int y, int x) - { - return shape.Index(y, x); - } - - /// - /// Access element at offset `index` in this Tensor. - /// This will create a blocking read, if this Tensor is a result of a computation on a different device (GPU). - /// - /// flat index - public float this[int index] - { - get { PrepareCacheForAccess(); return m_Cache[index]; } - set { PrepareCacheForAccess(); m_Cache[index] = value; m_CacheIsDirty = true; } - } - - /// - /// Access element at index [0,0,N,0,0,0,0,C] in this Tensor. - /// This will create a blocking read, if this Tensor is a result of a computation on a different device (GPU). - /// - /// batch - /// channels - public float this[int b, int ch] - { - get { PrepareCacheForAccess(); return m_Cache[Index(b, ch)]; } - set { PrepareCacheForAccess(); m_Cache[Index(b, ch)] = value; m_CacheIsDirty = true; } - } - - /// - /// Access element at index [0,0,N,0,0,H,W,C] in this Tensor. - /// This will create a blocking read, if this Tensor is a result of a computation on a different device (GPU). - /// - /// batch - /// height - /// width - /// channels - public float this[int b, int h, int w, int ch] - { - get { PrepareCacheForAccess(); return m_Cache[Index(b, h, w, ch)]; } - set { PrepareCacheForAccess(); m_Cache[Index(b, h, w, ch)] = value; m_CacheIsDirty = true; } - } - /// - /// Access element at index [0,0,N,0,D,H,W,C] in this Tensor. - /// This will create a blocking read, if this Tensor is a result of a computation on a different device (GPU). - /// - public float this[int b, int d, int h, int w, int ch] - { - get { PrepareCacheForAccess(); return m_Cache[Index(b, d, h, w, ch)]; } - set { PrepareCacheForAccess(); m_Cache[Index(b, d, h, w, ch)] = value; m_CacheIsDirty = true; } - } - - - /// - /// Access element at index [S,R,N,T,D,H,W,C] in this Tensor. - /// This will create a blocking read, if this Tensor is a result of a computation on a different device (GPU). - /// - /// sequence - /// direction - /// batch - /// time - /// depth - /// height - /// width - /// channels - public float this[int s, int r, int n, int t, int d, int h, int w, int c] - { - get { PrepareCacheForAccess(); return m_Cache[Index(s, r, n, t , d, h, w, c)]; } - set { PrepareCacheForAccess(); m_Cache[Index(s, r, n, t , d, h, w, c)] = value; m_CacheIsDirty = true; } - } - - /// - /// Return the cached linear memory representation of this tensor data. - /// This will create a blocking read, if this Tensor is a result of a computation on a different device (GPU). - /// IMPORTANT: Modifying contents of the returned array will have undefined behavior. - /// - /// cached linear memory representation of this tensor data - public float[] ToReadOnlyArray() - { - // @TODO: implement via ITensorData.SharedAccess(), public float[] ToReadOnlyArray(ref int arrayOffset) - PrepareCacheForAccess(); - return m_Cache; - } - #endregion - - /// - /// Device specific internal representation of Tensor data - /// - public ITensorData tensorOnDevice - { - get { return m_TensorOnDevice; } - private set { m_TensorOnDevice = value; if (value != null) m_preferredDataType = value.dataType; } - } - - /// - /// Upload data to device and return its instance - /// - public ITensorData data - { - get - { - if (m_TensorOnDevice == null) - UploadToDevice(new ArrayTensorData(shape, dataType)); - return m_TensorOnDevice; - } - } - - /// - public int cacheBytes => m_Cache?.Length * sizeof(float) ?? 0; - - /// - public ITensorDataStatistics GetTensorDataStatistics() { return m_TensorOnDevice; } - - /// - /// Tensor metadata summary - /// - /// Tensor metadata summary - public override string ToString() - { - return $"(`{name}` {shape}, alloc: {m_TensorAllocator?.GetType()}, onDevice:{m_TensorOnDevice})"; - } - - #region Obsolete - private bool m_Disposing = false; // to protect from infinite-loop. in case UnpinAndDisposeTensor() is called from Dispose() - - /// - /// Unload tensor data from device and dispose this Tensor - /// - /// device specific Tensor data - [ObsoleteAttribute("Use Dispose instead.", false)] - public ITensorData UnpinAndDisposeTensor() - { - // NOTE: since this Tensor is going to be Disposed - // there is no need to populate cache with data from tensorOnDevice - // we can save on skipping PrepareCacheForAccess() call - ITensorData unpinned = tensorOnDevice; - PinToDevice(null, false); - if (!m_Disposing) - Dispose(); - return unpinned; - } - - /// - /// Read-only array of Tensor data - /// - [ObsoleteAttribute("Use ToReadOnlyArray instead.", false)] - public float[] readonlyArray { get { PrepareCacheForAccess(); return m_Cache; } } - - /// - /// Offset into read-only array of Tensor data - /// - [ObsoleteAttribute("Use ToReadOnlyArray instead.", false)] - public int readonlyArrayOffset { get { return 0; } } - #endregion - -} - -} // namespace Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/Tensor.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/Tensor.cs.meta deleted file mode 100644 index 9bfd6bf..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Tensor.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 98a907db6ef714800aaf596877e02d38 -timeCreated: 1506363800 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/TensorExtensions.cs b/Packages/com.unity.barracuda/Runtime/Core/TensorExtensions.cs deleted file mode 100644 index 9e37bfc..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/TensorExtensions.cs +++ /dev/null @@ -1,1195 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Unity.Collections; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Unity.Barracuda { - -/// -/// Tensor extension methods -/// -public static class TensorExtensions -{ - static internal void TestInit(this Tensor X, int n = -1, int modulus = -1) - { - if (n < 0) - n = X.length; - n = Math.Min(n, X.length); - for (int i = 0; i < n; ++i) - { - if (modulus > 1) - X[i] = i % modulus; - else - X[i] = i; - } - } - - static internal void TestInitCos(this Tensor X, int n = -1, float offset = 0.0f) - { - if (n < 0) - n = X.length; - n = Math.Min(n, X.length); - for (int i = 0; i < n; ++i) - X[i] = Mathf.Cos(i + offset); - } - - static internal void TestInitRandom(this Tensor X, int n = -1) - { - if (n < 0) - n = X.length; - n = Math.Min(n, X.length); - for (int i = 0; i < n; ++i) - X[i] = UnityEngine.Random.value; - } - - static internal void TestInitValue(this Tensor X, float value=0.1f, int n = -1) - { - if (n < 0) - n = X.length; - n = Math.Min(n, X.length); - for (int i = 0; i < n; ++i) - X[i] = value; - } - - /// - /// Return Tensor data as float array, this will create a blocking read operation - /// - /// Tensor - /// Tensor data as float array - static public float[] AsFloats(this Tensor x) - { - return x.ToReadOnlyArray(); - } - - /// - /// Return Tensor data as int array (slow operation), this will create a blocking read operation - /// - /// Tensor - /// Tensor data as int array - static public int[] AsInts(this Tensor x) - { - return Array.ConvertAll(x.ToReadOnlyArray(), v => v <= (float)int.MinValue ? int.MinValue : v >= (float)int.MaxValue ? int.MaxValue : (int)v); - } - - /// - /// Return Tensor data as string, limits number of elements to `size` - /// - /// Tensor - /// element number limit - /// Returns Tensor data as string - static public string DataToString(this Tensor X, int size = 32) - { - var str = ""; - for (int i = 0; i < X.length && i < size; ++i) - { - str += X[i]; - str += " "; - } - if (X.length > size) - str += "..."; - return str; - } - - /// - /// Print Tensor metadata to console - /// - /// Tensor - /// message prefix - static public void Print(this Tensor X, string msg = "") - { - if (msg.Length > 0) - msg += " "; - D.Log($"{msg}{X.name} {X.shape}"); - } - - /// - /// Print Tensor data to console - /// - /// Tensor - /// element number limit - /// message prefix - static public void PrintDataPart(this Tensor X, int size, string msg = "") - { - if (msg.Length > 0) - msg += " "; - D.Log($"{msg}{X.DataToString(size)}"); - } - - /// - /// Compare Tensor contents - /// - /// left Tensor - /// right Tensor - /// `true` if shape and data content matches - static public bool Equals(this Tensor X, Tensor Y) - { - if (X.shape != Y.shape) - return false; - - if (X.length != Y.length) - return false; - - for (int i = 0; i < X.length; ++i) - { - if (X[i] != Y[i]) - return false; - } - - return true; - } - - /// - /// Compare Tensor contents approximately - /// - /// left Tensor - /// right Tensor - /// comparison threshold - /// limit number of elements to compare - /// `true` if shape match and while data content matches approximately - static public bool Approximately(this Tensor X, Tensor Y, float epsilon = 1e-4f, int count = -1) - { - if (X.shape != Y.shape) - return false; - - if (X.length != Y.length) - return false; - - if (count < 0) - count = X.length; - for (int i = 0; i < count; ++i) - { - // If one of the values is NaN, the comparison against epislon will return false. - // But if tensor has NaN and the other doesn't, they shouldn't be considered "close". - if (Mathf.Abs(X[i] - Y[i]) > epsilon || float.IsNaN(X[i]) != float.IsNaN(Y[i])) - { - // @TODO: move logging into dedicated function - D.Log("First mismatch @ [" + i + "]: " + X[i] + " != " + Y[i]); - return false; - } - } - - return true; - } - - /// - /// Calculate max difference between two tensors - /// - /// first Tensor - /// second Tensor - /// - static public float MaxDifference(this Tensor X, Tensor Y) - { - float maxD = 0f; - for (int i = 0; i < X.length; ++i) - maxD = Mathf.Max(Mathf.Abs(X[i] - Y[i]), maxD); - return maxD; - } - - /// - /// Reshape Tensor - /// - /// Tensor - /// new shape as array of int (expected as size 4 for NHWC or size 8 for SRNTDHWC) - /// reshaped Tensor - static public Tensor Reshape(this Tensor X, int[] size) - { - var newShape = X.shape.Reshape(size); - return X.Reshape(newShape); - } - - /// - /// Calculate max value index - /// - /// Tensor - /// max value index - static public int[] ArgMax(this Tensor X) - { - Assert.AreEqual(TensorShape.DataChannel, TensorShape.MaxRank - 1); // expects channels last layout - Assert.IsTrue(X.channels != 0); - Assert.AreEqual(X.length % X.channels, 0); - - // reduce over the last dimension - channels - var innerLength = X.channels; - var outterLength = X.length / innerLength; - - int[] result = new int[outterLength]; - for (var n = 0; n < outterLength; ++n) - { - float maxV = Mathf.NegativeInfinity; - for (int c = 0; c < innerLength; ++c) - { - var v = X[n * innerLength + c]; - if (maxV >= v) - continue; - maxV = v; - result[n] = c; - } - } - return result; - } - - /// - /// Return indices in order that would produce sorted Tensor values - /// - /// Tensor - /// indices in order that would produce sorted Tensor values - static public int[][] ArgSort(this Tensor X) - { - Assert.AreEqual(TensorShape.DataChannel, TensorShape.MaxRank - 1); // expects channels last layout - Assert.IsTrue(X.channels != 0); - Assert.AreEqual(X.length % X.channels, 0); - - // reduce over the last dimension - channels - var innerLength = X.channels; - var outterLength = X.length / innerLength; - - var result = new List(); - for (var n = 0; n < outterLength; ++n) - { - int[] indices = Enumerable.Range(0, innerLength).ToArray(); - - var sliceOffset = n * innerLength; - Array.Sort(indices, (a, b) => X[sliceOffset + a].CompareTo(X[sliceOffset + b])); - result.Add(indices); - } - return result.ToArray(); - } - - /// - /// Fill Tensor with `value` - /// - /// Tensor - /// value - public static void Fill(this Tensor X, float value) - { - for (int i = 0; i < X.length; ++i) - X[i] = value; - } - - /// - /// Calculate output shape for Gather operation - /// - /// input shapes - /// axis - /// output shape - static public TensorShape Gather(TensorShape[] shapes, int axis) - { - TensorShape shape = shapes[0]; - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - TensorShape indices = shapes[1]; - if (!indices.hasNamedDimensions) - indices = indices.AsNamed(); - - shape[axis] = indices.length; - - return shape; - } - - /// - /// Concatenate `Tensor` array along `axis` and calculate output shape - /// - /// Tensor array - /// axis - /// new `TensorShape` - /// Off-axis dimension mismatch - static public TensorShape Concat(Tensor[] tensors, int axis) - { - if (tensors.Length == 0) - return new TensorShape(); - - var a = tensors[0].shape; - if (!a.hasNamedDimensions) - a = a.AsNamed(); - var aAxis = a.Axis(axis); - - // validate that off axis dimensions are equal - for (var i = 1; i < tensors.Length; ++i) - { - var b = tensors[i].shape; - if (!b.hasNamedDimensions) - b = b.AsNamed(); - - var bAxis = b.Axis(axis); - a[aAxis] = 0; b[bAxis] = 0; - if (a != b) - { - foreach (var s in tensors) - D.Log(s.shape); - throw new ArgumentException("Off-axis dimensions must match"); - } - } - - var shape = tensors[0].shape; - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - var dstAxis = tensors[0].shape.Axis(axis); - for (var i = 1; i < tensors.Length; ++i) - { - var otherShape = tensors[i].shape; - if (!otherShape.hasNamedDimensions) - otherShape = otherShape.AsNamed(); - - shape[dstAxis] += otherShape[axis]; - } - - return shape; - } - - /// - /// Calculate concatenation output shape - /// - /// input shapes - /// concatenation axis - /// output shape - /// Off-axis dimension mismatch - static public TensorShape Concat(TensorShape[] shapes, int axis) - { - if (shapes.Length == 0) - return new TensorShape(); - - var a = shapes[0]; - if (!a.hasNamedDimensions) - a = a.AsNamed(); - var aAxis = a.Axis(axis); - - // validate that off axis dimensions are equal - for (var i = 1; i < shapes.Length; ++i) - { - - var b = shapes[i]; - if (!b.hasNamedDimensions) - b = b.AsNamed(); - - var bAxis = b.Axis(axis); - a[aAxis] = 0; b[bAxis] = 0; - if (a != b) - { - foreach (var s in shapes) - D.Log(s); - throw new ArgumentException("Off-axis dimensions must match"); - } - } - - var shape = shapes[0]; - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - var dstAxis = shape.Axis(axis); - for (var i = 1; i < shapes.Length; ++i) - { - var otherShape = shapes[i]; - if (!otherShape.hasNamedDimensions) - otherShape = otherShape.AsNamed(); - - shape[dstAxis] += otherShape[axis]; - } - - return shape; - } - - /// - /// Calculate maximum shape that would cover all input shapes - /// - /// input shapes - /// output shape - static public TensorShape Max(TensorShape[] shapes) - { - Assert.IsTrue(shapes.Length > 0); - - var shape = shapes[0]; - - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - for (var i = 1; i < shapes.Length; ++i) - { - var otherShape = shapes[i]; - if (!otherShape.hasNamedDimensions) - otherShape = otherShape.AsNamed(); - - for (var axis = 0; axis < TensorShape.MaxRank; axis++) - { - shape[axis] = Math.Max(shape[axis], otherShape[axis]); - } - } - - return shape; - } - - /// - /// Calculate maximum shape that would cover all input tensors - /// - /// input tensors - /// output shape - static public TensorShape MaxShape(Tensor[] tensors) - { - Assert.IsTrue(tensors.Length > 0); - var shape = tensors[0].shape; - - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - for (var i = 1; i < tensors.Length; ++i) - { - for (var axis = 0; axis < TensorShape.MaxRank; axis++) - { - var otherShape = tensors[i].shape; - if (!otherShape.hasNamedDimensions) - otherShape = otherShape.AsNamed(); - - shape[axis] = Math.Max(shape[axis], otherShape[axis]); - } - } - - return shape; - } - - /// - /// Scale TensorShape by the `scale` factor - /// - /// TensorShape - /// scale - /// output shape - static public TensorShape Scale(this TensorShape shape, TensorShape scale) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - var newShape = shape; - for (var axis = 0; axis < TensorShape.MaxRank; axis++) - newShape[axis] *= scale[axis]; - return newShape; - } - - /// - /// Scale TensorShape by the `scale` factor - /// - /// TensorShape - /// scale - /// output shape - static public TensorShape Scale(this TensorShape shape, int[] scale) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - if (scale.Length == TensorShape.MaxRank) - { - for (var axis = 0; axis < TensorShape.MaxRank; axis++) - shape[axis] *= scale[axis]; - } - else - { - Assert.AreEqual(4, scale.Length); - shape[TensorShape.DataBatch] *= scale[0]; - shape[5] *= scale[1]; - shape[6] *= scale[2]; - shape[7] *= scale[3]; - } - return shape; - } - - /// - /// Reduce TensorShape across specified `axis` - /// - /// TensorShape - /// axis - /// output shape - static public TensorShape Reduce(this TensorShape shape, int axis) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - axis = shape.Axis(axis); - var newShapeArray = shape; - newShapeArray[axis] = 1; - return newShapeArray; - } - - /// - /// Reshape TensorShape into new shape specified by `size`. At most one dimension of the new shape can be -1. - /// See: https://github.com/onnx/onnx/blob/master/docs/Operators.md#Reshape - /// - /// TensorShape - /// new shape - /// output shape - /// more than one dimension is unspecified - static public TensorShape Reshape(this TensorShape shape, int[] size4Dor8D) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - unsafe - { - int* size = stackalloc int[TensorShape.MaxRank]; - int* newShapeArray = stackalloc int[TensorShape.MaxRank]; - - Get8DParametersNoAlloc(shape, size4Dor8D, size, 1); - for (int d = 0; d < TensorShape.MaxRank; ++d) - newShapeArray[d] = shape[d]; - - // From: https://github.com/onnx/onnx/blob/master/docs/Operators.md#Reshape - // - // At most one dimension of the new shape can be -1. - // In this case, the value is inferred from the size of the tensor and the remaining dimensions. - // - // A dimension could also be 0, - // in which case the actual dimension value is unchanged (i.e. taken from the input tensor). - - var multipleOf = 1; - var unknownIndex = -1; - for (int q = 0; q < TensorShape.MaxRank; ++q) - { - if (size[q] > 0) - { - multipleOf *= size[q]; - newShapeArray[q] = size[q]; - } - else if (size[q] == 0) - multipleOf *= newShapeArray[q]; - else if (unknownIndex == -1) - unknownIndex = q; - else - throw new ArgumentException("Can only specify one unknown dimension"); - } - - if (unknownIndex == -1) - { - // all dimensions are given - var newShape = new TensorShape(newShapeArray[0], newShapeArray[1], newShapeArray[2], newShapeArray[3], - newShapeArray[4], newShapeArray[5], newShapeArray[6], newShapeArray[7]); - if (shape.length != newShape.length) - throw new ArgumentException("Cannot reshape array of size " + shape.length + - " into shape " + newShape); - return newShape; - } - - var solveForIndex = shape.length / multipleOf; - bool remainderLeft = shape.length % multipleOf != 0; - - if (remainderLeft) - throw new ArgumentException("Cannot reshape array of size " + shape.length + - " into shape with multiple of " + multipleOf + " elements"); - - newShapeArray[unknownIndex] = solveForIndex; - return new TensorShape(newShapeArray[0], newShapeArray[1], newShapeArray[2], newShapeArray[3], - newShapeArray[4], newShapeArray[5], newShapeArray[6], newShapeArray[7]); - } - } - - /// - /// Calculate new shape after applying border to current TensorShape - /// - /// TensorShape - /// border - /// new TensorShape - static public TensorShape ApplyBorder(this TensorShape shape, int[] border) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - Assert.IsTrue(border.Length == 6 || border.Length == 8); - if(border.Length == 6) - { - shape[TensorShape.H] += border[1] + border[4]; - shape[TensorShape.W] += border[0] + border[3]; - shape[TensorShape.C] += border[2] + border[5]; - } - else if (border.Length == 8) - { - shape[TensorShape.D] += border[2] + border[6]; - shape[TensorShape.H] += border[1] + border[5]; - shape[TensorShape.W] += border[0] + border[4]; - shape[TensorShape.C] += border[3] + border[7]; - } - - return shape; - } - - static internal int[] AdjustPadToKernel(this Tensor tensor, Tensor kernel, int[] stride, int[] pad) - { - return AdjustPadToKernel(tensor.shape, kernel.shape, stride, pad); - } - - static internal int[] AdjustPadToKernel(this TensorShape shape, TensorShape kernel, int[] stride, int[] pad) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - Assert.IsTrue(stride.Length==2 || stride.Length==3); - unsafe - { - int* kernelDims = stackalloc int[stride.Length == 2 ? 2 : 3]; - kernelDims[0] = kernel.kernelWidth; - kernelDims[1] = kernel.kernelHeight; - - if (stride.Length > 2) - kernelDims[2] = kernel.kernelSpatialDepth; - - return AdjustPadToPool(shape, kernelDims, stride, pad); - } - } - - static internal int[] AdjustPadToPool(this Tensor tensor, int[] pool, int[] stride, int[] pad) - { - return AdjustPadToPool(tensor.shape, pool, stride, pad); - } - - static internal unsafe int[] AdjustPadToPool(this Tensor tensor, int* pool, int[] stride, int[] pad) - { - return AdjustPadToPool(tensor.shape, pool, stride, pad); - } - - static internal int[] AdjustPadToPool(this TensorShape shape, int[] pool, int[] stride, int[] pad) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - unsafe - { - fixed (int* pPool = pool) - { - return AdjustPadToPool(shape, pPool, stride, pad); - } - } - } - - static internal unsafe int[] AdjustPadToPool(this TensorShape shape, int* pool, int[] stride, int[] pad) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - Assert.IsTrue(stride.Length > 0); - int featureCount = stride.Length; - Assert.IsTrue(featureCount <= TensorShape.DataFeatures.Length); - - // negative pad values mean auto_pad type is used - if (pad[0] >= 0) - return pad; - - var type = (Layer.AutoPad)pad[0]; - if (type == Layer.AutoPad.SameUpper || type == Layer.AutoPad.SameLower) - { - // Based on ONNX (AveragePool & MaxPool) - // https://github.com/onnx/onnx/blob/master/docs/Operators.md - // and TensorFlow docs: - // https://www.tensorflow.org/api_guides/python/nn#Notes_on_SAME_Convolution_Padding - var adjustedPad = new int [featureCount*2]; - for (var i = 0; i < featureCount; ++i) - { - var featureModStride = shape.width % stride[i]; - if (featureModStride == 0) - featureModStride = stride[i]; - - var padAlongFeature = Math.Max(pool[i] - featureModStride, 0); - // Code above (based on TensorFlow docs) is equivalent to (based on ONNX docs): - // padAlongWidth = (Mathf.Ceil(shape.width/stride[0]) - 1) * stride[0] + pool[0] - shape.width; - // padAlongHeight = (Mathf.Ceil(shape.height/stride[1]) - 1) * stride[1] + pool[1] - shape.height; - var featureSmall = padAlongFeature / 2; - var featureLarge = padAlongFeature - featureSmall; - if (type == Layer.AutoPad.SameUpper) { - adjustedPad[i] = featureSmall; - adjustedPad[i+featureCount] = featureLarge; - } else { - adjustedPad[i] = featureLarge; - adjustedPad[i+featureCount] = featureSmall; - } - } - return adjustedPad; - } - else - throw new NotImplementedException("This padding type is not implemented yet!"); - } - - static internal TensorShape ApplyPool(this TensorShape shape, int[] pool, int[] stride, int[] pad, - bool ceilMode = false) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - Assert.IsTrue(stride.Length == pool.Length); - unsafe - { - fixed (int* pPool = pool) - { - return ApplyPool(shape, pPool, stride, pad, ceilMode); - } - } - } - - static internal unsafe TensorShape ApplyPool(this TensorShape shape, int* pool, int[] stride, int[] pad, bool ceilMode = false) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - Assert.IsTrue(stride.Length > 0); - - Assert.IsTrue(stride.Length*2 == pad.Length); - int featureCount = stride.Length; - Assert.IsTrue(featureCount <= TensorShape.DataFeatures.Length); - - // Based on ONNX (AveragePool & MaxPool) - // https://github.com/onnx/onnx/blob/master/docs/Operators.md - // Theano "Convolution arithmetic tutorial" - // http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html#quick-reference - // and TensorFlow docs: - // https://www.tensorflow.org/api_guides/python/nn#Convolution - // https://www.tensorflow.org/api_guides/python/nn#Notes_on_SAME_Convolution_Padding - // - // output_size = (input_size + pad_left + pad_right - kernel_size) / stride + 1 - var newShape = shape; - for (var i = 0; i < featureCount; ++i) - { - // C# automatically rounds down - // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators - if (ceilMode) - newShape[TensorShape.DataFeatures[i]] = (shape[TensorShape.DataFeatures[i]] + (pad[i]+pad[i+featureCount]) - pool[i] + stride[i] - 1) / stride[i] + 1; - else - newShape[TensorShape.DataFeatures[i]] = (shape[TensorShape.DataFeatures[i]] + (pad[i]+pad[i+featureCount]) - pool[i]) / stride[i] + 1; - } - return newShape; - } - - static internal TensorShape ApplyKernel(this TensorShape shape, TensorShape kernel, int[] stride, int[] pad) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - unsafe - { - Assert.IsTrue(stride.Length==2 || stride.Length==3); - int* kernelDims = stackalloc int[stride.Length == 2 ? 2 : 3]; - kernelDims[0] = kernel.kernelWidth; - kernelDims[1] = kernel.kernelHeight; - if (stride.Length > 2) - kernelDims[2] = kernel.kernelSpatialDepth; - - var outShape = ApplyPool(shape, kernelDims, stride, pad); - outShape[7] = kernel.kernelCount; - return outShape; - } - } - - static internal TensorShape ApplyKernelInverse(this TensorShape shape, TensorShape kernel, int[] stride, int[] pad, int[] outputAdjustment) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - Assert.IsTrue(stride.Length > 0); - Assert.IsTrue(stride.Length * 2 == pad.Length); - Assert.IsTrue(stride.Length <= TensorShape.KernelSpatials.Length); - Assert.IsTrue(stride.Length <= TensorShape.DataFeatures.Length); - - // Based on ONNX (ConvTranspose) - // https://github.com/onnx/onnx/blob/master/docs/Operators.md - // and Theano "Convolution arithmetic tutorial" - // http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html#transposed-convolution-arithmetic - // - // Inverse of: - // output_size = (input_size + pad_left + pad_right - kernel_size) / stride + 1 - // Resulting in: - // output_size = (input_size - 1 ) * stride - (pad_left + pad_right) + kernel_size + output_adj - // output_adj = (input_size + (pad_left + pad_right) - kernel_size) % stride - // - if (outputAdjustment == null || outputAdjustment.Length == 0) - { - outputAdjustment = new int[stride.Length]; - for (var i = 0; i < stride.Length; ++i) - { - var featureAxis = TensorShape.DataFeatures[i]; - var kernelAxis = TensorShape.KernelSpatials[i]; - var padding = pad[i] + pad[stride.Length+i]; - outputAdjustment[i] = (shape[featureAxis] + padding - kernel[kernelAxis]) % stride[i]; - } - } - - var newShape = shape; - for (var i = 0; i < stride.Length; ++i) - { - var featureAxis = TensorShape.DataFeatures[i]; - var kernelAxis = TensorShape.KernelSpatials[i]; - var padding = pad[i] + pad[stride.Length+i]; - newShape[featureAxis] = (shape[featureAxis] - 1) * stride[i] - padding + kernel[kernelAxis] + outputAdjustment[i]; - } - - newShape[TensorShape.KernelOutChannel] = kernel.kernelCount; - return newShape; - } - - /// - /// Wrap index (emulate Python array index behavior) - /// - /// index - /// array length - /// wrapped around index - static public int WrapIndex(int i, int length) - { - // allow index to be equal to length - // in order to enable iteration over [i,end) range - if (i >= length) - return length; - - // in C# modulo of negative is negative - // to emulate Python array behavior, we use: https://stackoverflow.com/questions/1082917/mod-of-negative-number-is-melting-my-brain/1082938 - var v = i % length; - return v < 0 ? (v + length): v; - } - - static internal bool IsNDHWC(this TensorShape shape) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - return shape.sequenceLength == 1 && - shape.numberOfDirections == 1 && - shape.extraDimension == 1; - } - - static internal bool Is4D(this TensorShape shape) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - return shape.sequenceLength == 1 && - shape.numberOfDirections == 1 && - shape.extraDimension == 1 && - shape.depth == 1; - } - - // Works for NCHW or NHWC - static internal int Convert4DTo8DAxis(int axis) - { - Assert.IsTrue(axis < 4); - Assert.IsTrue(axis > -4); - if (axis < 0) //backward indexing - { - return axis; - } - else if (axis == 0) //batch - return TensorShape.DataBatch; - else //H,W,C - return axis + TensorShape.D; - } - - static internal int FirstNotIdentityFeatureDimensionIndex(this TensorShape shape) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - for (int dimIndex = TensorShape.DataFeature3; dimIndex < TensorShape.MaxRank; ++dimIndex) - { - if (shape[dimIndex] > 1) - return dimIndex; - } - - return TensorShape.MaxRank; - } - - static internal bool Is8DAxisConvertibleTo4D(int axis) - { - Assert.IsTrue(axis > -4); - Assert.IsTrue(axis < TensorShape.MaxRank); - return axis < 0 || axis == TensorShape.DataBatch || axis > TensorShape.D; - } - - /// - /// Check if all tensors are convertible to 4D tensors - /// - /// tensors - /// `true` if all tensors are 4D (or less) - static public bool AreAllTensorsConvertibleTo4D(Tensor[] tensors) - { - for (int i = 0; i < tensors.Length; ++i) - { - if (!tensors[i].shape.Is4D()) - return false; - } - - return true; - } - - static internal int Convert8DAxisTo4D(int axis) - { - Assert.IsTrue(Is8DAxisConvertibleTo4D(axis)); - if (axis < 0) //backward indexing - { - return axis; - } - else if (axis == TensorShape.DataBatch) //batch - return 0; - else //H,W,C - return axis - TensorShape.D; - } - - static internal unsafe void Get8DParametersNoAlloc(this TensorShape shape, int[] parameters, int* parameters8D, int defaultValue) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - if (parameters.Length == TensorShape.MaxRank) - { - for (int i = 0; i < TensorShape.MaxRank; ++i) - parameters8D[i] = parameters[i]; - } - else - { - Assert.AreEqual(4, parameters.Length); - if (!shape.Is4D()) Assert.IsTrue(false, $"4D Parameters {parameters} can't be used with a tensor of shape {shape} as it contains other dimensions, please use 8D parameters for this shape."); - parameters8D[0] = defaultValue; - parameters8D[1] = defaultValue; - parameters8D[2] = parameters[0]; - parameters8D[3] = defaultValue; - parameters8D[4] = defaultValue; - parameters8D[5] = parameters[1]; - parameters8D[6] = parameters[2]; - parameters8D[7] = parameters[3]; - } - } - - /// - /// Calculate 8D permutations from 4D - /// - /// shape - /// permutations - /// 8D permutations - static public int[] Get8DPermutationsForNHWCPermutationsAndShape(this TensorShape shape, int[] permutations) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - if (permutations.Length == TensorShape.MaxRank) - return permutations; - - Assert.AreEqual(4, permutations.Length); - if (!shape.Is4D()) Assert.IsTrue(false, $"4D Permutation {permutations} can't be used with a tensor of shape {shape} as it contains other dimensions, please use an 8D permutation for this shape."); - int batchOldAxis = Convert4DTo8DAxis(permutations[0]); - int heighOldAxis = Convert4DTo8DAxis(permutations[1]); - int widthOldIndex = Convert4DTo8DAxis(permutations[2]); - int channeOldIndex = Convert4DTo8DAxis(permutations[3]); - return new int[] {0, 1, batchOldAxis, 3, 4, heighOldAxis, widthOldIndex, channeOldIndex }; - } - - static internal NativeArray Get8DPermutationsForNHWCPermutationsAndShape(this TensorShape shape, NativeArray inPermutations) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - if (inPermutations.Length == TensorShape.MaxRank) - return inPermutations; - - Assert.AreEqual(4, inPermutations.Length); - if (!shape.Is4D()) Assert.IsTrue(false, $"4D Permutation {inPermutations.ToString()} can't be used with a tensor of shape {shape} as it contains other dimensions, please use an 8D permutation for this shape."); - int batchOldAxis = Convert4DTo8DAxis(inPermutations[0]); - int heighOldAxis = Convert4DTo8DAxis(inPermutations[1]); - int widthOldIndex = Convert4DTo8DAxis(inPermutations[2]); - int channeOldIndex = Convert4DTo8DAxis(inPermutations[3]); - - // Valid only for single frame - NativeArray outPermutations = new NativeArray(8, Allocator.Temp); - outPermutations[0] = 0; - outPermutations[1] = 1; - outPermutations[2] = batchOldAxis; - outPermutations[3] = 3; - outPermutations[4] = 4; - outPermutations[5] = heighOldAxis; - outPermutations[6] = widthOldIndex; - outPermutations[7] = channeOldIndex; - - return outPermutations; - } - - static internal int[] Get8DPermutationsForNCHWPermutationsAndShape(this TensorShape shape, int[] permutations) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - if (permutations.Length == TensorShape.MaxRank) - return permutations; - - Assert.AreEqual(4, permutations.Length); - if (!shape.Is4D()) Assert.IsTrue(false, $"4D Permutation {permutations} can't be used with a tensor of shape {shape} as it contains other dimensions, please use an 8D permutation for this shape."); - int batchOldAxis = Convert4DTo8DAxis(permutations[0]); - int channelOldIndex = Convert4DTo8DAxis(permutations[1]); - int heightOldIndex = Convert4DTo8DAxis(permutations[2]); - int widthOldIndex = Convert4DTo8DAxis(permutations[3]); - return new int[] {0, 1, batchOldAxis, 3, 4, channelOldIndex, heightOldIndex, widthOldIndex }; - } - - static internal NativeArray Get8DPermutationsForNCHWPermutationsAndShape(this TensorShape shape, NativeArray inPermutations) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - if (inPermutations.Length == TensorShape.MaxRank) - return inPermutations; - - Assert.AreEqual(4, inPermutations.Length); - if (!shape.Is4D()) Assert.IsTrue(false, $"4D Permutation {inPermutations.ToString()} can't be used with a tensor of shape {shape} as it contains other dimensions, please use an 8D permutation for this shape."); - int batchOldAxis = Convert4DTo8DAxis(inPermutations[0]); - int channelOldIndex = Convert4DTo8DAxis(inPermutations[1]); - int heightOldIndex = Convert4DTo8DAxis(inPermutations[2]); - int widthOldIndex = Convert4DTo8DAxis(inPermutations[3]); - - // Valid only for single frame - NativeArray outPermutations = new NativeArray(8, Allocator.Temp); - outPermutations[0] = 0; - outPermutations[1] = 1; - outPermutations[2] = batchOldAxis; - outPermutations[3] = 3; - outPermutations[4] = 4; - outPermutations[5] = channelOldIndex; - outPermutations[6] = heightOldIndex; - outPermutations[7] = widthOldIndex; - - return outPermutations; - } - - static internal unsafe TensorShape ApplyStridedSlice8DUnsafeNoAlloc(this TensorShape shape, int* starts, int* ends, - int* stride) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - TensorShape sliced = shape; - - for (int i = 0; i < shape.rank; ++i) - { - // NOTE: begin=0, end=0, stride=1 <= full range from the existing axis - // begin=0, end=X, stride=1 <= full range from the existing axis, if X==last element on this axis - // begin=0, end=0, stride=0 <= new axis OR shrink axis to a single 1st element - // begin=N, end=N, stride=0 <= shrink axis to a single Nth element - - // take + 1 is si > shape[i] - int ei = TensorExtensions.WrapIndex(ends[i], shape[i]); - int si = TensorExtensions.WrapIndex(starts[i], shape[i]); - - - // Barracuda convetion (non ONNX), t[0:0] => t[:] - if (si == 0 && ei == 0) - ei = shape[i]; - - if (stride[i] > 0) - sliced[i] = (int)Math.Round((double)(Math.Min(ei, shape[i]) - Math.Min(si, shape[i] - 1)) / (double)(Mathf.Abs(stride[i])), MidpointRounding.AwayFromZero); - else if (stride[i] < 0) - { - bool inclusive = ends[i] < -shape[i]; // edge case when ends is negative and bigger than nchwShape - sliced[i] = (int)Math.Round((double)(Math.Min(si, shape[i] - 1) - Math.Min(ei, shape[i]) + (inclusive ? 1 : 0)) / (double)(Mathf.Abs(stride[i])), MidpointRounding.AwayFromZero); - } - else - { - // Assert.IsTrue(stride[i] != 0); // 0 strides not allowed - // breaks legacy implementations - D.LogWarning("StridedSlice with 0 strides, not supported! Slicing to 1D dimension"); - sliced[i] = 1; - } - } - - return sliced; - } - - static internal TensorShape ApplyStridedSlice(this TensorShape shape, int[] starts, int[] ends, int[] stride) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - unsafe - { - int* starts8Dbuffer = stackalloc int[TensorShape.MaxRank]; - int* ends8Dbuffer = stackalloc int[TensorShape.MaxRank]; - int* stride8Dbuffer = stackalloc int[TensorShape.MaxRank]; - Get8DParametersNoAlloc(shape, starts, starts8Dbuffer, 0); - Get8DParametersNoAlloc(shape, ends, ends8Dbuffer, 1); - Get8DParametersNoAlloc(shape, stride, stride8Dbuffer, 1); - - return shape.ApplyStridedSlice8DUnsafeNoAlloc(starts8Dbuffer, ends8Dbuffer, stride8Dbuffer); - } - } - - - /// - /// Calculate shape after applying permutations - /// - /// shape - /// permutations - /// new shape - static public int[] Permute(int[] shape, int[] permutations) - { - Assert.AreEqual(shape.Length, permutations.Length); - var output = new int[shape.Length]; - for (var i = 0; i < permutations.Length; ++i) - output[i] = permutations[i] >= 0 ? shape[permutations[i]] : 1; - return output; - } - - /// - /// Calculate TensorShape after applying permutations - /// - /// shape - /// permutations - /// new TensorShape - static public TensorShape Permute(this TensorShape shape, int[] permutations) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - if (permutations.Length == 4) - permutations = Get8DPermutationsForNHWCPermutationsAndShape(shape, permutations); - - var permutedShape = new int[TensorShape.MaxRank]; - for (var i = 0; i < permutations.Length; ++i) - permutedShape[i] = permutations[i] >= 0 ? shape[permutations[i]] : 1; - - var output = new TensorShape(permutedShape); - return output; - } - - static internal TensorShape Permute(this TensorShape shape, NativeArray permutations) - { - if (!shape.hasNamedDimensions) - shape = shape.AsNamed(); - - if (permutations.Length == 4) - permutations = Get8DPermutationsForNHWCPermutationsAndShape(shape, permutations); - - var permutedShape = new int[TensorShape.MaxRank]; - for (var i = 0; i < permutations.Length; ++i) - permutedShape[i] = permutations[i] >= 0 ? shape[permutations[i]] : 1; - - var output = new TensorShape(permutedShape); - return output; - } - - /// - /// Create ITensorData from Texture - /// - /// Texture - /// shape - /// created ITensorData - /// thrown if unsupported texture type is supplied - static public ITensorData CreateFromTexture(Texture tex, TensorShape shape) - { - Assert.AreEqual(tex.width, shape.width); - Assert.AreEqual(tex.height, shape.height); - Assert.IsTrue(shape.channels < 4); - - // @TODO: implement proper GPU storage - var data = new ArrayTensorData(shape); - if (tex is Texture2D) - { - Texture2D tex2d = tex as Texture2D; - var pixels = tex2d.GetPixels(); - for (int i = 0; i < data.array.Length && i < pixels.Length * shape.channels; ++i) - data.array[i] = pixels[i / shape.channels][i % shape.channels]; - } - else - throw new NotImplementedException(); - - return data; - } -} - -} // namespace Unity.Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/TensorExtensions.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/TensorExtensions.cs.meta deleted file mode 100644 index a774bdd..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/TensorExtensions.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 3fb6bb6c79a8e4887a615dbfc580e1cd -timeCreated: 1506363800 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/TextureAsTensorData.cs b/Packages/com.unity.barracuda/Runtime/Core/TextureAsTensorData.cs deleted file mode 100644 index 84d2355..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/TextureAsTensorData.cs +++ /dev/null @@ -1,423 +0,0 @@ -using UnityEngine; -using UnityEngine.Experimental.Rendering; // AsyncGPUReadback -using UnityEngine.Assertions; -using System; - -namespace Unity.Barracuda -{ - -/// -/// Texture based `Tensor` storage -/// -public class TextureAsTensorData : UniqueResourceId, ITensorData -{ - /// - /// Flip flag enum - /// - public enum Flip - { - /// - /// None - /// - None, - - /// - /// Flip Y - /// - Y, - } - - /// - /// Interpret depth as enum - /// - public enum InterpretDepthAs - { - /// - /// Batch - /// - Batch, - - /// - /// Channels - /// - Channels, - } - - /// - /// Interpret color enum - /// - public enum InterpretColorAs - { - /// - /// Average multiple channels - /// - AverageMultipleChannels, - // TODO: PickFirstChannel, - } - - /// - /// multiplies scales texture value - /// - public Vector4 scale - { - get { return m_scale; } - } - - /// - /// subtracts bias texture value - /// - public Vector4 bias - { - get { return m_bias; } - } - - - private TensorShape m_Shape; - private Texture[] m_Textures; - private int m_InterpretPixelAsChannels; - private InterpretDepthAs m_InterpretDepthAs; - private InterpretColorAs m_InterpretColorAs; - private Flip m_Flip; - private Vector4 m_scale, m_bias; - - - /// - /// Shape - /// - public TensorShape shape - { - get { return m_Shape; } - } - - /// - /// Backing textures - /// - public Texture[] textures - { - get { return m_Textures; } - } - - /// - /// Interpret pixel as channels - /// - public int interpretPixelAsChannels - { - get { return m_InterpretPixelAsChannels; } - } - - /// - /// Interpret depth as - /// - public InterpretDepthAs interpretDepthAs - { - get { return m_InterpretDepthAs; } - } - - /// - /// Interpret color as - /// - public InterpretColorAs interpretColorAs - { - get { return m_InterpretColorAs; } - } - - /// - /// Flip flag - /// - public Flip flip - { - get { return m_Flip; } - } - - /// - /// Create `TextureAsTensorData` from supplied `textures` - /// - /// backing textures - /// interpret pixel as channels - /// flip - /// depth as - /// color as - /// thrown if textures array is empty or texture types are different - /// thrown if unsupported texture type is supplied - public TextureAsTensorData(Texture[] textures, int interpretPixelAsChannels = -1, - Flip flip = Flip.Y, InterpretDepthAs depthAs = InterpretDepthAs.Batch, - InterpretColorAs colorAs = InterpretColorAs.AverageMultipleChannels) : - this(textures, flip, depthAs, colorAs, Vector4.one, Vector4.zero, interpretPixelAsChannels) - { - } - - /// - /// Create `TextureAsTensorData` from supplied `textures` - /// - /// backing textures - /// interpret pixel as channels - /// flip - /// depth as - /// color as - /// multiplies `scale` to texture values - /// substracts `bias` from texture values - /// thrown if textures array is empty or texture types are different - /// thrown if unsupported texture type is supplied - public TextureAsTensorData(Texture[] textures, - Flip flip, InterpretDepthAs depthAs, InterpretColorAs colorAs, Vector4 scale, Vector4 bias, - int interpretPixelAsChannels) - { - if (textures.Length < 1) - throw new ArgumentException("Textures array must be non empty"); - - if (interpretPixelAsChannels < 0) - { - interpretPixelAsChannels = TextureFormatUtils.FormatToChannelCount(textures[0]); - - // check that all textures have the same number of channels - foreach (var tex in textures) - if (interpretPixelAsChannels != TextureFormatUtils.FormatToChannelCount(tex)) - throw new ArgumentException("All textures must have the same number of channels"); - } - - m_InterpretPixelAsChannels = interpretPixelAsChannels; - m_InterpretDepthAs = depthAs; - m_InterpretColorAs = colorAs; - m_Flip = flip; - - m_scale = scale; - m_bias = bias; - - var width = textures[0].width; - var height = textures[0].height; - - var totalDepth = 0; - foreach (var tex in textures) - { - if (tex.width != width || tex.height != height) - throw new ArgumentException("All textures must have the same width and height dimensions"); - - var tex2D = tex as Texture2D; - var texArr = tex as Texture2DArray; - var tex3D = tex as Texture3D; - var rt = tex as RenderTexture; - if (tex2D) - totalDepth += 1; - else if (texArr) - totalDepth += texArr.depth; - else if (tex3D) - totalDepth += tex3D.depth; - else if (rt) - totalDepth += rt.volumeDepth; - else - throw new InvalidOperationException("Unsupported texture type"); - } - - m_Textures = textures; - - int batch = 1; - int channels = interpretPixelAsChannels; - if (m_InterpretDepthAs == InterpretDepthAs.Batch) - batch *= totalDepth; - else if (m_InterpretDepthAs == InterpretDepthAs.Channels) - channels *= totalDepth; - - m_Shape = new TensorShape(batch, height, width, channels); - } - - /// - /// Create `TextureAsTensorData` from supplied `texture` - /// - /// texture - /// interpret pixel as channels - /// flip - /// depth as - /// color as - public TextureAsTensorData(Texture texture, int interpretPixelAsChannels = -1, - Flip flip = Flip.Y, InterpretDepthAs depthAs = InterpretDepthAs.Batch, - InterpretColorAs colorAs = InterpretColorAs.AverageMultipleChannels) - : this(new[] { texture }, interpretPixelAsChannels, flip, depthAs, colorAs) - { - } - - /// - public virtual void Reserve(int count) - { - // currently always readonly - throw new InvalidOperationException("TextureAsTensorData is readonly"); - } - - /// - public virtual void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0) - { - // currently always readonly - throw new InvalidOperationException("TextureAsTensorData is readonly"); - } - - /// - public virtual bool ScheduleAsyncDownload(int count) - { - // @TODO: cache compute tensor data and request async - return true; - } - - private static void FillCacheFromTexture(float[] output, Texture tex, - int batchOffset, int channelOffset, int[] channelWriteMask, int[] channelReadMap, - bool flipY, Vector4 scale4, Vector4 bias4, TensorShape texDataShape) - { - var tex2D = tex as Texture2D; - var texArr = tex as Texture2DArray; - var tex3D = tex as Texture3D; - var rt = tex as RenderTexture; - - Color[] colors = null; - var texDepth = 1; - if (tex2D) - { - colors = tex2D.GetPixels(0); - texDepth = 1; - } - else if (texArr) - { - colors = texArr.GetPixels(0, 0); - texDepth = texArr.depth; - } - else if (tex3D) - { - colors = tex3D.GetPixels(0); - texDepth = tex3D.depth; - } - else if (rt) - { - var currentRT = RenderTexture.active; - RenderTexture.active = rt; - Texture2D tmpTexture = new Texture2D(rt.width, rt.height, tex.graphicsFormat, TextureCreationFlags.None); - tmpTexture.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); - tmpTexture.Apply(); - colors = tmpTexture.GetPixels(0); - RenderTexture.active = currentRT; - texDepth = rt.volumeDepth; - if (rt.format == RenderTextureFormat.RHalf) - Debug.LogError( - "Texture to Tensor does not support RHalf format for source rendertarget when Compute shader are not available on platform."); - } - - if (texDepth != 1) - { - Debug.LogError( - "Texture to Tensor only support texture resource with one slice when Compute shader are not available on platform!"); - } - - Assert.IsNotNull(colors); - - for (int x = 0; x < texDataShape.width; ++x) - for (int yTex = 0; yTex < texDataShape.height; ++yTex) - { - int c = channelOffset; - int y = flipY ? texDataShape.height - yTex - 1 : yTex; - - var pixelIndex = yTex * texDataShape.width + x; - Vector4 v = colors[pixelIndex]; - bool specialCaseWhenChannelMaskIsEmptyStoresAverage = true; - for (int i = 0; i < 4; ++i) - { - if (channelWriteMask[i] == 1) - { - int readFrom = channelReadMap[i]; - float value = i < 3 ? 0 : 1; // default values for channels R,G,B=0 and A=1 - float scale = 1.0f; - float bias = 0.0f; - if (readFrom >= 0) - { - value = v[readFrom]; - scale = scale4[readFrom]; - bias = bias4[readFrom]; - } - - output[texDataShape.Index(batchOffset, y, x, c)] = scale * value + bias; - specialCaseWhenChannelMaskIsEmptyStoresAverage = false; - c += 1; - } - } - - if (specialCaseWhenChannelMaskIsEmptyStoresAverage) - { - v = Vector4.Scale(v, scale4) + bias4; - float avg = (v.x + v.y + v.z) / 3.0f; - output[texDataShape.Index(batchOffset, y, x, c)] = avg; - } - } - } - - // TODO@: expose now that Download necesarrily goes via the gpu (compute/pixel) ? - private float[] TextureToTensorDataCache(TensorShape shape) - { - float[] tensorDataCache = new float[shape.length]; - bool flipY = flip == Flip.Y; - - int batchOffset = 0; - int channelOffset = 0; - foreach (var tex in textures) - { - var channelWriteMask = TextureFormatUtils.FormatToChannelMask(tex, interpretPixelAsChannels); - var channelReadMap = TextureFormatUtils.FormatToChannelReadMap(tex, interpretPixelAsChannels); - - FillCacheFromTexture(tensorDataCache, tex, batchOffset, channelOffset, channelWriteMask, channelReadMap, - flipY, scale, bias, shape); - - if (interpretDepthAs == InterpretDepthAs.Batch) - batchOffset += 1; - else if (interpretDepthAs == InterpretDepthAs.Channels) - channelOffset += interpretPixelAsChannels; - } - - return tensorDataCache; - } - - /// - public virtual float[] Download(TensorShape shape) - { - if (ComputeInfo.supportsCompute && SystemInfo.supportsComputeShaders) - { - var gpuBackend = new ReferenceComputeOps(null); - // @TODO: cache compute buffer - using (var computeTensorData = - gpuBackend.TextureToTensorData(this, "__internalDownloadTextureToTensorData")) - { - return computeTensorData.Download(shape); - } - } - else - { - var gpuBackend = new PixelShaderOps(null); - using (var pixelShaderTensorData = - gpuBackend.TextureToTensorData(this, "__internalDownloadTextureToTensorData")) - { - return pixelShaderTensorData.Download(shape); - } - } - } - - /// - public virtual BarracudaArray SharedAccess(out int offset) - { - offset = 0; - return new BarracudaArrayFromManagedArray(Download(shape)); //TODO fp16 - } - - /// - public virtual int maxCapacity => m_Shape.length; - - /// - public virtual DataType dataType => DataType.Float; //todo fp16 - - /// - public virtual bool inUse => true; - - /// - public virtual bool isGPUMem => true; - - /// - /// Dispose - /// - public virtual void Dispose() - { - } -} - -} //namespace Barracuda diff --git a/Packages/com.unity.barracuda/Runtime/Core/TextureAsTensorData.cs.meta b/Packages/com.unity.barracuda/Runtime/Core/TextureAsTensorData.cs.meta deleted file mode 100644 index 0860956..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/TextureAsTensorData.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9efb45881d225884794451e999e5f38b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Core/Unity.Barracuda.asmdef b/Packages/com.unity.barracuda/Runtime/Core/Unity.Barracuda.asmdef deleted file mode 100644 index 6c04153..0000000 --- a/Packages/com.unity.barracuda/Runtime/Core/Unity.Barracuda.asmdef +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "Unity.Barracuda", - "references": [ - "Unity.Burst", - "Unity.Mathematics" - ], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/ONNX.meta b/Packages/com.unity.barracuda/Runtime/ONNX.meta deleted file mode 100644 index b31d3e9..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a35c2ad22abab4076b4b3b7943a34202 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/Generated.meta b/Packages/com.unity.barracuda/Runtime/ONNX/Generated.meta deleted file mode 100644 index f811373..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/Generated.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 16bcd0c303b3d9e4c92fb65f54bf2c91 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/Generated/Onnx.cs b/Packages/com.unity.barracuda/Runtime/ONNX/Generated/Onnx.cs deleted file mode 100644 index 77891eb..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/Generated/Onnx.cs +++ /dev/null @@ -1,4412 +0,0 @@ -// -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: onnx.proto3 -// -#pragma warning disable 1591, 0612, 3021 -#region Designer generated code - -using pb = global::Google.Protobuf; -using pbc = global::Google.Protobuf.Collections; -using pbr = global::Google.Protobuf.Reflection; -using scg = global::System.Collections.Generic; -namespace Onnx { - - /// Holder for reflection information generated from onnx.proto3 - internal static partial class OnnxReflection { - - #region Descriptor - /// File descriptor for onnx.proto3 - public static pbr::FileDescriptor Descriptor { - get { return descriptor; } - } - private static pbr::FileDescriptor descriptor; - - static OnnxReflection() { - byte[] descriptorData = global::System.Convert.FromBase64String( - string.Concat( - "Cgtvbm54LnByb3RvMxIEb25ueCLoBAoOQXR0cmlidXRlUHJvdG8SDAoEbmFt", - "ZRgBIAEoCRIVCg1yZWZfYXR0cl9uYW1lGBUgASgJEhIKCmRvY19zdHJpbmcY", - "DSABKAkSMAoEdHlwZRgUIAEoDjIiLm9ubnguQXR0cmlidXRlUHJvdG8uQXR0", - "cmlidXRlVHlwZRIJCgFmGAIgASgCEgkKAWkYAyABKAMSCQoBcxgEIAEoDBIc", - "CgF0GAUgASgLMhEub25ueC5UZW5zb3JQcm90bxIbCgFnGAYgASgLMhAub25u", - "eC5HcmFwaFByb3RvEi4KDXNwYXJzZV90ZW5zb3IYFiABKAsyFy5vbm54LlNw", - "YXJzZVRlbnNvclByb3RvEg4KBmZsb2F0cxgHIAMoAhIMCgRpbnRzGAggAygD", - "Eg8KB3N0cmluZ3MYCSADKAwSIgoHdGVuc29ycxgKIAMoCzIRLm9ubnguVGVu", - "c29yUHJvdG8SIAoGZ3JhcGhzGAsgAygLMhAub25ueC5HcmFwaFByb3RvEi8K", - "DnNwYXJzZV90ZW5zb3JzGBcgAygLMhcub25ueC5TcGFyc2VUZW5zb3JQcm90", - "byK4AQoNQXR0cmlidXRlVHlwZRINCglVTkRFRklORUQQABIJCgVGTE9BVBAB", - "EgcKA0lOVBACEgoKBlNUUklORxADEgoKBlRFTlNPUhAEEgkKBUdSQVBIEAUS", - "EQoNU1BBUlNFX1RFTlNPUhALEgoKBkZMT0FUUxAGEggKBElOVFMQBxILCgdT", - "VFJJTkdTEAgSCwoHVEVOU09SUxAJEgoKBkdSQVBIUxAKEhIKDlNQQVJTRV9U", - "RU5TT1JTEAwiUQoOVmFsdWVJbmZvUHJvdG8SDAoEbmFtZRgBIAEoCRIdCgR0", - "eXBlGAIgASgLMg8ub25ueC5UeXBlUHJvdG8SEgoKZG9jX3N0cmluZxgDIAEo", - "CSKWAQoJTm9kZVByb3RvEg0KBWlucHV0GAEgAygJEg4KBm91dHB1dBgCIAMo", - "CRIMCgRuYW1lGAMgASgJEg8KB29wX3R5cGUYBCABKAkSDgoGZG9tYWluGAcg", - "ASgJEicKCWF0dHJpYnV0ZRgFIAMoCzIULm9ubnguQXR0cmlidXRlUHJvdG8S", - "EgoKZG9jX3N0cmluZxgGIAEoCSKTAgoKTW9kZWxQcm90bxISCgppcl92ZXJz", - "aW9uGAEgASgDEi4KDG9wc2V0X2ltcG9ydBgIIAMoCzIYLm9ubnguT3BlcmF0", - "b3JTZXRJZFByb3RvEhUKDXByb2R1Y2VyX25hbWUYAiABKAkSGAoQcHJvZHVj", - "ZXJfdmVyc2lvbhgDIAEoCRIOCgZkb21haW4YBCABKAkSFQoNbW9kZWxfdmVy", - "c2lvbhgFIAEoAxISCgpkb2Nfc3RyaW5nGAYgASgJEh8KBWdyYXBoGAcgASgL", - "MhAub25ueC5HcmFwaFByb3RvEjQKDm1ldGFkYXRhX3Byb3BzGA4gAygLMhwu", - "b25ueC5TdHJpbmdTdHJpbmdFbnRyeVByb3RvIjQKFlN0cmluZ1N0cmluZ0Vu", - "dHJ5UHJvdG8SCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJImsKEFRlbnNv", - "ckFubm90YXRpb24SEwoLdGVuc29yX25hbWUYASABKAkSQgoccXVhbnRfcGFy", - "YW1ldGVyX3RlbnNvcl9uYW1lcxgCIAMoCzIcLm9ubnguU3RyaW5nU3RyaW5n", - "RW50cnlQcm90byLYAgoKR3JhcGhQcm90bxIdCgRub2RlGAEgAygLMg8ub25u", - "eC5Ob2RlUHJvdG8SDAoEbmFtZRgCIAEoCRImCgtpbml0aWFsaXplchgFIAMo", - "CzIRLm9ubnguVGVuc29yUHJvdG8SMwoSc3BhcnNlX2luaXRpYWxpemVyGA8g", - "AygLMhcub25ueC5TcGFyc2VUZW5zb3JQcm90bxISCgpkb2Nfc3RyaW5nGAog", - "ASgJEiMKBWlucHV0GAsgAygLMhQub25ueC5WYWx1ZUluZm9Qcm90bxIkCgZv", - "dXRwdXQYDCADKAsyFC5vbm54LlZhbHVlSW5mb1Byb3RvEigKCnZhbHVlX2lu", - "Zm8YDSADKAsyFC5vbm54LlZhbHVlSW5mb1Byb3RvEjcKF3F1YW50aXphdGlv", - "bl9hbm5vdGF0aW9uGA4gAygLMhYub25ueC5UZW5zb3JBbm5vdGF0aW9uIrgF", - "CgtUZW5zb3JQcm90bxIMCgRkaW1zGAEgAygDEhEKCWRhdGFfdHlwZRgCIAEo", - "BRIqCgdzZWdtZW50GAMgASgLMhkub25ueC5UZW5zb3JQcm90by5TZWdtZW50", - "EhYKCmZsb2F0X2RhdGEYBCADKAJCAhABEhYKCmludDMyX2RhdGEYBSADKAVC", - "AhABEhMKC3N0cmluZ19kYXRhGAYgAygMEhYKCmludDY0X2RhdGEYByADKANC", - "AhABEgwKBG5hbWUYCCABKAkSEgoKZG9jX3N0cmluZxgMIAEoCRIQCghyYXdf", - "ZGF0YRgJIAEoDBIzCg1leHRlcm5hbF9kYXRhGA0gAygLMhwub25ueC5TdHJp", - "bmdTdHJpbmdFbnRyeVByb3RvEjUKDWRhdGFfbG9jYXRpb24YDiABKA4yHi5v", - "bm54LlRlbnNvclByb3RvLkRhdGFMb2NhdGlvbhIXCgtkb3VibGVfZGF0YRgK", - "IAMoAUICEAESFwoLdWludDY0X2RhdGEYCyADKARCAhABGiUKB1NlZ21lbnQS", - "DQoFYmVnaW4YASABKAMSCwoDZW5kGAIgASgDItoBCghEYXRhVHlwZRINCglV", - "TkRFRklORUQQABIJCgVGTE9BVBABEgkKBVVJTlQ4EAISCAoESU5UOBADEgoK", - "BlVJTlQxNhAEEgkKBUlOVDE2EAUSCQoFSU5UMzIQBhIJCgVJTlQ2NBAHEgoK", - "BlNUUklORxAIEggKBEJPT0wQCRILCgdGTE9BVDE2EAoSCgoGRE9VQkxFEAsS", - "CgoGVUlOVDMyEAwSCgoGVUlOVDY0EA0SDQoJQ09NUExFWDY0EA4SDgoKQ09N", - "UExFWDEyOBAPEgwKCEJGTE9BVDE2EBAiKQoMRGF0YUxvY2F0aW9uEgsKB0RF", - "RkFVTFQQABIMCghFWFRFUk5BTBABImgKEVNwYXJzZVRlbnNvclByb3RvEiEK", - "BnZhbHVlcxgBIAEoCzIRLm9ubnguVGVuc29yUHJvdG8SIgoHaW5kaWNlcxgC", - "IAEoCzIRLm9ubnguVGVuc29yUHJvdG8SDAoEZGltcxgDIAMoAyKVAQoQVGVu", - "c29yU2hhcGVQcm90bxItCgNkaW0YASADKAsyIC5vbm54LlRlbnNvclNoYXBl", - "UHJvdG8uRGltZW5zaW9uGlIKCURpbWVuc2lvbhITCglkaW1fdmFsdWUYASAB", - "KANIABITCglkaW1fcGFyYW0YAiABKAlIABISCgpkZW5vdGF0aW9uGAMgASgJ", - "QgcKBXZhbHVlIuUBCglUeXBlUHJvdG8SLQoLdGVuc29yX3R5cGUYASABKAsy", - "Fi5vbm54LlR5cGVQcm90by5UZW5zb3JIABISCgpkZW5vdGF0aW9uGAYgASgJ", - "GkIKBlRlbnNvchIRCgllbGVtX3R5cGUYASABKAUSJQoFc2hhcGUYAiABKAsy", - "Fi5vbm54LlRlbnNvclNoYXBlUHJvdG8aSAoMU3BhcnNlVGVuc29yEhEKCWVs", - "ZW1fdHlwZRgBIAEoBRIlCgVzaGFwZRgCIAEoCzIWLm9ubnguVGVuc29yU2hh", - "cGVQcm90b0IHCgV2YWx1ZSI1ChJPcGVyYXRvclNldElkUHJvdG8SDgoGZG9t", - "YWluGAEgASgJEg8KB3ZlcnNpb24YAiABKAMqsQEKB1ZlcnNpb24SEgoOX1NU", - "QVJUX1ZFUlNJT04QABIZChVJUl9WRVJTSU9OXzIwMTdfMTBfMTAQARIZChVJ", - "Ul9WRVJTSU9OXzIwMTdfMTBfMzAQAhIYChRJUl9WRVJTSU9OXzIwMTdfMTFf", - "MxADEhgKFElSX1ZFUlNJT05fMjAxOV8xXzIyEAQSGAoUSVJfVkVSU0lPTl8y", - "MDE5XzNfMTgQBRIOCgpJUl9WRVJTSU9OEAZiBnByb3RvMw==")); - descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, - new pbr::FileDescriptor[] { }, - new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Onnx.Version), }, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.AttributeProto), global::Onnx.AttributeProto.Parser, new[]{ "Name", "RefAttrName", "DocString", "Type", "F", "I", "S", "T", "G", "SparseTensor", "Floats", "Ints", "Strings", "Tensors", "Graphs", "SparseTensors" }, null, new[]{ typeof(global::Onnx.AttributeProto.Types.AttributeType) }, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.ValueInfoProto), global::Onnx.ValueInfoProto.Parser, new[]{ "Name", "Type", "DocString" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.NodeProto), global::Onnx.NodeProto.Parser, new[]{ "Input", "Output", "Name", "OpType", "Domain", "Attribute", "DocString" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.ModelProto), global::Onnx.ModelProto.Parser, new[]{ "IrVersion", "OpsetImport", "ProducerName", "ProducerVersion", "Domain", "ModelVersion", "DocString", "Graph", "MetadataProps" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.StringStringEntryProto), global::Onnx.StringStringEntryProto.Parser, new[]{ "Key", "Value" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorAnnotation), global::Onnx.TensorAnnotation.Parser, new[]{ "TensorName", "QuantParameterTensorNames" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.GraphProto), global::Onnx.GraphProto.Parser, new[]{ "Node", "Name", "Initializer", "SparseInitializer", "DocString", "Input", "Output", "ValueInfo", "QuantizationAnnotation" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorProto), global::Onnx.TensorProto.Parser, new[]{ "Dims", "DataType", "Segment", "FloatData", "Int32Data", "StringData", "Int64Data", "Name", "DocString", "RawData", "ExternalData", "DataLocation", "DoubleData", "Uint64Data" }, null, new[]{ typeof(global::Onnx.TensorProto.Types.DataType), typeof(global::Onnx.TensorProto.Types.DataLocation) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorProto.Types.Segment), global::Onnx.TensorProto.Types.Segment.Parser, new[]{ "Begin", "End" }, null, null, null)}), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.SparseTensorProto), global::Onnx.SparseTensorProto.Parser, new[]{ "Values", "Indices", "Dims" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorShapeProto), global::Onnx.TensorShapeProto.Parser, new[]{ "Dim" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorShapeProto.Types.Dimension), global::Onnx.TensorShapeProto.Types.Dimension.Parser, new[]{ "DimValue", "DimParam", "Denotation" }, new[]{ "Value" }, null, null)}), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TypeProto), global::Onnx.TypeProto.Parser, new[]{ "TensorType", "Denotation" }, new[]{ "Value" }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TypeProto.Types.Tensor), global::Onnx.TypeProto.Types.Tensor.Parser, new[]{ "ElemType", "Shape" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TypeProto.Types.SparseTensor), global::Onnx.TypeProto.Types.SparseTensor.Parser, new[]{ "ElemType", "Shape" }, null, null, null)}), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.OperatorSetIdProto), global::Onnx.OperatorSetIdProto.Parser, new[]{ "Domain", "Version" }, null, null, null) - })); - } - #endregion - - } - #region Enums - /// - /// Versioning - /// - /// ONNX versioning is specified in docs/IR.md and elaborated on in docs/Versioning.md - /// - /// To be compatible with both proto2 and proto3, we will use a version number - /// that is not defined by the default value but an explicit enum number. - /// - internal enum Version { - /// - /// proto3 requires the first enum value to be zero. - /// We add this just to appease the compiler. - /// - [pbr::OriginalName("_START_VERSION")] StartVersion = 0, - /// - /// The version field is always serialized and we will use it to store the - /// version that the graph is generated from. This helps us set up version - /// control. - /// For the IR, we are using simple numbers starting with with 0x00000001, - /// which was the version we published on Oct 10, 2017. - /// - [pbr::OriginalName("IR_VERSION_2017_10_10")] IrVersion20171010 = 1, - /// - /// IR_VERSION 2 published on Oct 30, 2017 - /// - Added type discriminator to AttributeProto to support proto3 users - /// - [pbr::OriginalName("IR_VERSION_2017_10_30")] IrVersion20171030 = 2, - /// - /// IR VERSION 3 published on Nov 3, 2017 - /// - For operator versioning: - /// - Added new message OperatorSetIdProto - /// - Added opset_import in ModelProto - /// - For vendor extensions, added domain in NodeProto - /// - [pbr::OriginalName("IR_VERSION_2017_11_3")] IrVersion2017113 = 3, - /// - /// IR VERSION 4 published on Jan 22, 2019 - /// - Relax constraint that initializers should be a subset of graph inputs - /// - Add type BFLOAT16 - /// - [pbr::OriginalName("IR_VERSION_2019_1_22")] IrVersion2019122 = 4, - /// - /// IR VERSION 5 published on March 18, 2019 - /// - Add message TensorAnnotation. - /// - Add quantization annotation in GraphProto to map tensor with its scale and zero point quantization parameters. - /// - [pbr::OriginalName("IR_VERSION_2019_3_18")] IrVersion2019318 = 5, - /// - /// IR VERSION 6 published on <TBD> - /// - Add support for sparse tensor constants stored in model. - /// - Add message SparseTensorProto - /// - Add sparse initializers - /// - [pbr::OriginalName("IR_VERSION")] IrVersion = 6, - } - - #endregion - - #region Messages - /// - /// Attributes - /// - /// A named attribute containing either singular float, integer, string, graph, - /// and tensor values, or repeated float, integer, string, graph, and tensor values. - /// An AttributeProto MUST contain the name field, and *only one* of the - /// following content fields, effectively enforcing a C/C++ union equivalent. - /// - internal sealed partial class AttributeProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AttributeProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[0]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public AttributeProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public AttributeProto(AttributeProto other) : this() { - name_ = other.name_; - refAttrName_ = other.refAttrName_; - docString_ = other.docString_; - type_ = other.type_; - f_ = other.f_; - i_ = other.i_; - s_ = other.s_; - T = other.t_ != null ? other.T.Clone() : null; - G = other.g_ != null ? other.G.Clone() : null; - SparseTensor = other.sparseTensor_ != null ? other.SparseTensor.Clone() : null; - floats_ = other.floats_.Clone(); - ints_ = other.ints_.Clone(); - strings_ = other.strings_.Clone(); - tensors_ = other.tensors_.Clone(); - graphs_ = other.graphs_.Clone(); - sparseTensors_ = other.sparseTensors_.Clone(); - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public AttributeProto Clone() { - return new AttributeProto(this); - } - - /// Field number for the "name" field. - public const int NameFieldNumber = 1; - private string name_ = ""; - /// - /// The name field MUST be present for this version of the IR. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Name { - get { return name_; } - set { - name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "ref_attr_name" field. - public const int RefAttrNameFieldNumber = 21; - private string refAttrName_ = ""; - /// - /// if ref_attr_name is not empty, ref_attr_name is the attribute name in parent function. - /// In this case, this AttributeProto does not contain data, and it's a reference of attribute - /// in parent scope. - /// NOTE: This should ONLY be used in function (sub-graph). It's invalid to be used in main graph. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string RefAttrName { - get { return refAttrName_; } - set { - refAttrName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "doc_string" field. - public const int DocStringFieldNumber = 13; - private string docString_ = ""; - /// - /// A human-readable documentation for this attribute. Markdown is allowed. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string DocString { - get { return docString_; } - set { - docString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "type" field. - public const int TypeFieldNumber = 20; - private global::Onnx.AttributeProto.Types.AttributeType type_ = 0; - /// - /// The type field MUST be present for this version of the IR. - /// For 0.0.1 versions of the IR, this field was not defined, and - /// implementations needed to use has_field hueristics to determine - /// which value field was in use. For IR_VERSION 0.0.2 or later, this - /// field MUST be set and match the f|i|s|t|... field in use. This - /// change was made to accomodate proto3 implementations. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.AttributeProto.Types.AttributeType Type { - get { return type_; } - set { - type_ = value; - } - } - - /// Field number for the "f" field. - public const int FFieldNumber = 2; - private float f_; - /// - /// Exactly ONE of the following fields must be present for this version of the IR - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public float F { - get { return f_; } - set { - f_ = value; - } - } - - /// Field number for the "i" field. - public const int IFieldNumber = 3; - private long i_; - /// - /// int - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public long I { - get { return i_; } - set { - i_ = value; - } - } - - /// Field number for the "s" field. - public const int SFieldNumber = 4; - private pb::ByteString s_ = pb::ByteString.Empty; - /// - /// UTF-8 string - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pb::ByteString S { - get { return s_; } - set { - s_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "t" field. - public const int TFieldNumber = 5; - private global::Onnx.TensorProto t_; - /// - /// tensor value - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TensorProto T { - get { return t_; } - set { - t_ = value; - } - } - - /// Field number for the "g" field. - public const int GFieldNumber = 6; - private global::Onnx.GraphProto g_; - /// - /// graph - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.GraphProto G { - get { return g_; } - set { - g_ = value; - } - } - - /// Field number for the "sparse_tensor" field. - public const int SparseTensorFieldNumber = 22; - private global::Onnx.SparseTensorProto sparseTensor_; - /// - /// sparse tensor value - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.SparseTensorProto SparseTensor { - get { return sparseTensor_; } - set { - sparseTensor_ = value; - } - } - - /// Field number for the "floats" field. - public const int FloatsFieldNumber = 7; - private static readonly pb::FieldCodec _repeated_floats_codec - = pb::FieldCodec.ForFloat(58); - private readonly pbc::RepeatedField floats_ = new pbc::RepeatedField(); - /// - /// list of floats - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Floats { - get { return floats_; } - } - - /// Field number for the "ints" field. - public const int IntsFieldNumber = 8; - private static readonly pb::FieldCodec _repeated_ints_codec - = pb::FieldCodec.ForInt64(66); - private readonly pbc::RepeatedField ints_ = new pbc::RepeatedField(); - /// - /// list of ints - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Ints { - get { return ints_; } - } - - /// Field number for the "strings" field. - public const int StringsFieldNumber = 9; - private static readonly pb::FieldCodec _repeated_strings_codec - = pb::FieldCodec.ForBytes(74); - private readonly pbc::RepeatedField strings_ = new pbc::RepeatedField(); - /// - /// list of UTF-8 strings - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Strings { - get { return strings_; } - } - - /// Field number for the "tensors" field. - public const int TensorsFieldNumber = 10; - private static readonly pb::FieldCodec _repeated_tensors_codec - = pb::FieldCodec.ForMessage(82, global::Onnx.TensorProto.Parser); - private readonly pbc::RepeatedField tensors_ = new pbc::RepeatedField(); - /// - /// list of tensors - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Tensors { - get { return tensors_; } - } - - /// Field number for the "graphs" field. - public const int GraphsFieldNumber = 11; - private static readonly pb::FieldCodec _repeated_graphs_codec - = pb::FieldCodec.ForMessage(90, global::Onnx.GraphProto.Parser); - private readonly pbc::RepeatedField graphs_ = new pbc::RepeatedField(); - /// - /// list of graph - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Graphs { - get { return graphs_; } - } - - /// Field number for the "sparse_tensors" field. - public const int SparseTensorsFieldNumber = 23; - private static readonly pb::FieldCodec _repeated_sparseTensors_codec - = pb::FieldCodec.ForMessage(186, global::Onnx.SparseTensorProto.Parser); - private readonly pbc::RepeatedField sparseTensors_ = new pbc::RepeatedField(); - /// - /// list of sparse tensors - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField SparseTensors { - get { return sparseTensors_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as AttributeProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(AttributeProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Name != other.Name) return false; - if (RefAttrName != other.RefAttrName) return false; - if (DocString != other.DocString) return false; - if (Type != other.Type) return false; - if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(F, other.F)) return false; - if (I != other.I) return false; - if (S != other.S) return false; - if (!object.Equals(T, other.T)) return false; - if (!object.Equals(G, other.G)) return false; - if (!object.Equals(SparseTensor, other.SparseTensor)) return false; - if(!floats_.Equals(other.floats_)) return false; - if(!ints_.Equals(other.ints_)) return false; - if(!strings_.Equals(other.strings_)) return false; - if(!tensors_.Equals(other.tensors_)) return false; - if(!graphs_.Equals(other.graphs_)) return false; - if(!sparseTensors_.Equals(other.sparseTensors_)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Name.Length != 0) hash ^= Name.GetHashCode(); - if (RefAttrName.Length != 0) hash ^= RefAttrName.GetHashCode(); - if (DocString.Length != 0) hash ^= DocString.GetHashCode(); - if (Type != 0) hash ^= Type.GetHashCode(); - if (F != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(F); - if (I != 0L) hash ^= I.GetHashCode(); - if (S.Length != 0) hash ^= S.GetHashCode(); - if (t_ != null) hash ^= T.GetHashCode(); - if (g_ != null) hash ^= G.GetHashCode(); - if (sparseTensor_ != null) hash ^= SparseTensor.GetHashCode(); - hash ^= floats_.GetHashCode(); - hash ^= ints_.GetHashCode(); - hash ^= strings_.GetHashCode(); - hash ^= tensors_.GetHashCode(); - hash ^= graphs_.GetHashCode(); - hash ^= sparseTensors_.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Name.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Name); - } - if (F != 0F) { - output.WriteRawTag(21); - output.WriteFloat(F); - } - if (I != 0L) { - output.WriteRawTag(24); - output.WriteInt64(I); - } - if (S.Length != 0) { - output.WriteRawTag(34); - output.WriteBytes(S); - } - if (t_ != null) { - output.WriteRawTag(42); - output.WriteMessage(T); - } - if (g_ != null) { - output.WriteRawTag(50); - output.WriteMessage(G); - } - floats_.WriteTo(output, _repeated_floats_codec); - ints_.WriteTo(output, _repeated_ints_codec); - strings_.WriteTo(output, _repeated_strings_codec); - tensors_.WriteTo(output, _repeated_tensors_codec); - graphs_.WriteTo(output, _repeated_graphs_codec); - if (DocString.Length != 0) { - output.WriteRawTag(106); - output.WriteString(DocString); - } - if (Type != 0) { - output.WriteRawTag(160, 1); - output.WriteEnum((int) Type); - } - if (RefAttrName.Length != 0) { - output.WriteRawTag(170, 1); - output.WriteString(RefAttrName); - } - if (sparseTensor_ != null) { - output.WriteRawTag(178, 1); - output.WriteMessage(SparseTensor); - } - sparseTensors_.WriteTo(output, _repeated_sparseTensors_codec); - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Name.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); - } - if (RefAttrName.Length != 0) { - size += 2 + pb::CodedOutputStream.ComputeStringSize(RefAttrName); - } - if (DocString.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(DocString); - } - if (Type != 0) { - size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) Type); - } - if (F != 0F) { - size += 1 + 4; - } - if (I != 0L) { - size += 1 + pb::CodedOutputStream.ComputeInt64Size(I); - } - if (S.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeBytesSize(S); - } - if (t_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(T); - } - if (g_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(G); - } - if (sparseTensor_ != null) { - size += 2 + pb::CodedOutputStream.ComputeMessageSize(SparseTensor); - } - size += floats_.CalculateSize(_repeated_floats_codec); - size += ints_.CalculateSize(_repeated_ints_codec); - size += strings_.CalculateSize(_repeated_strings_codec); - size += tensors_.CalculateSize(_repeated_tensors_codec); - size += graphs_.CalculateSize(_repeated_graphs_codec); - size += sparseTensors_.CalculateSize(_repeated_sparseTensors_codec); - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(AttributeProto other) { - if (other == null) { - return; - } - if (other.Name.Length != 0) { - Name = other.Name; - } - if (other.RefAttrName.Length != 0) { - RefAttrName = other.RefAttrName; - } - if (other.DocString.Length != 0) { - DocString = other.DocString; - } - if (other.Type != 0) { - Type = other.Type; - } - if (other.F != 0F) { - F = other.F; - } - if (other.I != 0L) { - I = other.I; - } - if (other.S.Length != 0) { - S = other.S; - } - if (other.t_ != null) { - if (t_ == null) { - t_ = new global::Onnx.TensorProto(); - } - T.MergeFrom(other.T); - } - if (other.g_ != null) { - if (g_ == null) { - g_ = new global::Onnx.GraphProto(); - } - G.MergeFrom(other.G); - } - if (other.sparseTensor_ != null) { - if (sparseTensor_ == null) { - sparseTensor_ = new global::Onnx.SparseTensorProto(); - } - SparseTensor.MergeFrom(other.SparseTensor); - } - floats_.Add(other.floats_); - ints_.Add(other.ints_); - strings_.Add(other.strings_); - tensors_.Add(other.tensors_); - graphs_.Add(other.graphs_); - sparseTensors_.Add(other.sparseTensors_); - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Name = input.ReadString(); - break; - } - case 21: { - F = input.ReadFloat(); - break; - } - case 24: { - I = input.ReadInt64(); - break; - } - case 34: { - S = input.ReadBytes(); - break; - } - case 42: { - if (t_ == null) { - t_ = new global::Onnx.TensorProto(); - } - input.ReadMessage(t_); - break; - } - case 50: { - if (g_ == null) { - g_ = new global::Onnx.GraphProto(); - } - input.ReadMessage(g_); - break; - } - case 58: - case 61: { - floats_.AddEntriesFrom(input, _repeated_floats_codec); - break; - } - case 66: - case 64: { - ints_.AddEntriesFrom(input, _repeated_ints_codec); - break; - } - case 74: { - strings_.AddEntriesFrom(input, _repeated_strings_codec); - break; - } - case 82: { - tensors_.AddEntriesFrom(input, _repeated_tensors_codec); - break; - } - case 90: { - graphs_.AddEntriesFrom(input, _repeated_graphs_codec); - break; - } - case 106: { - DocString = input.ReadString(); - break; - } - case 160: { - type_ = (global::Onnx.AttributeProto.Types.AttributeType) input.ReadEnum(); - break; - } - case 170: { - RefAttrName = input.ReadString(); - break; - } - case 178: { - if (sparseTensor_ == null) { - sparseTensor_ = new global::Onnx.SparseTensorProto(); - } - input.ReadMessage(sparseTensor_); - break; - } - case 186: { - sparseTensors_.AddEntriesFrom(input, _repeated_sparseTensors_codec); - break; - } - } - } - } - - #region Nested types - /// Container for nested types declared in the AttributeProto message type. - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static partial class Types { - /// - /// Note: this enum is structurally identical to the OpSchema::AttrType - /// enum defined in schema.h. If you rev one, you likely need to rev the other. - /// - internal enum AttributeType { - [pbr::OriginalName("UNDEFINED")] Undefined = 0, - [pbr::OriginalName("FLOAT")] Float = 1, - [pbr::OriginalName("INT")] Int = 2, - [pbr::OriginalName("STRING")] String = 3, - [pbr::OriginalName("TENSOR")] Tensor = 4, - [pbr::OriginalName("GRAPH")] Graph = 5, - [pbr::OriginalName("SPARSE_TENSOR")] SparseTensor = 11, - [pbr::OriginalName("FLOATS")] Floats = 6, - [pbr::OriginalName("INTS")] Ints = 7, - [pbr::OriginalName("STRINGS")] Strings = 8, - [pbr::OriginalName("TENSORS")] Tensors = 9, - [pbr::OriginalName("GRAPHS")] Graphs = 10, - [pbr::OriginalName("SPARSE_TENSORS")] SparseTensors = 12, - } - - } - #endregion - - } - - /// - /// Defines information on value, including the name, the type, and - /// the shape of the value. - /// - internal sealed partial class ValueInfoProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ValueInfoProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[1]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public ValueInfoProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public ValueInfoProto(ValueInfoProto other) : this() { - name_ = other.name_; - Type = other.type_ != null ? other.Type.Clone() : null; - docString_ = other.docString_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public ValueInfoProto Clone() { - return new ValueInfoProto(this); - } - - /// Field number for the "name" field. - public const int NameFieldNumber = 1; - private string name_ = ""; - /// - /// This field MUST be present in this version of the IR. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Name { - get { return name_; } - set { - name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "type" field. - public const int TypeFieldNumber = 2; - private global::Onnx.TypeProto type_; - /// - /// This field MUST be present in this version of the IR. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TypeProto Type { - get { return type_; } - set { - type_ = value; - } - } - - /// Field number for the "doc_string" field. - public const int DocStringFieldNumber = 3; - private string docString_ = ""; - /// - /// A human-readable documentation for this value. Markdown is allowed. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string DocString { - get { return docString_; } - set { - docString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as ValueInfoProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(ValueInfoProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Name != other.Name) return false; - if (!object.Equals(Type, other.Type)) return false; - if (DocString != other.DocString) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Name.Length != 0) hash ^= Name.GetHashCode(); - if (type_ != null) hash ^= Type.GetHashCode(); - if (DocString.Length != 0) hash ^= DocString.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Name.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Name); - } - if (type_ != null) { - output.WriteRawTag(18); - output.WriteMessage(Type); - } - if (DocString.Length != 0) { - output.WriteRawTag(26); - output.WriteString(DocString); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Name.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); - } - if (type_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Type); - } - if (DocString.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(DocString); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(ValueInfoProto other) { - if (other == null) { - return; - } - if (other.Name.Length != 0) { - Name = other.Name; - } - if (other.type_ != null) { - if (type_ == null) { - type_ = new global::Onnx.TypeProto(); - } - Type.MergeFrom(other.Type); - } - if (other.DocString.Length != 0) { - DocString = other.DocString; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Name = input.ReadString(); - break; - } - case 18: { - if (type_ == null) { - type_ = new global::Onnx.TypeProto(); - } - input.ReadMessage(type_); - break; - } - case 26: { - DocString = input.ReadString(); - break; - } - } - } - } - - } - - /// - /// Nodes - /// - /// Computation graphs are made up of a DAG of nodes, which represent what is - /// commonly called a "layer" or "pipeline stage" in machine learning frameworks. - /// - /// For example, it can be a node of type "Conv" that takes in an image, a filter - /// tensor and a bias tensor, and produces the convolved output. - /// - internal sealed partial class NodeProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NodeProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[2]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public NodeProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public NodeProto(NodeProto other) : this() { - input_ = other.input_.Clone(); - output_ = other.output_.Clone(); - name_ = other.name_; - opType_ = other.opType_; - domain_ = other.domain_; - attribute_ = other.attribute_.Clone(); - docString_ = other.docString_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public NodeProto Clone() { - return new NodeProto(this); - } - - /// Field number for the "input" field. - public const int InputFieldNumber = 1; - private static readonly pb::FieldCodec _repeated_input_codec - = pb::FieldCodec.ForString(10); - private readonly pbc::RepeatedField input_ = new pbc::RepeatedField(); - /// - /// namespace Value - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Input { - get { return input_; } - } - - /// Field number for the "output" field. - public const int OutputFieldNumber = 2; - private static readonly pb::FieldCodec _repeated_output_codec - = pb::FieldCodec.ForString(18); - private readonly pbc::RepeatedField output_ = new pbc::RepeatedField(); - /// - /// namespace Value - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Output { - get { return output_; } - } - - /// Field number for the "name" field. - public const int NameFieldNumber = 3; - private string name_ = ""; - /// - /// An optional identifier for this node in a graph. - /// This field MAY be absent in ths version of the IR. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Name { - get { return name_; } - set { - name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "op_type" field. - public const int OpTypeFieldNumber = 4; - private string opType_ = ""; - /// - /// The symbolic identifier of the Operator to execute. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string OpType { - get { return opType_; } - set { - opType_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "domain" field. - public const int DomainFieldNumber = 7; - private string domain_ = ""; - /// - /// The domain of the OperatorSet that specifies the operator named by op_type. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Domain { - get { return domain_; } - set { - domain_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "attribute" field. - public const int AttributeFieldNumber = 5; - private static readonly pb::FieldCodec _repeated_attribute_codec - = pb::FieldCodec.ForMessage(42, global::Onnx.AttributeProto.Parser); - private readonly pbc::RepeatedField attribute_ = new pbc::RepeatedField(); - /// - /// Additional named attributes. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Attribute { - get { return attribute_; } - } - - /// Field number for the "doc_string" field. - public const int DocStringFieldNumber = 6; - private string docString_ = ""; - /// - /// A human-readable documentation for this node. Markdown is allowed. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string DocString { - get { return docString_; } - set { - docString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as NodeProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(NodeProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if(!input_.Equals(other.input_)) return false; - if(!output_.Equals(other.output_)) return false; - if (Name != other.Name) return false; - if (OpType != other.OpType) return false; - if (Domain != other.Domain) return false; - if(!attribute_.Equals(other.attribute_)) return false; - if (DocString != other.DocString) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - hash ^= input_.GetHashCode(); - hash ^= output_.GetHashCode(); - if (Name.Length != 0) hash ^= Name.GetHashCode(); - if (OpType.Length != 0) hash ^= OpType.GetHashCode(); - if (Domain.Length != 0) hash ^= Domain.GetHashCode(); - hash ^= attribute_.GetHashCode(); - if (DocString.Length != 0) hash ^= DocString.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - input_.WriteTo(output, _repeated_input_codec); - output_.WriteTo(output, _repeated_output_codec); - if (Name.Length != 0) { - output.WriteRawTag(26); - output.WriteString(Name); - } - if (OpType.Length != 0) { - output.WriteRawTag(34); - output.WriteString(OpType); - } - attribute_.WriteTo(output, _repeated_attribute_codec); - if (DocString.Length != 0) { - output.WriteRawTag(50); - output.WriteString(DocString); - } - if (Domain.Length != 0) { - output.WriteRawTag(58); - output.WriteString(Domain); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - size += input_.CalculateSize(_repeated_input_codec); - size += output_.CalculateSize(_repeated_output_codec); - if (Name.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); - } - if (OpType.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(OpType); - } - if (Domain.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Domain); - } - size += attribute_.CalculateSize(_repeated_attribute_codec); - if (DocString.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(DocString); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(NodeProto other) { - if (other == null) { - return; - } - input_.Add(other.input_); - output_.Add(other.output_); - if (other.Name.Length != 0) { - Name = other.Name; - } - if (other.OpType.Length != 0) { - OpType = other.OpType; - } - if (other.Domain.Length != 0) { - Domain = other.Domain; - } - attribute_.Add(other.attribute_); - if (other.DocString.Length != 0) { - DocString = other.DocString; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - input_.AddEntriesFrom(input, _repeated_input_codec); - break; - } - case 18: { - output_.AddEntriesFrom(input, _repeated_output_codec); - break; - } - case 26: { - Name = input.ReadString(); - break; - } - case 34: { - OpType = input.ReadString(); - break; - } - case 42: { - attribute_.AddEntriesFrom(input, _repeated_attribute_codec); - break; - } - case 50: { - DocString = input.ReadString(); - break; - } - case 58: { - Domain = input.ReadString(); - break; - } - } - } - } - - } - - /// - /// Models - /// - /// ModelProto is a top-level file/container format for bundling a ML model and - /// associating its computation graph with metadata. - /// - /// The semantics of the model are described by the associated GraphProto. - /// - internal sealed partial class ModelProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ModelProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[3]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public ModelProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public ModelProto(ModelProto other) : this() { - irVersion_ = other.irVersion_; - opsetImport_ = other.opsetImport_.Clone(); - producerName_ = other.producerName_; - producerVersion_ = other.producerVersion_; - domain_ = other.domain_; - modelVersion_ = other.modelVersion_; - docString_ = other.docString_; - Graph = other.graph_ != null ? other.Graph.Clone() : null; - metadataProps_ = other.metadataProps_.Clone(); - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public ModelProto Clone() { - return new ModelProto(this); - } - - /// Field number for the "ir_version" field. - public const int IrVersionFieldNumber = 1; - private long irVersion_; - /// - /// The version of the IR this model targets. See Version enum above. - /// This field MUST be present. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public long IrVersion { - get { return irVersion_; } - set { - irVersion_ = value; - } - } - - /// Field number for the "opset_import" field. - public const int OpsetImportFieldNumber = 8; - private static readonly pb::FieldCodec _repeated_opsetImport_codec - = pb::FieldCodec.ForMessage(66, global::Onnx.OperatorSetIdProto.Parser); - private readonly pbc::RepeatedField opsetImport_ = new pbc::RepeatedField(); - /// - /// The OperatorSets this model relies on. - /// All ModelProtos MUST have at least one entry that - /// specifies which version of the ONNX OperatorSet is - /// being imported. - /// - /// All nodes in the ModelProto's graph will bind against the operator - /// with the same-domain/same-op_type operator with the HIGHEST version - /// in the referenced operator sets. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField OpsetImport { - get { return opsetImport_; } - } - - /// Field number for the "producer_name" field. - public const int ProducerNameFieldNumber = 2; - private string producerName_ = ""; - /// - /// The name of the framework or tool used to generate this model. - /// This field SHOULD be present to indicate which implementation/tool/framework - /// emitted the model. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string ProducerName { - get { return producerName_; } - set { - producerName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "producer_version" field. - public const int ProducerVersionFieldNumber = 3; - private string producerVersion_ = ""; - /// - /// The version of the framework or tool used to generate this model. - /// This field SHOULD be present to indicate which implementation/tool/framework - /// emitted the model. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string ProducerVersion { - get { return producerVersion_; } - set { - producerVersion_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "domain" field. - public const int DomainFieldNumber = 4; - private string domain_ = ""; - /// - /// Domain name of the model. - /// We use reverse domain names as name space indicators. For example: - /// `com.facebook.fair` or `com.microsoft.cognitiveservices` - /// - /// Together with `model_version` and GraphProto.name, this forms the unique identity of - /// the graph. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Domain { - get { return domain_; } - set { - domain_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "model_version" field. - public const int ModelVersionFieldNumber = 5; - private long modelVersion_; - /// - /// The version of the graph encoded. See Version enum below. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public long ModelVersion { - get { return modelVersion_; } - set { - modelVersion_ = value; - } - } - - /// Field number for the "doc_string" field. - public const int DocStringFieldNumber = 6; - private string docString_ = ""; - /// - /// A human-readable documentation for this model. Markdown is allowed. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string DocString { - get { return docString_; } - set { - docString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "graph" field. - public const int GraphFieldNumber = 7; - private global::Onnx.GraphProto graph_; - /// - /// The parameterized graph that is evaluated to execute the model. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.GraphProto Graph { - get { return graph_; } - set { - graph_ = value; - } - } - - /// Field number for the "metadata_props" field. - public const int MetadataPropsFieldNumber = 14; - private static readonly pb::FieldCodec _repeated_metadataProps_codec - = pb::FieldCodec.ForMessage(114, global::Onnx.StringStringEntryProto.Parser); - private readonly pbc::RepeatedField metadataProps_ = new pbc::RepeatedField(); - /// - /// Named metadata values; keys should be distinct. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField MetadataProps { - get { return metadataProps_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as ModelProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(ModelProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (IrVersion != other.IrVersion) return false; - if(!opsetImport_.Equals(other.opsetImport_)) return false; - if (ProducerName != other.ProducerName) return false; - if (ProducerVersion != other.ProducerVersion) return false; - if (Domain != other.Domain) return false; - if (ModelVersion != other.ModelVersion) return false; - if (DocString != other.DocString) return false; - if (!object.Equals(Graph, other.Graph)) return false; - if(!metadataProps_.Equals(other.metadataProps_)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (IrVersion != 0L) hash ^= IrVersion.GetHashCode(); - hash ^= opsetImport_.GetHashCode(); - if (ProducerName.Length != 0) hash ^= ProducerName.GetHashCode(); - if (ProducerVersion.Length != 0) hash ^= ProducerVersion.GetHashCode(); - if (Domain.Length != 0) hash ^= Domain.GetHashCode(); - if (ModelVersion != 0L) hash ^= ModelVersion.GetHashCode(); - if (DocString.Length != 0) hash ^= DocString.GetHashCode(); - if (graph_ != null) hash ^= Graph.GetHashCode(); - hash ^= metadataProps_.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (IrVersion != 0L) { - output.WriteRawTag(8); - output.WriteInt64(IrVersion); - } - if (ProducerName.Length != 0) { - output.WriteRawTag(18); - output.WriteString(ProducerName); - } - if (ProducerVersion.Length != 0) { - output.WriteRawTag(26); - output.WriteString(ProducerVersion); - } - if (Domain.Length != 0) { - output.WriteRawTag(34); - output.WriteString(Domain); - } - if (ModelVersion != 0L) { - output.WriteRawTag(40); - output.WriteInt64(ModelVersion); - } - if (DocString.Length != 0) { - output.WriteRawTag(50); - output.WriteString(DocString); - } - if (graph_ != null) { - output.WriteRawTag(58); - output.WriteMessage(Graph); - } - opsetImport_.WriteTo(output, _repeated_opsetImport_codec); - metadataProps_.WriteTo(output, _repeated_metadataProps_codec); - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (IrVersion != 0L) { - size += 1 + pb::CodedOutputStream.ComputeInt64Size(IrVersion); - } - size += opsetImport_.CalculateSize(_repeated_opsetImport_codec); - if (ProducerName.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(ProducerName); - } - if (ProducerVersion.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(ProducerVersion); - } - if (Domain.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Domain); - } - if (ModelVersion != 0L) { - size += 1 + pb::CodedOutputStream.ComputeInt64Size(ModelVersion); - } - if (DocString.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(DocString); - } - if (graph_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Graph); - } - size += metadataProps_.CalculateSize(_repeated_metadataProps_codec); - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(ModelProto other) { - if (other == null) { - return; - } - if (other.IrVersion != 0L) { - IrVersion = other.IrVersion; - } - opsetImport_.Add(other.opsetImport_); - if (other.ProducerName.Length != 0) { - ProducerName = other.ProducerName; - } - if (other.ProducerVersion.Length != 0) { - ProducerVersion = other.ProducerVersion; - } - if (other.Domain.Length != 0) { - Domain = other.Domain; - } - if (other.ModelVersion != 0L) { - ModelVersion = other.ModelVersion; - } - if (other.DocString.Length != 0) { - DocString = other.DocString; - } - if (other.graph_ != null) { - if (graph_ == null) { - graph_ = new global::Onnx.GraphProto(); - } - Graph.MergeFrom(other.Graph); - } - metadataProps_.Add(other.metadataProps_); - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 8: { - IrVersion = input.ReadInt64(); - break; - } - case 18: { - ProducerName = input.ReadString(); - break; - } - case 26: { - ProducerVersion = input.ReadString(); - break; - } - case 34: { - Domain = input.ReadString(); - break; - } - case 40: { - ModelVersion = input.ReadInt64(); - break; - } - case 50: { - DocString = input.ReadString(); - break; - } - case 58: { - if (graph_ == null) { - graph_ = new global::Onnx.GraphProto(); - } - input.ReadMessage(graph_); - break; - } - case 66: { - opsetImport_.AddEntriesFrom(input, _repeated_opsetImport_codec); - break; - } - case 114: { - metadataProps_.AddEntriesFrom(input, _repeated_metadataProps_codec); - break; - } - } - } - } - - } - - /// - /// StringStringEntryProto follows the pattern for cross-proto-version maps. - /// See https://developers.google.com/protocol-buffers/docs/proto3#maps - /// - internal sealed partial class StringStringEntryProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StringStringEntryProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[4]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public StringStringEntryProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public StringStringEntryProto(StringStringEntryProto other) : this() { - key_ = other.key_; - value_ = other.value_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public StringStringEntryProto Clone() { - return new StringStringEntryProto(this); - } - - /// Field number for the "key" field. - public const int KeyFieldNumber = 1; - private string key_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Key { - get { return key_; } - set { - key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "value" field. - public const int ValueFieldNumber = 2; - private string value_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Value { - get { return value_; } - set { - value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as StringStringEntryProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(StringStringEntryProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Key != other.Key) return false; - if (Value != other.Value) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Key.Length != 0) hash ^= Key.GetHashCode(); - if (Value.Length != 0) hash ^= Value.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Key.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Key); - } - if (Value.Length != 0) { - output.WriteRawTag(18); - output.WriteString(Value); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Key.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); - } - if (Value.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Value); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(StringStringEntryProto other) { - if (other == null) { - return; - } - if (other.Key.Length != 0) { - Key = other.Key; - } - if (other.Value.Length != 0) { - Value = other.Value; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Key = input.ReadString(); - break; - } - case 18: { - Value = input.ReadString(); - break; - } - } - } - } - - } - - internal sealed partial class TensorAnnotation : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TensorAnnotation()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[5]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorAnnotation() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorAnnotation(TensorAnnotation other) : this() { - tensorName_ = other.tensorName_; - quantParameterTensorNames_ = other.quantParameterTensorNames_.Clone(); - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorAnnotation Clone() { - return new TensorAnnotation(this); - } - - /// Field number for the "tensor_name" field. - public const int TensorNameFieldNumber = 1; - private string tensorName_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string TensorName { - get { return tensorName_; } - set { - tensorName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "quant_parameter_tensor_names" field. - public const int QuantParameterTensorNamesFieldNumber = 2; - private static readonly pb::FieldCodec _repeated_quantParameterTensorNames_codec - = pb::FieldCodec.ForMessage(18, global::Onnx.StringStringEntryProto.Parser); - private readonly pbc::RepeatedField quantParameterTensorNames_ = new pbc::RepeatedField(); - /// - /// <key, value> pairs to annotate tensor specified by <tensor_name> above. - /// The keys used in the mapping below must be pre-defined in ONNX spec. - /// For example, for 8-bit linear quantization case, 'SCALE_TENSOR', 'ZERO_POINT_TENSOR' will be pre-defined as - /// quantization parameter keys. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField QuantParameterTensorNames { - get { return quantParameterTensorNames_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as TensorAnnotation); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(TensorAnnotation other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (TensorName != other.TensorName) return false; - if(!quantParameterTensorNames_.Equals(other.quantParameterTensorNames_)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (TensorName.Length != 0) hash ^= TensorName.GetHashCode(); - hash ^= quantParameterTensorNames_.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (TensorName.Length != 0) { - output.WriteRawTag(10); - output.WriteString(TensorName); - } - quantParameterTensorNames_.WriteTo(output, _repeated_quantParameterTensorNames_codec); - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (TensorName.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(TensorName); - } - size += quantParameterTensorNames_.CalculateSize(_repeated_quantParameterTensorNames_codec); - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(TensorAnnotation other) { - if (other == null) { - return; - } - if (other.TensorName.Length != 0) { - TensorName = other.TensorName; - } - quantParameterTensorNames_.Add(other.quantParameterTensorNames_); - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - TensorName = input.ReadString(); - break; - } - case 18: { - quantParameterTensorNames_.AddEntriesFrom(input, _repeated_quantParameterTensorNames_codec); - break; - } - } - } - } - - } - - /// - /// Graphs - /// - /// A graph defines the computational logic of a model and is comprised of a parameterized - /// list of nodes that form a directed acyclic graph based on their inputs and outputs. - /// This is the equivalent of the "network" or "graph" in many deep learning - /// frameworks. - /// - internal sealed partial class GraphProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GraphProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[6]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public GraphProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public GraphProto(GraphProto other) : this() { - node_ = other.node_.Clone(); - name_ = other.name_; - initializer_ = other.initializer_.Clone(); - sparseInitializer_ = other.sparseInitializer_.Clone(); - docString_ = other.docString_; - input_ = other.input_.Clone(); - output_ = other.output_.Clone(); - valueInfo_ = other.valueInfo_.Clone(); - quantizationAnnotation_ = other.quantizationAnnotation_.Clone(); - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public GraphProto Clone() { - return new GraphProto(this); - } - - /// Field number for the "node" field. - public const int NodeFieldNumber = 1; - private static readonly pb::FieldCodec _repeated_node_codec - = pb::FieldCodec.ForMessage(10, global::Onnx.NodeProto.Parser); - private readonly pbc::RepeatedField node_ = new pbc::RepeatedField(); - /// - /// The nodes in the graph, sorted topologically. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Node { - get { return node_; } - } - - /// Field number for the "name" field. - public const int NameFieldNumber = 2; - private string name_ = ""; - /// - /// The name of the graph. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Name { - get { return name_; } - set { - name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "initializer" field. - public const int InitializerFieldNumber = 5; - private static readonly pb::FieldCodec _repeated_initializer_codec - = pb::FieldCodec.ForMessage(42, global::Onnx.TensorProto.Parser); - private readonly pbc::RepeatedField initializer_ = new pbc::RepeatedField(); - /// - /// A list of named tensor values, used to specify constant inputs of the graph. - /// Each TensorProto entry must have a distinct name (within the list) that - /// MAY also appear in the input list. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Initializer { - get { return initializer_; } - } - - /// Field number for the "sparse_initializer" field. - public const int SparseInitializerFieldNumber = 15; - private static readonly pb::FieldCodec _repeated_sparseInitializer_codec - = pb::FieldCodec.ForMessage(122, global::Onnx.SparseTensorProto.Parser); - private readonly pbc::RepeatedField sparseInitializer_ = new pbc::RepeatedField(); - /// - /// Initializers (see above) stored in sparse format. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField SparseInitializer { - get { return sparseInitializer_; } - } - - /// Field number for the "doc_string" field. - public const int DocStringFieldNumber = 10; - private string docString_ = ""; - /// - /// A human-readable documentation for this graph. Markdown is allowed. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string DocString { - get { return docString_; } - set { - docString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "input" field. - public const int InputFieldNumber = 11; - private static readonly pb::FieldCodec _repeated_input_codec - = pb::FieldCodec.ForMessage(90, global::Onnx.ValueInfoProto.Parser); - private readonly pbc::RepeatedField input_ = new pbc::RepeatedField(); - /// - /// The inputs and outputs of the graph. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Input { - get { return input_; } - } - - /// Field number for the "output" field. - public const int OutputFieldNumber = 12; - private static readonly pb::FieldCodec _repeated_output_codec - = pb::FieldCodec.ForMessage(98, global::Onnx.ValueInfoProto.Parser); - private readonly pbc::RepeatedField output_ = new pbc::RepeatedField(); - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Output { - get { return output_; } - } - - /// Field number for the "value_info" field. - public const int ValueInfoFieldNumber = 13; - private static readonly pb::FieldCodec _repeated_valueInfo_codec - = pb::FieldCodec.ForMessage(106, global::Onnx.ValueInfoProto.Parser); - private readonly pbc::RepeatedField valueInfo_ = new pbc::RepeatedField(); - /// - /// Information for the values in the graph. The ValueInfoProto.name's - /// must be distinct. It is optional for a value to appear in value_info list. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField ValueInfo { - get { return valueInfo_; } - } - - /// Field number for the "quantization_annotation" field. - public const int QuantizationAnnotationFieldNumber = 14; - private static readonly pb::FieldCodec _repeated_quantizationAnnotation_codec - = pb::FieldCodec.ForMessage(114, global::Onnx.TensorAnnotation.Parser); - private readonly pbc::RepeatedField quantizationAnnotation_ = new pbc::RepeatedField(); - /// - /// This field carries information to indicate the mapping among a tensor and its - /// quantization parameter tensors. For example: - /// For tensor 'a', it may have {'SCALE_TENSOR', 'a_scale'} and {'ZERO_POINT_TENSOR', 'a_zero_point'} annotated, - /// which means, tensor 'a_scale' and tensor 'a_zero_point' are scale and zero point of tensor 'a' in the model. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField QuantizationAnnotation { - get { return quantizationAnnotation_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as GraphProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(GraphProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if(!node_.Equals(other.node_)) return false; - if (Name != other.Name) return false; - if(!initializer_.Equals(other.initializer_)) return false; - if(!sparseInitializer_.Equals(other.sparseInitializer_)) return false; - if (DocString != other.DocString) return false; - if(!input_.Equals(other.input_)) return false; - if(!output_.Equals(other.output_)) return false; - if(!valueInfo_.Equals(other.valueInfo_)) return false; - if(!quantizationAnnotation_.Equals(other.quantizationAnnotation_)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - hash ^= node_.GetHashCode(); - if (Name.Length != 0) hash ^= Name.GetHashCode(); - hash ^= initializer_.GetHashCode(); - hash ^= sparseInitializer_.GetHashCode(); - if (DocString.Length != 0) hash ^= DocString.GetHashCode(); - hash ^= input_.GetHashCode(); - hash ^= output_.GetHashCode(); - hash ^= valueInfo_.GetHashCode(); - hash ^= quantizationAnnotation_.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - node_.WriteTo(output, _repeated_node_codec); - if (Name.Length != 0) { - output.WriteRawTag(18); - output.WriteString(Name); - } - initializer_.WriteTo(output, _repeated_initializer_codec); - if (DocString.Length != 0) { - output.WriteRawTag(82); - output.WriteString(DocString); - } - input_.WriteTo(output, _repeated_input_codec); - output_.WriteTo(output, _repeated_output_codec); - valueInfo_.WriteTo(output, _repeated_valueInfo_codec); - quantizationAnnotation_.WriteTo(output, _repeated_quantizationAnnotation_codec); - sparseInitializer_.WriteTo(output, _repeated_sparseInitializer_codec); - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - size += node_.CalculateSize(_repeated_node_codec); - if (Name.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); - } - size += initializer_.CalculateSize(_repeated_initializer_codec); - size += sparseInitializer_.CalculateSize(_repeated_sparseInitializer_codec); - if (DocString.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(DocString); - } - size += input_.CalculateSize(_repeated_input_codec); - size += output_.CalculateSize(_repeated_output_codec); - size += valueInfo_.CalculateSize(_repeated_valueInfo_codec); - size += quantizationAnnotation_.CalculateSize(_repeated_quantizationAnnotation_codec); - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(GraphProto other) { - if (other == null) { - return; - } - node_.Add(other.node_); - if (other.Name.Length != 0) { - Name = other.Name; - } - initializer_.Add(other.initializer_); - sparseInitializer_.Add(other.sparseInitializer_); - if (other.DocString.Length != 0) { - DocString = other.DocString; - } - input_.Add(other.input_); - output_.Add(other.output_); - valueInfo_.Add(other.valueInfo_); - quantizationAnnotation_.Add(other.quantizationAnnotation_); - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - node_.AddEntriesFrom(input, _repeated_node_codec); - break; - } - case 18: { - Name = input.ReadString(); - break; - } - case 42: { - initializer_.AddEntriesFrom(input, _repeated_initializer_codec); - break; - } - case 82: { - DocString = input.ReadString(); - break; - } - case 90: { - input_.AddEntriesFrom(input, _repeated_input_codec); - break; - } - case 98: { - output_.AddEntriesFrom(input, _repeated_output_codec); - break; - } - case 106: { - valueInfo_.AddEntriesFrom(input, _repeated_valueInfo_codec); - break; - } - case 114: { - quantizationAnnotation_.AddEntriesFrom(input, _repeated_quantizationAnnotation_codec); - break; - } - case 122: { - sparseInitializer_.AddEntriesFrom(input, _repeated_sparseInitializer_codec); - break; - } - } - } - } - - } - - /// - /// Tensors - /// - /// A serialized tensor value. - /// - internal sealed partial class TensorProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TensorProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[7]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorProto(TensorProto other) : this() { - dims_ = other.dims_.Clone(); - dataType_ = other.dataType_; - Segment = other.segment_ != null ? other.Segment.Clone() : null; - floatData_ = other.floatData_.Clone(); - int32Data_ = other.int32Data_.Clone(); - stringData_ = other.stringData_.Clone(); - int64Data_ = other.int64Data_.Clone(); - name_ = other.name_; - docString_ = other.docString_; - rawData_ = other.rawData_; - externalData_ = other.externalData_.Clone(); - dataLocation_ = other.dataLocation_; - doubleData_ = other.doubleData_.Clone(); - uint64Data_ = other.uint64Data_.Clone(); - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorProto Clone() { - return new TensorProto(this); - } - - /// Field number for the "dims" field. - public const int DimsFieldNumber = 1; - private static readonly pb::FieldCodec _repeated_dims_codec - = pb::FieldCodec.ForInt64(10); - private readonly pbc::RepeatedField dims_ = new pbc::RepeatedField(); - /// - /// The shape of the tensor. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Dims { - get { return dims_; } - } - - /// Field number for the "data_type" field. - public const int DataTypeFieldNumber = 2; - private int dataType_; - /// - /// The data type of the tensor. - /// This field MUST have a valid TensorProto.DataType value - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int DataType { - get { return dataType_; } - set { - dataType_ = value; - } - } - - /// Field number for the "segment" field. - public const int SegmentFieldNumber = 3; - private global::Onnx.TensorProto.Types.Segment segment_; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TensorProto.Types.Segment Segment { - get { return segment_; } - set { - segment_ = value; - } - } - - /// Field number for the "float_data" field. - public const int FloatDataFieldNumber = 4; - private static readonly pb::FieldCodec _repeated_floatData_codec - = pb::FieldCodec.ForFloat(34); - private readonly pbc::RepeatedField floatData_ = new pbc::RepeatedField(); - /// - /// For float and complex64 values - /// Complex64 tensors are encoded as a single array of floats, - /// with the real components appearing in odd numbered positions, - /// and the corresponding imaginary component apparing in the - /// subsequent even numbered position. (e.g., [1.0 + 2.0i, 3.0 + 4.0i] - /// is encoded as [1.0, 2.0 ,3.0 ,4.0] - /// When this field is present, the data_type field MUST be FLOAT or COMPLEX64. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField FloatData { - get { return floatData_; } - } - - /// Field number for the "int32_data" field. - public const int Int32DataFieldNumber = 5; - private static readonly pb::FieldCodec _repeated_int32Data_codec - = pb::FieldCodec.ForInt32(42); - private readonly pbc::RepeatedField int32Data_ = new pbc::RepeatedField(); - /// - /// For int32, uint8, int8, uint16, int16, bool, and float16 values - /// float16 values must be bit-wise converted to an uint16_t prior - /// to writing to the buffer. - /// When this field is present, the data_type field MUST be - /// INT32, INT16, INT8, UINT16, UINT8, BOOL, or FLOAT16 - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Int32Data { - get { return int32Data_; } - } - - /// Field number for the "string_data" field. - public const int StringDataFieldNumber = 6; - private static readonly pb::FieldCodec _repeated_stringData_codec - = pb::FieldCodec.ForBytes(50); - private readonly pbc::RepeatedField stringData_ = new pbc::RepeatedField(); - /// - /// For strings. - /// Each element of string_data is a UTF-8 encoded Unicode - /// string. No trailing null, no leading BOM. The protobuf "string" - /// scalar type is not used to match ML community conventions. - /// When this field is present, the data_type field MUST be STRING - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField StringData { - get { return stringData_; } - } - - /// Field number for the "int64_data" field. - public const int Int64DataFieldNumber = 7; - private static readonly pb::FieldCodec _repeated_int64Data_codec - = pb::FieldCodec.ForInt64(58); - private readonly pbc::RepeatedField int64Data_ = new pbc::RepeatedField(); - /// - /// For int64. - /// When this field is present, the data_type field MUST be INT64 - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Int64Data { - get { return int64Data_; } - } - - /// Field number for the "name" field. - public const int NameFieldNumber = 8; - private string name_ = ""; - /// - /// Optionally, a name for the tensor. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Name { - get { return name_; } - set { - name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "doc_string" field. - public const int DocStringFieldNumber = 12; - private string docString_ = ""; - /// - /// A human-readable documentation for this tensor. Markdown is allowed. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string DocString { - get { return docString_; } - set { - docString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "raw_data" field. - public const int RawDataFieldNumber = 9; - private pb::ByteString rawData_ = pb::ByteString.Empty; - /// - /// Serializations can either use one of the fields above, or use this - /// raw bytes field. The only exception is the string case, where one is - /// required to store the content in the repeated bytes string_data field. - /// - /// When this raw_data field is used to store tensor value, elements MUST - /// be stored in as fixed-width, little-endian order. - /// Floating-point data types MUST be stored in IEEE 754 format. - /// Complex64 elements must be written as two consecutive FLOAT values, real component first. - /// Complex128 elements must be written as two consecutive DOUBLE values, real component first. - /// Boolean type MUST be written one byte per tensor element (00000001 for true, 00000000 for false). - /// - /// Note: the advantage of specific field rather than the raw_data field is - /// that in some cases (e.g. int data), protobuf does a better packing via - /// variable length storage, and may lead to smaller binary footprint. - /// When this field is present, the data_type field MUST NOT be STRING or UNDEFINED - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pb::ByteString RawData { - get { return rawData_; } - set { - rawData_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "external_data" field. - public const int ExternalDataFieldNumber = 13; - private static readonly pb::FieldCodec _repeated_externalData_codec - = pb::FieldCodec.ForMessage(106, global::Onnx.StringStringEntryProto.Parser); - private readonly pbc::RepeatedField externalData_ = new pbc::RepeatedField(); - /// - /// Data can be stored inside the protobuf file using type-specific fields or raw_data. - /// Alternatively, raw bytes data can be stored in an external file, using the external_data field. - /// external_data stores key-value pairs describing data location. Recognized keys are: - /// - "location" (required) - POSIX filesystem path relative to the directory where the ONNX - /// protobuf model was stored - /// - "offset" (optional) - position of byte at which stored data begins. Integer stored as string. - /// Offset values SHOULD be multiples 4096 (page size) to enable mmap support. - /// - "length" (optional) - number of bytes containing data. Integer stored as string. - /// - "checksum" (optional) - SHA1 digest of file specified in under 'location' key. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField ExternalData { - get { return externalData_; } - } - - /// Field number for the "data_location" field. - public const int DataLocationFieldNumber = 14; - private global::Onnx.TensorProto.Types.DataLocation dataLocation_ = 0; - /// - /// If value not set, data is stored in raw_data (if set) otherwise in type-specified field. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TensorProto.Types.DataLocation DataLocation { - get { return dataLocation_; } - set { - dataLocation_ = value; - } - } - - /// Field number for the "double_data" field. - public const int DoubleDataFieldNumber = 10; - private static readonly pb::FieldCodec _repeated_doubleData_codec - = pb::FieldCodec.ForDouble(82); - private readonly pbc::RepeatedField doubleData_ = new pbc::RepeatedField(); - /// - /// For double - /// Complex128 tensors are encoded as a single array of doubles, - /// with the real components appearing in odd numbered positions, - /// and the corresponding imaginary component apparing in the - /// subsequent even numbered position. (e.g., [1.0 + 2.0i, 3.0 + 4.0i] - /// is encoded as [1.0, 2.0 ,3.0 ,4.0] - /// When this field is present, the data_type field MUST be DOUBLE or COMPLEX128 - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField DoubleData { - get { return doubleData_; } - } - - /// Field number for the "uint64_data" field. - public const int Uint64DataFieldNumber = 11; - private static readonly pb::FieldCodec _repeated_uint64Data_codec - = pb::FieldCodec.ForUInt64(90); - private readonly pbc::RepeatedField uint64Data_ = new pbc::RepeatedField(); - /// - /// For uint64 and uint32 values - /// When this field is present, the data_type field MUST be - /// UINT32 or UINT64 - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Uint64Data { - get { return uint64Data_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as TensorProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(TensorProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if(!dims_.Equals(other.dims_)) return false; - if (DataType != other.DataType) return false; - if (!object.Equals(Segment, other.Segment)) return false; - if(!floatData_.Equals(other.floatData_)) return false; - if(!int32Data_.Equals(other.int32Data_)) return false; - if(!stringData_.Equals(other.stringData_)) return false; - if(!int64Data_.Equals(other.int64Data_)) return false; - if (Name != other.Name) return false; - if (DocString != other.DocString) return false; - if (RawData != other.RawData) return false; - if(!externalData_.Equals(other.externalData_)) return false; - if (DataLocation != other.DataLocation) return false; - if(!doubleData_.Equals(other.doubleData_)) return false; - if(!uint64Data_.Equals(other.uint64Data_)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - hash ^= dims_.GetHashCode(); - if (DataType != 0) hash ^= DataType.GetHashCode(); - if (segment_ != null) hash ^= Segment.GetHashCode(); - hash ^= floatData_.GetHashCode(); - hash ^= int32Data_.GetHashCode(); - hash ^= stringData_.GetHashCode(); - hash ^= int64Data_.GetHashCode(); - if (Name.Length != 0) hash ^= Name.GetHashCode(); - if (DocString.Length != 0) hash ^= DocString.GetHashCode(); - if (RawData.Length != 0) hash ^= RawData.GetHashCode(); - hash ^= externalData_.GetHashCode(); - if (DataLocation != 0) hash ^= DataLocation.GetHashCode(); - hash ^= doubleData_.GetHashCode(); - hash ^= uint64Data_.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - dims_.WriteTo(output, _repeated_dims_codec); - if (DataType != 0) { - output.WriteRawTag(16); - output.WriteInt32(DataType); - } - if (segment_ != null) { - output.WriteRawTag(26); - output.WriteMessage(Segment); - } - floatData_.WriteTo(output, _repeated_floatData_codec); - int32Data_.WriteTo(output, _repeated_int32Data_codec); - stringData_.WriteTo(output, _repeated_stringData_codec); - int64Data_.WriteTo(output, _repeated_int64Data_codec); - if (Name.Length != 0) { - output.WriteRawTag(66); - output.WriteString(Name); - } - if (RawData.Length != 0) { - output.WriteRawTag(74); - output.WriteBytes(RawData); - } - doubleData_.WriteTo(output, _repeated_doubleData_codec); - uint64Data_.WriteTo(output, _repeated_uint64Data_codec); - if (DocString.Length != 0) { - output.WriteRawTag(98); - output.WriteString(DocString); - } - externalData_.WriteTo(output, _repeated_externalData_codec); - if (DataLocation != 0) { - output.WriteRawTag(112); - output.WriteEnum((int) DataLocation); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - size += dims_.CalculateSize(_repeated_dims_codec); - if (DataType != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(DataType); - } - if (segment_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Segment); - } - size += floatData_.CalculateSize(_repeated_floatData_codec); - size += int32Data_.CalculateSize(_repeated_int32Data_codec); - size += stringData_.CalculateSize(_repeated_stringData_codec); - size += int64Data_.CalculateSize(_repeated_int64Data_codec); - if (Name.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); - } - if (DocString.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(DocString); - } - if (RawData.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeBytesSize(RawData); - } - size += externalData_.CalculateSize(_repeated_externalData_codec); - if (DataLocation != 0) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) DataLocation); - } - size += doubleData_.CalculateSize(_repeated_doubleData_codec); - size += uint64Data_.CalculateSize(_repeated_uint64Data_codec); - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(TensorProto other) { - if (other == null) { - return; - } - dims_.Add(other.dims_); - if (other.DataType != 0) { - DataType = other.DataType; - } - if (other.segment_ != null) { - if (segment_ == null) { - segment_ = new global::Onnx.TensorProto.Types.Segment(); - } - Segment.MergeFrom(other.Segment); - } - floatData_.Add(other.floatData_); - int32Data_.Add(other.int32Data_); - stringData_.Add(other.stringData_); - int64Data_.Add(other.int64Data_); - if (other.Name.Length != 0) { - Name = other.Name; - } - if (other.DocString.Length != 0) { - DocString = other.DocString; - } - if (other.RawData.Length != 0) { - RawData = other.RawData; - } - externalData_.Add(other.externalData_); - if (other.DataLocation != 0) { - DataLocation = other.DataLocation; - } - doubleData_.Add(other.doubleData_); - uint64Data_.Add(other.uint64Data_); - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: - case 8: { - dims_.AddEntriesFrom(input, _repeated_dims_codec); - break; - } - case 16: { - DataType = input.ReadInt32(); - break; - } - case 26: { - if (segment_ == null) { - segment_ = new global::Onnx.TensorProto.Types.Segment(); - } - input.ReadMessage(segment_); - break; - } - case 34: - case 37: { - floatData_.AddEntriesFrom(input, _repeated_floatData_codec); - break; - } - case 42: - case 40: { - int32Data_.AddEntriesFrom(input, _repeated_int32Data_codec); - break; - } - case 50: { - stringData_.AddEntriesFrom(input, _repeated_stringData_codec); - break; - } - case 58: - case 56: { - int64Data_.AddEntriesFrom(input, _repeated_int64Data_codec); - break; - } - case 66: { - Name = input.ReadString(); - break; - } - case 74: { - RawData = input.ReadBytes(); - break; - } - case 82: - case 81: { - doubleData_.AddEntriesFrom(input, _repeated_doubleData_codec); - break; - } - case 90: - case 88: { - uint64Data_.AddEntriesFrom(input, _repeated_uint64Data_codec); - break; - } - case 98: { - DocString = input.ReadString(); - break; - } - case 106: { - externalData_.AddEntriesFrom(input, _repeated_externalData_codec); - break; - } - case 112: { - dataLocation_ = (global::Onnx.TensorProto.Types.DataLocation) input.ReadEnum(); - break; - } - } - } - } - - #region Nested types - /// Container for nested types declared in the TensorProto message type. - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static partial class Types { - internal enum DataType { - [pbr::OriginalName("UNDEFINED")] Undefined = 0, - /// - /// Basic types. - /// - [pbr::OriginalName("FLOAT")] Float = 1, - /// - /// uint8_t - /// - [pbr::OriginalName("UINT8")] Uint8 = 2, - /// - /// int8_t - /// - [pbr::OriginalName("INT8")] Int8 = 3, - /// - /// uint16_t - /// - [pbr::OriginalName("UINT16")] Uint16 = 4, - /// - /// int16_t - /// - [pbr::OriginalName("INT16")] Int16 = 5, - /// - /// int32_t - /// - [pbr::OriginalName("INT32")] Int32 = 6, - /// - /// int64_t - /// - [pbr::OriginalName("INT64")] Int64 = 7, - /// - /// string - /// - [pbr::OriginalName("STRING")] String = 8, - /// - /// bool - /// - [pbr::OriginalName("BOOL")] Bool = 9, - /// - /// IEEE754 half-precision floating-point format (16 bits wide). - /// This format has 1 sign bit, 5 exponent bits, and 10 mantissa bits. - /// - [pbr::OriginalName("FLOAT16")] Float16 = 10, - [pbr::OriginalName("DOUBLE")] Double = 11, - [pbr::OriginalName("UINT32")] Uint32 = 12, - [pbr::OriginalName("UINT64")] Uint64 = 13, - /// - /// complex with float32 real and imaginary components - /// - [pbr::OriginalName("COMPLEX64")] Complex64 = 14, - /// - /// complex with float64 real and imaginary components - /// - [pbr::OriginalName("COMPLEX128")] Complex128 = 15, - /// - /// Non-IEEE floating-point format based on IEEE754 single-precision - /// floating-point number truncated to 16 bits. - /// This format has 1 sign bit, 8 exponent bits, and 7 mantissa bits. - /// - [pbr::OriginalName("BFLOAT16")] Bfloat16 = 16, - } - - /// - /// Location of the data for this tensor. MUST be one of: - /// - DEFAULT - data stored inside the protobuf message. Data is stored in raw_data (if set) otherwise in type-specified field. - /// - EXTERNAL - data stored in an external location as described by external_data field. - /// - internal enum DataLocation { - [pbr::OriginalName("DEFAULT")] Default = 0, - [pbr::OriginalName("EXTERNAL")] External = 1, - } - - /// - /// For very large tensors, we may want to store them in chunks, in which - /// case the following fields will specify the segment that is stored in - /// the current TensorProto. - /// - internal sealed partial class Segment : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Segment()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.TensorProto.Descriptor.NestedTypes[0]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Segment() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Segment(Segment other) : this() { - begin_ = other.begin_; - end_ = other.end_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Segment Clone() { - return new Segment(this); - } - - /// Field number for the "begin" field. - public const int BeginFieldNumber = 1; - private long begin_; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public long Begin { - get { return begin_; } - set { - begin_ = value; - } - } - - /// Field number for the "end" field. - public const int EndFieldNumber = 2; - private long end_; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public long End { - get { return end_; } - set { - end_ = value; - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as Segment); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(Segment other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Begin != other.Begin) return false; - if (End != other.End) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Begin != 0L) hash ^= Begin.GetHashCode(); - if (End != 0L) hash ^= End.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Begin != 0L) { - output.WriteRawTag(8); - output.WriteInt64(Begin); - } - if (End != 0L) { - output.WriteRawTag(16); - output.WriteInt64(End); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Begin != 0L) { - size += 1 + pb::CodedOutputStream.ComputeInt64Size(Begin); - } - if (End != 0L) { - size += 1 + pb::CodedOutputStream.ComputeInt64Size(End); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(Segment other) { - if (other == null) { - return; - } - if (other.Begin != 0L) { - Begin = other.Begin; - } - if (other.End != 0L) { - End = other.End; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 8: { - Begin = input.ReadInt64(); - break; - } - case 16: { - End = input.ReadInt64(); - break; - } - } - } - } - - } - - } - #endregion - - } - - /// - /// A serialized sparse-tensor value - /// - internal sealed partial class SparseTensorProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SparseTensorProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[8]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public SparseTensorProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public SparseTensorProto(SparseTensorProto other) : this() { - Values = other.values_ != null ? other.Values.Clone() : null; - Indices = other.indices_ != null ? other.Indices.Clone() : null; - dims_ = other.dims_.Clone(); - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public SparseTensorProto Clone() { - return new SparseTensorProto(this); - } - - /// Field number for the "values" field. - public const int ValuesFieldNumber = 1; - private global::Onnx.TensorProto values_; - /// - /// The sequence of non-default values are encoded as a tensor of shape [NNZ]. - /// The default-value is zero for numeric tensors, and empty-string for string tensors. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TensorProto Values { - get { return values_; } - set { - values_ = value; - } - } - - /// Field number for the "indices" field. - public const int IndicesFieldNumber = 2; - private global::Onnx.TensorProto indices_; - /// - /// The indices of the non-default values, which may be stored in one of two formats. - /// (a) Indices can be a tensor of shape [NNZ, rank] with the [i,j]-th value - /// corresponding to the j-th index of the i-th value (in the values tensor). - /// (b) Indices can be a tensor of shape [NNZ], in which case the i-th value - /// must be the linearized-index of the i-th value (in the values tensor). - /// The linearized-index can be converted into an index tuple (k_1,...,k_rank) - /// using the shape provided below. - /// The indices must appear in ascending order without duplication. - /// In the first format, the ordering is lexicographic-ordering: - /// e.g., index-value [1,4] must appear before [2,1] - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TensorProto Indices { - get { return indices_; } - set { - indices_ = value; - } - } - - /// Field number for the "dims" field. - public const int DimsFieldNumber = 3; - private static readonly pb::FieldCodec _repeated_dims_codec - = pb::FieldCodec.ForInt64(26); - private readonly pbc::RepeatedField dims_ = new pbc::RepeatedField(); - /// - /// The shape of the underlying dense-tensor: [dim_1, dim_2, ... dim_rank] - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Dims { - get { return dims_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as SparseTensorProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(SparseTensorProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (!object.Equals(Values, other.Values)) return false; - if (!object.Equals(Indices, other.Indices)) return false; - if(!dims_.Equals(other.dims_)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (values_ != null) hash ^= Values.GetHashCode(); - if (indices_ != null) hash ^= Indices.GetHashCode(); - hash ^= dims_.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (values_ != null) { - output.WriteRawTag(10); - output.WriteMessage(Values); - } - if (indices_ != null) { - output.WriteRawTag(18); - output.WriteMessage(Indices); - } - dims_.WriteTo(output, _repeated_dims_codec); - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (values_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Values); - } - if (indices_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Indices); - } - size += dims_.CalculateSize(_repeated_dims_codec); - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(SparseTensorProto other) { - if (other == null) { - return; - } - if (other.values_ != null) { - if (values_ == null) { - values_ = new global::Onnx.TensorProto(); - } - Values.MergeFrom(other.Values); - } - if (other.indices_ != null) { - if (indices_ == null) { - indices_ = new global::Onnx.TensorProto(); - } - Indices.MergeFrom(other.Indices); - } - dims_.Add(other.dims_); - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - if (values_ == null) { - values_ = new global::Onnx.TensorProto(); - } - input.ReadMessage(values_); - break; - } - case 18: { - if (indices_ == null) { - indices_ = new global::Onnx.TensorProto(); - } - input.ReadMessage(indices_); - break; - } - case 26: - case 24: { - dims_.AddEntriesFrom(input, _repeated_dims_codec); - break; - } - } - } - } - - } - - /// - /// Defines a tensor shape. A dimension can be either an integer value - /// or a symbolic variable. A symbolic variable represents an unknown - /// dimension. - /// - internal sealed partial class TensorShapeProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TensorShapeProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[9]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorShapeProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorShapeProto(TensorShapeProto other) : this() { - dim_ = other.dim_.Clone(); - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TensorShapeProto Clone() { - return new TensorShapeProto(this); - } - - /// Field number for the "dim" field. - public const int DimFieldNumber = 1; - private static readonly pb::FieldCodec _repeated_dim_codec - = pb::FieldCodec.ForMessage(10, global::Onnx.TensorShapeProto.Types.Dimension.Parser); - private readonly pbc::RepeatedField dim_ = new pbc::RepeatedField(); - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public pbc::RepeatedField Dim { - get { return dim_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as TensorShapeProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(TensorShapeProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if(!dim_.Equals(other.dim_)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - hash ^= dim_.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - dim_.WriteTo(output, _repeated_dim_codec); - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - size += dim_.CalculateSize(_repeated_dim_codec); - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(TensorShapeProto other) { - if (other == null) { - return; - } - dim_.Add(other.dim_); - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - dim_.AddEntriesFrom(input, _repeated_dim_codec); - break; - } - } - } - } - - #region Nested types - /// Container for nested types declared in the TensorShapeProto message type. - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static partial class Types { - internal sealed partial class Dimension : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Dimension()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.TensorShapeProto.Descriptor.NestedTypes[0]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Dimension() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Dimension(Dimension other) : this() { - denotation_ = other.denotation_; - switch (other.ValueCase) { - case ValueOneofCase.DimValue: - DimValue = other.DimValue; - break; - case ValueOneofCase.DimParam: - DimParam = other.DimParam; - break; - } - - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Dimension Clone() { - return new Dimension(this); - } - - /// Field number for the "dim_value" field. - public const int DimValueFieldNumber = 1; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public long DimValue { - get { return valueCase_ == ValueOneofCase.DimValue ? (long) value_ : 0L; } - set { - value_ = value; - valueCase_ = ValueOneofCase.DimValue; - } - } - - /// Field number for the "dim_param" field. - public const int DimParamFieldNumber = 2; - /// - /// namespace Shape - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string DimParam { - get { return valueCase_ == ValueOneofCase.DimParam ? (string) value_ : ""; } - set { - value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - valueCase_ = ValueOneofCase.DimParam; - } - } - - /// Field number for the "denotation" field. - public const int DenotationFieldNumber = 3; - private string denotation_ = ""; - /// - /// Standard denotation can optionally be used to denote tensor - /// dimensions with standard semantic descriptions to ensure - /// that operations are applied to the correct axis of a tensor. - /// Refer to https://github.com/onnx/onnx/blob/master/docs/DimensionDenotation.md#denotation-definition - /// for pre-defined dimension denotations. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Denotation { - get { return denotation_; } - set { - denotation_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - private object value_; - /// Enum of possible cases for the "value" oneof. - public enum ValueOneofCase { - None = 0, - DimValue = 1, - DimParam = 2, - } - private ValueOneofCase valueCase_ = ValueOneofCase.None; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public ValueOneofCase ValueCase { - get { return valueCase_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void ClearValue() { - valueCase_ = ValueOneofCase.None; - value_ = null; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as Dimension); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(Dimension other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (DimValue != other.DimValue) return false; - if (DimParam != other.DimParam) return false; - if (Denotation != other.Denotation) return false; - if (ValueCase != other.ValueCase) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (valueCase_ == ValueOneofCase.DimValue) hash ^= DimValue.GetHashCode(); - if (valueCase_ == ValueOneofCase.DimParam) hash ^= DimParam.GetHashCode(); - if (Denotation.Length != 0) hash ^= Denotation.GetHashCode(); - hash ^= (int) valueCase_; - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (valueCase_ == ValueOneofCase.DimValue) { - output.WriteRawTag(8); - output.WriteInt64(DimValue); - } - if (valueCase_ == ValueOneofCase.DimParam) { - output.WriteRawTag(18); - output.WriteString(DimParam); - } - if (Denotation.Length != 0) { - output.WriteRawTag(26); - output.WriteString(Denotation); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (valueCase_ == ValueOneofCase.DimValue) { - size += 1 + pb::CodedOutputStream.ComputeInt64Size(DimValue); - } - if (valueCase_ == ValueOneofCase.DimParam) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(DimParam); - } - if (Denotation.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Denotation); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(Dimension other) { - if (other == null) { - return; - } - if (other.Denotation.Length != 0) { - Denotation = other.Denotation; - } - switch (other.ValueCase) { - case ValueOneofCase.DimValue: - DimValue = other.DimValue; - break; - case ValueOneofCase.DimParam: - DimParam = other.DimParam; - break; - } - - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 8: { - DimValue = input.ReadInt64(); - break; - } - case 18: { - DimParam = input.ReadString(); - break; - } - case 26: { - Denotation = input.ReadString(); - break; - } - } - } - } - - } - - } - #endregion - - } - - /// - /// Types - /// - /// The standard ONNX data types. - /// - internal sealed partial class TypeProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TypeProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[10]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TypeProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TypeProto(TypeProto other) : this() { - denotation_ = other.denotation_; - switch (other.ValueCase) { - case ValueOneofCase.TensorType: - TensorType = other.TensorType.Clone(); - break; - } - - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public TypeProto Clone() { - return new TypeProto(this); - } - - /// Field number for the "tensor_type" field. - public const int TensorTypeFieldNumber = 1; - /// - /// The type of a tensor. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TypeProto.Types.Tensor TensorType { - get { return valueCase_ == ValueOneofCase.TensorType ? (global::Onnx.TypeProto.Types.Tensor) value_ : null; } - set { - value_ = value; - valueCase_ = value == null ? ValueOneofCase.None : ValueOneofCase.TensorType; - } - } - - /// Field number for the "denotation" field. - public const int DenotationFieldNumber = 6; - private string denotation_ = ""; - /// - /// An optional denotation can be used to denote the whole - /// type with a standard semantic description as to what is - /// stored inside. Refer to https://github.com/onnx/onnx/blob/master/docs/TypeDenotation.md#type-denotation-definition - /// for pre-defined type denotations. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Denotation { - get { return denotation_; } - set { - denotation_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - private object value_; - /// Enum of possible cases for the "value" oneof. - public enum ValueOneofCase { - None = 0, - TensorType = 1, - } - private ValueOneofCase valueCase_ = ValueOneofCase.None; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public ValueOneofCase ValueCase { - get { return valueCase_; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void ClearValue() { - valueCase_ = ValueOneofCase.None; - value_ = null; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as TypeProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(TypeProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (!object.Equals(TensorType, other.TensorType)) return false; - if (Denotation != other.Denotation) return false; - if (ValueCase != other.ValueCase) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (valueCase_ == ValueOneofCase.TensorType) hash ^= TensorType.GetHashCode(); - if (Denotation.Length != 0) hash ^= Denotation.GetHashCode(); - hash ^= (int) valueCase_; - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (valueCase_ == ValueOneofCase.TensorType) { - output.WriteRawTag(10); - output.WriteMessage(TensorType); - } - if (Denotation.Length != 0) { - output.WriteRawTag(50); - output.WriteString(Denotation); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (valueCase_ == ValueOneofCase.TensorType) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(TensorType); - } - if (Denotation.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Denotation); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(TypeProto other) { - if (other == null) { - return; - } - if (other.Denotation.Length != 0) { - Denotation = other.Denotation; - } - switch (other.ValueCase) { - case ValueOneofCase.TensorType: - if (TensorType == null) { - TensorType = new global::Onnx.TypeProto.Types.Tensor(); - } - TensorType.MergeFrom(other.TensorType); - break; - } - - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - global::Onnx.TypeProto.Types.Tensor subBuilder = new global::Onnx.TypeProto.Types.Tensor(); - if (valueCase_ == ValueOneofCase.TensorType) { - subBuilder.MergeFrom(TensorType); - } - input.ReadMessage(subBuilder); - TensorType = subBuilder; - break; - } - case 50: { - Denotation = input.ReadString(); - break; - } - } - } - } - - #region Nested types - /// Container for nested types declared in the TypeProto message type. - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static partial class Types { - internal sealed partial class Tensor : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Tensor()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.TypeProto.Descriptor.NestedTypes[0]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Tensor() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Tensor(Tensor other) : this() { - elemType_ = other.elemType_; - Shape = other.shape_ != null ? other.Shape.Clone() : null; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Tensor Clone() { - return new Tensor(this); - } - - /// Field number for the "elem_type" field. - public const int ElemTypeFieldNumber = 1; - private int elemType_; - /// - /// This field MUST NOT have the value of UNDEFINED - /// This field MUST have a valid TensorProto.DataType value - /// This field MUST be present for this version of the IR. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int ElemType { - get { return elemType_; } - set { - elemType_ = value; - } - } - - /// Field number for the "shape" field. - public const int ShapeFieldNumber = 2; - private global::Onnx.TensorShapeProto shape_; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TensorShapeProto Shape { - get { return shape_; } - set { - shape_ = value; - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as Tensor); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(Tensor other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (ElemType != other.ElemType) return false; - if (!object.Equals(Shape, other.Shape)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (ElemType != 0) hash ^= ElemType.GetHashCode(); - if (shape_ != null) hash ^= Shape.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (ElemType != 0) { - output.WriteRawTag(8); - output.WriteInt32(ElemType); - } - if (shape_ != null) { - output.WriteRawTag(18); - output.WriteMessage(Shape); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (ElemType != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(ElemType); - } - if (shape_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Shape); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(Tensor other) { - if (other == null) { - return; - } - if (other.ElemType != 0) { - ElemType = other.ElemType; - } - if (other.shape_ != null) { - if (shape_ == null) { - shape_ = new global::Onnx.TensorShapeProto(); - } - Shape.MergeFrom(other.Shape); - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 8: { - ElemType = input.ReadInt32(); - break; - } - case 18: { - if (shape_ == null) { - shape_ = new global::Onnx.TensorShapeProto(); - } - input.ReadMessage(shape_); - break; - } - } - } - } - - } - - internal sealed partial class SparseTensor : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SparseTensor()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.TypeProto.Descriptor.NestedTypes[1]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public SparseTensor() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public SparseTensor(SparseTensor other) : this() { - elemType_ = other.elemType_; - Shape = other.shape_ != null ? other.Shape.Clone() : null; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public SparseTensor Clone() { - return new SparseTensor(this); - } - - /// Field number for the "elem_type" field. - public const int ElemTypeFieldNumber = 1; - private int elemType_; - /// - /// This field MUST NOT have the value of UNDEFINED - /// This field MUST have a valid TensorProto.DataType value - /// This field MUST be present for this version of the IR. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int ElemType { - get { return elemType_; } - set { - elemType_ = value; - } - } - - /// Field number for the "shape" field. - public const int ShapeFieldNumber = 2; - private global::Onnx.TensorShapeProto shape_; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Onnx.TensorShapeProto Shape { - get { return shape_; } - set { - shape_ = value; - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as SparseTensor); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(SparseTensor other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (ElemType != other.ElemType) return false; - if (!object.Equals(Shape, other.Shape)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (ElemType != 0) hash ^= ElemType.GetHashCode(); - if (shape_ != null) hash ^= Shape.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (ElemType != 0) { - output.WriteRawTag(8); - output.WriteInt32(ElemType); - } - if (shape_ != null) { - output.WriteRawTag(18); - output.WriteMessage(Shape); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (ElemType != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(ElemType); - } - if (shape_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Shape); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(SparseTensor other) { - if (other == null) { - return; - } - if (other.ElemType != 0) { - ElemType = other.ElemType; - } - if (other.shape_ != null) { - if (shape_ == null) { - shape_ = new global::Onnx.TensorShapeProto(); - } - Shape.MergeFrom(other.Shape); - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 8: { - ElemType = input.ReadInt32(); - break; - } - case 18: { - if (shape_ == null) { - shape_ = new global::Onnx.TensorShapeProto(); - } - input.ReadMessage(shape_); - break; - } - } - } - } - - } - - } - #endregion - - } - - /// - /// Operator Sets - /// - /// OperatorSets are uniquely identified by a (domain, opset_version) pair. - /// - internal sealed partial class OperatorSetIdProto : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OperatorSetIdProto()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Onnx.OnnxReflection.Descriptor.MessageTypes[11]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public OperatorSetIdProto() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public OperatorSetIdProto(OperatorSetIdProto other) : this() { - domain_ = other.domain_; - version_ = other.version_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public OperatorSetIdProto Clone() { - return new OperatorSetIdProto(this); - } - - /// Field number for the "domain" field. - public const int DomainFieldNumber = 1; - private string domain_ = ""; - /// - /// The domain of the operator set being identified. - /// The empty string ("") or absence of this field implies the operator - /// set that is defined as part of the ONNX specification. - /// This field MUST be present in this version of the IR when referring to any other operator set. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Domain { - get { return domain_; } - set { - domain_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "version" field. - public const int VersionFieldNumber = 2; - private long version_; - /// - /// The version of the operator set being identified. - /// This field MUST be present in this version of the IR. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public long Version { - get { return version_; } - set { - version_ = value; - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as OperatorSetIdProto); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(OperatorSetIdProto other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Domain != other.Domain) return false; - if (Version != other.Version) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Domain.Length != 0) hash ^= Domain.GetHashCode(); - if (Version != 0L) hash ^= Version.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Domain.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Domain); - } - if (Version != 0L) { - output.WriteRawTag(16); - output.WriteInt64(Version); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Domain.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Domain); - } - if (Version != 0L) { - size += 1 + pb::CodedOutputStream.ComputeInt64Size(Version); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(OperatorSetIdProto other) { - if (other == null) { - return; - } - if (other.Domain.Length != 0) { - Domain = other.Domain; - } - if (other.Version != 0L) { - Version = other.Version; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Domain = input.ReadString(); - break; - } - case 16: { - Version = input.ReadInt64(); - break; - } - } - } - } - - } - - #endregion - -} - -#endregion Designer generated code diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/Generated/Onnx.cs.meta b/Packages/com.unity.barracuda/Runtime/ONNX/Generated/Onnx.cs.meta deleted file mode 100644 index 67d554f..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/Generated/Onnx.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8d42bd74580844e3882d05aa15ba78a0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/Generated/onnx.proto3 b/Packages/com.unity.barracuda/Runtime/ONNX/Generated/onnx.proto3 deleted file mode 100644 index db33804..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/Generated/onnx.proto3 +++ /dev/null @@ -1,548 +0,0 @@ -// -// WARNING: This file is automatically generated! Please edit onnx.in.proto. -// - - -// Copyright (c) ONNX Project Contributors. -// Licensed under the MIT license. - -syntax = "proto3"; - -package onnx; - -// Overview -// -// ONNX is an open specification that is comprised of the following components: -// -// 1) A definition of an extensible computation graph model. -// 2) Definitions of standard data types. -// 3) Definitions of built-in operators. -// -// This document describes the syntax of models and their computation graphs, -// as well as the standard data types. Together, they are referred to as the ONNX -// Intermediate Representation, or 'IR' for short. -// -// The normative semantic specification of the ONNX IR is found in docs/IR.md. -// Definitions of the built-in neural network operators may be found in docs/Operators.md. - -// Notes -// -// Release -// -// We are still in the very early stage of defining ONNX. The current -// version of ONNX is a starting point. While we are actively working -// towards a complete spec, we would like to get the community involved -// by sharing our working version of ONNX. -// -// Protobuf compatibility -// -// To simplify framework compatibility, ONNX is defined using the subset of protobuf -// that is compatible with both protobuf v2 and v3. This means that we do not use any -// protobuf features that are only available in one of the two versions. -// -// Here are the most notable contortions we have to carry out to work around -// these limitations: -// -// - No 'map' (added protobuf 3.0). We instead represent mappings as lists -// of key-value pairs, where order does not matter and duplicates -// are not allowed. - - -// Versioning -// -// ONNX versioning is specified in docs/IR.md and elaborated on in docs/Versioning.md -// -// To be compatible with both proto2 and proto3, we will use a version number -// that is not defined by the default value but an explicit enum number. -enum Version { - // proto3 requires the first enum value to be zero. - // We add this just to appease the compiler. - _START_VERSION = 0; - // The version field is always serialized and we will use it to store the - // version that the graph is generated from. This helps us set up version - // control. - // For the IR, we are using simple numbers starting with with 0x00000001, - // which was the version we published on Oct 10, 2017. - IR_VERSION_2017_10_10 = 0x0000000000000001; - - // IR_VERSION 2 published on Oct 30, 2017 - // - Added type discriminator to AttributeProto to support proto3 users - IR_VERSION_2017_10_30 = 0x0000000000000002; - - // IR VERSION 3 published on Nov 3, 2017 - // - For operator versioning: - // - Added new message OperatorSetIdProto - // - Added opset_import in ModelProto - // - For vendor extensions, added domain in NodeProto - IR_VERSION_2017_11_3 = 0x0000000000000003; - - // IR VERSION 4 published on Jan 22, 2019 - // - Relax constraint that initializers should be a subset of graph inputs - // - Add type BFLOAT16 - IR_VERSION_2019_1_22 = 0x0000000000000004; - - // IR VERSION 5 published on March 18, 2019 - // - Add message TensorAnnotation. - // - Add quantization annotation in GraphProto to map tensor with its scale and zero point quantization parameters. - IR_VERSION_2019_3_18 = 0x0000000000000005; - - // IR VERSION 6 published on - // - Add support for sparse tensor constants stored in model. - // - Add message SparseTensorProto - // - Add sparse initializers - IR_VERSION = 0x0000000000000006; -} - -// Attributes -// -// A named attribute containing either singular float, integer, string, graph, -// and tensor values, or repeated float, integer, string, graph, and tensor values. -// An AttributeProto MUST contain the name field, and *only one* of the -// following content fields, effectively enforcing a C/C++ union equivalent. -message AttributeProto { - - // Note: this enum is structurally identical to the OpSchema::AttrType - // enum defined in schema.h. If you rev one, you likely need to rev the other. - enum AttributeType { - UNDEFINED = 0; - FLOAT = 1; - INT = 2; - STRING = 3; - TENSOR = 4; - GRAPH = 5; - SPARSE_TENSOR = 11; - - FLOATS = 6; - INTS = 7; - STRINGS = 8; - TENSORS = 9; - GRAPHS = 10; - SPARSE_TENSORS = 12; - } - - // The name field MUST be present for this version of the IR. - string name = 1; // namespace Attribute - - // if ref_attr_name is not empty, ref_attr_name is the attribute name in parent function. - // In this case, this AttributeProto does not contain data, and it's a reference of attribute - // in parent scope. - // NOTE: This should ONLY be used in function (sub-graph). It's invalid to be used in main graph. - string ref_attr_name = 21; - - // A human-readable documentation for this attribute. Markdown is allowed. - string doc_string = 13; - - // The type field MUST be present for this version of the IR. - // For 0.0.1 versions of the IR, this field was not defined, and - // implementations needed to use has_field hueristics to determine - // which value field was in use. For IR_VERSION 0.0.2 or later, this - // field MUST be set and match the f|i|s|t|... field in use. This - // change was made to accomodate proto3 implementations. - AttributeType type = 20; // discriminator that indicates which field below is in use - - // Exactly ONE of the following fields must be present for this version of the IR - float f = 2; // float - int64 i = 3; // int - bytes s = 4; // UTF-8 string - TensorProto t = 5; // tensor value - GraphProto g = 6; // graph - SparseTensorProto sparse_tensor = 22; // sparse tensor value - // Do not use field below, it's deprecated. - // optional ValueProto v = 12; // value - subsumes everything but graph - - repeated float floats = 7; // list of floats - repeated int64 ints = 8; // list of ints - repeated bytes strings = 9; // list of UTF-8 strings - repeated TensorProto tensors = 10; // list of tensors - repeated GraphProto graphs = 11; // list of graph - repeated SparseTensorProto sparse_tensors = 23; // list of sparse tensors -} - -// Defines information on value, including the name, the type, and -// the shape of the value. -message ValueInfoProto { - // This field MUST be present in this version of the IR. - string name = 1; // namespace Value - // This field MUST be present in this version of the IR. - TypeProto type = 2; - // A human-readable documentation for this value. Markdown is allowed. - string doc_string = 3; -} - -// Nodes -// -// Computation graphs are made up of a DAG of nodes, which represent what is -// commonly called a "layer" or "pipeline stage" in machine learning frameworks. -// -// For example, it can be a node of type "Conv" that takes in an image, a filter -// tensor and a bias tensor, and produces the convolved output. -message NodeProto { - repeated string input = 1; // namespace Value - repeated string output = 2; // namespace Value - - // An optional identifier for this node in a graph. - // This field MAY be absent in ths version of the IR. - string name = 3; // namespace Node - - // The symbolic identifier of the Operator to execute. - string op_type = 4; // namespace Operator - // The domain of the OperatorSet that specifies the operator named by op_type. - string domain = 7; // namespace Domain - - // Additional named attributes. - repeated AttributeProto attribute = 5; - - // A human-readable documentation for this node. Markdown is allowed. - string doc_string = 6; -} - -// Models -// -// ModelProto is a top-level file/container format for bundling a ML model and -// associating its computation graph with metadata. -// -// The semantics of the model are described by the associated GraphProto. -message ModelProto { - // The version of the IR this model targets. See Version enum above. - // This field MUST be present. - int64 ir_version = 1; - - // The OperatorSets this model relies on. - // All ModelProtos MUST have at least one entry that - // specifies which version of the ONNX OperatorSet is - // being imported. - // - // All nodes in the ModelProto's graph will bind against the operator - // with the same-domain/same-op_type operator with the HIGHEST version - // in the referenced operator sets. - repeated OperatorSetIdProto opset_import = 8; - - // The name of the framework or tool used to generate this model. - // This field SHOULD be present to indicate which implementation/tool/framework - // emitted the model. - string producer_name = 2; - - // The version of the framework or tool used to generate this model. - // This field SHOULD be present to indicate which implementation/tool/framework - // emitted the model. - string producer_version = 3; - - // Domain name of the model. - // We use reverse domain names as name space indicators. For example: - // `com.facebook.fair` or `com.microsoft.cognitiveservices` - // - // Together with `model_version` and GraphProto.name, this forms the unique identity of - // the graph. - string domain = 4; - - // The version of the graph encoded. See Version enum below. - int64 model_version = 5; - - // A human-readable documentation for this model. Markdown is allowed. - string doc_string = 6; - - // The parameterized graph that is evaluated to execute the model. - GraphProto graph = 7; - - // Named metadata values; keys should be distinct. - repeated StringStringEntryProto metadata_props = 14; -}; - -// StringStringEntryProto follows the pattern for cross-proto-version maps. -// See https://developers.google.com/protocol-buffers/docs/proto3#maps -message StringStringEntryProto { - string key = 1; - string value= 2; -}; - -message TensorAnnotation { - string tensor_name = 1; - // pairs to annotate tensor specified by above. - // The keys used in the mapping below must be pre-defined in ONNX spec. - // For example, for 8-bit linear quantization case, 'SCALE_TENSOR', 'ZERO_POINT_TENSOR' will be pre-defined as - // quantization parameter keys. - repeated StringStringEntryProto quant_parameter_tensor_names = 2; -} - - - -// Graphs -// -// A graph defines the computational logic of a model and is comprised of a parameterized -// list of nodes that form a directed acyclic graph based on their inputs and outputs. -// This is the equivalent of the "network" or "graph" in many deep learning -// frameworks. -message GraphProto { - // The nodes in the graph, sorted topologically. - repeated NodeProto node = 1; - - // The name of the graph. - string name = 2; // namespace Graph - - // A list of named tensor values, used to specify constant inputs of the graph. - // Each TensorProto entry must have a distinct name (within the list) that - // MAY also appear in the input list. - repeated TensorProto initializer = 5; - - // Initializers (see above) stored in sparse format. - repeated SparseTensorProto sparse_initializer = 15; - - // A human-readable documentation for this graph. Markdown is allowed. - string doc_string = 10; - - // The inputs and outputs of the graph. - repeated ValueInfoProto input = 11; - repeated ValueInfoProto output = 12; - - // Information for the values in the graph. The ValueInfoProto.name's - // must be distinct. It is optional for a value to appear in value_info list. - repeated ValueInfoProto value_info = 13; - - // This field carries information to indicate the mapping among a tensor and its - // quantization parameter tensors. For example: - // For tensor 'a', it may have {'SCALE_TENSOR', 'a_scale'} and {'ZERO_POINT_TENSOR', 'a_zero_point'} annotated, - // which means, tensor 'a_scale' and tensor 'a_zero_point' are scale and zero point of tensor 'a' in the model. - repeated TensorAnnotation quantization_annotation = 14; - - // DO NOT USE the following fields, they were deprecated from earlier versions. - // repeated string input = 3; - // repeated string output = 4; - // optional int64 ir_version = 6; - // optional int64 producer_version = 7; - // optional string producer_tag = 8; - // optional string domain = 9; -} - -// Tensors -// -// A serialized tensor value. -message TensorProto { - enum DataType { - UNDEFINED = 0; - // Basic types. - FLOAT = 1; // float - UINT8 = 2; // uint8_t - INT8 = 3; // int8_t - UINT16 = 4; // uint16_t - INT16 = 5; // int16_t - INT32 = 6; // int32_t - INT64 = 7; // int64_t - STRING = 8; // string - BOOL = 9; // bool - - // IEEE754 half-precision floating-point format (16 bits wide). - // This format has 1 sign bit, 5 exponent bits, and 10 mantissa bits. - FLOAT16 = 10; - - DOUBLE = 11; - UINT32 = 12; - UINT64 = 13; - COMPLEX64 = 14; // complex with float32 real and imaginary components - COMPLEX128 = 15; // complex with float64 real and imaginary components - - // Non-IEEE floating-point format based on IEEE754 single-precision - // floating-point number truncated to 16 bits. - // This format has 1 sign bit, 8 exponent bits, and 7 mantissa bits. - BFLOAT16 = 16; - - // Future extensions go here. - } - - // The shape of the tensor. - repeated int64 dims = 1; - - // The data type of the tensor. - // This field MUST have a valid TensorProto.DataType value - int32 data_type = 2; - - // For very large tensors, we may want to store them in chunks, in which - // case the following fields will specify the segment that is stored in - // the current TensorProto. - message Segment { - int64 begin = 1; - int64 end = 2; - } - Segment segment = 3; - - // Tensor content must be organized in row-major order. - // - // Depending on the data_type field, exactly one of the fields below with - // name ending in _data is used to store the elements of the tensor. - - // For float and complex64 values - // Complex64 tensors are encoded as a single array of floats, - // with the real components appearing in odd numbered positions, - // and the corresponding imaginary component apparing in the - // subsequent even numbered position. (e.g., [1.0 + 2.0i, 3.0 + 4.0i] - // is encoded as [1.0, 2.0 ,3.0 ,4.0] - // When this field is present, the data_type field MUST be FLOAT or COMPLEX64. - repeated float float_data = 4 [packed = true]; - - // For int32, uint8, int8, uint16, int16, bool, and float16 values - // float16 values must be bit-wise converted to an uint16_t prior - // to writing to the buffer. - // When this field is present, the data_type field MUST be - // INT32, INT16, INT8, UINT16, UINT8, BOOL, or FLOAT16 - repeated int32 int32_data = 5 [packed = true]; - - // For strings. - // Each element of string_data is a UTF-8 encoded Unicode - // string. No trailing null, no leading BOM. The protobuf "string" - // scalar type is not used to match ML community conventions. - // When this field is present, the data_type field MUST be STRING - repeated bytes string_data = 6; - - // For int64. - // When this field is present, the data_type field MUST be INT64 - repeated int64 int64_data = 7 [packed = true]; - - // Optionally, a name for the tensor. - string name = 8; // namespace Value - - // A human-readable documentation for this tensor. Markdown is allowed. - string doc_string = 12; - - // Serializations can either use one of the fields above, or use this - // raw bytes field. The only exception is the string case, where one is - // required to store the content in the repeated bytes string_data field. - // - // When this raw_data field is used to store tensor value, elements MUST - // be stored in as fixed-width, little-endian order. - // Floating-point data types MUST be stored in IEEE 754 format. - // Complex64 elements must be written as two consecutive FLOAT values, real component first. - // Complex128 elements must be written as two consecutive DOUBLE values, real component first. - // Boolean type MUST be written one byte per tensor element (00000001 for true, 00000000 for false). - // - // Note: the advantage of specific field rather than the raw_data field is - // that in some cases (e.g. int data), protobuf does a better packing via - // variable length storage, and may lead to smaller binary footprint. - // When this field is present, the data_type field MUST NOT be STRING or UNDEFINED - bytes raw_data = 9; - - // Data can be stored inside the protobuf file using type-specific fields or raw_data. - // Alternatively, raw bytes data can be stored in an external file, using the external_data field. - // external_data stores key-value pairs describing data location. Recognized keys are: - // - "location" (required) - POSIX filesystem path relative to the directory where the ONNX - // protobuf model was stored - // - "offset" (optional) - position of byte at which stored data begins. Integer stored as string. - // Offset values SHOULD be multiples 4096 (page size) to enable mmap support. - // - "length" (optional) - number of bytes containing data. Integer stored as string. - // - "checksum" (optional) - SHA1 digest of file specified in under 'location' key. - repeated StringStringEntryProto external_data = 13; - - // Location of the data for this tensor. MUST be one of: - // - DEFAULT - data stored inside the protobuf message. Data is stored in raw_data (if set) otherwise in type-specified field. - // - EXTERNAL - data stored in an external location as described by external_data field. - enum DataLocation { - DEFAULT = 0; - EXTERNAL = 1; - } - - // If value not set, data is stored in raw_data (if set) otherwise in type-specified field. - DataLocation data_location = 14; - - // For double - // Complex128 tensors are encoded as a single array of doubles, - // with the real components appearing in odd numbered positions, - // and the corresponding imaginary component apparing in the - // subsequent even numbered position. (e.g., [1.0 + 2.0i, 3.0 + 4.0i] - // is encoded as [1.0, 2.0 ,3.0 ,4.0] - // When this field is present, the data_type field MUST be DOUBLE or COMPLEX128 - repeated double double_data = 10 [packed = true]; - - // For uint64 and uint32 values - // When this field is present, the data_type field MUST be - // UINT32 or UINT64 - repeated uint64 uint64_data = 11 [packed = true]; -} - -// A serialized sparse-tensor value -message SparseTensorProto { - // The sequence of non-default values are encoded as a tensor of shape [NNZ]. - // The default-value is zero for numeric tensors, and empty-string for string tensors. - TensorProto values = 1; - - // The indices of the non-default values, which may be stored in one of two formats. - // (a) Indices can be a tensor of shape [NNZ, rank] with the [i,j]-th value - // corresponding to the j-th index of the i-th value (in the values tensor). - // (b) Indices can be a tensor of shape [NNZ], in which case the i-th value - // must be the linearized-index of the i-th value (in the values tensor). - // The linearized-index can be converted into an index tuple (k_1,...,k_rank) - // using the shape provided below. - // The indices must appear in ascending order without duplication. - // In the first format, the ordering is lexicographic-ordering: - // e.g., index-value [1,4] must appear before [2,1] - TensorProto indices = 2; - - // The shape of the underlying dense-tensor: [dim_1, dim_2, ... dim_rank] - repeated int64 dims = 3; -} - -// Defines a tensor shape. A dimension can be either an integer value -// or a symbolic variable. A symbolic variable represents an unknown -// dimension. -message TensorShapeProto { - message Dimension { - oneof value { - int64 dim_value = 1; - string dim_param = 2; // namespace Shape - }; - // Standard denotation can optionally be used to denote tensor - // dimensions with standard semantic descriptions to ensure - // that operations are applied to the correct axis of a tensor. - // Refer to https://github.com/onnx/onnx/blob/master/docs/DimensionDenotation.md#denotation-definition - // for pre-defined dimension denotations. - string denotation = 3; - }; - repeated Dimension dim = 1; -} - -// Types -// -// The standard ONNX data types. -message TypeProto { - - message Tensor { - // This field MUST NOT have the value of UNDEFINED - // This field MUST have a valid TensorProto.DataType value - // This field MUST be present for this version of the IR. - int32 elem_type = 1; - TensorShapeProto shape = 2; - } - - message SparseTensor { - // This field MUST NOT have the value of UNDEFINED - // This field MUST have a valid TensorProto.DataType value - // This field MUST be present for this version of the IR. - int32 elem_type = 1; - TensorShapeProto shape = 2; - } - - - oneof value { - // The type of a tensor. - Tensor tensor_type = 1; - - } - - // An optional denotation can be used to denote the whole - // type with a standard semantic description as to what is - // stored inside. Refer to https://github.com/onnx/onnx/blob/master/docs/TypeDenotation.md#type-denotation-definition - // for pre-defined type denotations. - string denotation = 6; -} - -// Operator Sets -// -// OperatorSets are uniquely identified by a (domain, opset_version) pair. -message OperatorSetIdProto { - // The domain of the operator set being identified. - // The empty string ("") or absence of this field implies the operator - // set that is defined as part of the ONNX specification. - // This field MUST be present in this version of the IR when referring to any other operator set. - string domain = 1; - - // The version of the operator set being identified. - // This field MUST be present in this version of the IR. - int64 version = 2; -} \ No newline at end of file diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/HalfHelper.cs b/Packages/com.unity.barracuda/Runtime/ONNX/HalfHelper.cs deleted file mode 100644 index 85a8e60..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/HalfHelper.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System.Runtime.InteropServices; -using System; - -// Based on https://sourceforge.net/p/csharp-half/code/HEAD/tree/System.Half/HalfHelper.cs -namespace Unity.Barracuda.ONNX -{ - /// - /// Helper class for Half conversions and some low level operations. - /// This class is internally used in the Half class. - /// - /// - /// References: - /// - Fast Half Float Conversions, Jeroen van der Zijp, link: http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf - /// - internal static class HalfHelper - { - private static uint[] mantissaTable = GenerateMantissaTable(); - private static uint[] exponentTable = GenerateExponentTable(); - private static ushort[] offsetTable = GenerateOffsetTable(); - private static ushort[] baseTable = GenerateBaseTable(); - private static sbyte[] shiftTable = GenerateShiftTable(); - - // Transforms the subnormal representation to a normalized one. - private static uint ConvertMantissa(int i) - { - uint m = (uint)(i << 13); // Zero pad mantissa bits - uint e = 0; // Zero exponent - - // While not normalized - while ((m & 0x00800000) == 0) - { - e -= 0x00800000; // Decrement exponent (1<<23) - m <<= 1; // Shift mantissa - } - m &= unchecked((uint)~0x00800000); // Clear leading 1 bit - e += 0x38800000; // Adjust bias ((127-14)<<23) - return m | e; // Return combined number - } - - private static uint[] GenerateMantissaTable() - { - uint[] mantissaTable = new uint[2048]; - mantissaTable[0] = 0; - for (int i = 1; i < 1024; i++) - { - mantissaTable[i] = ConvertMantissa(i); - } - for (int i = 1024; i < 2048; i++) - { - mantissaTable[i] = (uint)(0x38000000 + ((i - 1024) << 13)); - } - - return mantissaTable; - } - private static uint[] GenerateExponentTable() - { - uint[] exponentTable = new uint[64]; - exponentTable[0] = 0; - for (int i = 1; i < 31; i++) - { - exponentTable[i] = (uint)(i << 23); - } - exponentTable[31] = 0x47800000; - exponentTable[32] = 0x80000000; - for (int i = 33; i < 63; i++) - { - exponentTable[i] = (uint)(0x80000000 + ((i - 32) << 23)); - } - exponentTable[63] = 0xc7800000; - - return exponentTable; - } - private static ushort[] GenerateOffsetTable() - { - ushort[] offsetTable = new ushort[64]; - offsetTable[0] = 0; - for (int i = 1; i < 32; i++) - { - offsetTable[i] = 1024; - } - offsetTable[32] = 0; - for (int i = 33; i < 64; i++) - { - offsetTable[i] = 1024; - } - - return offsetTable; - } - private static ushort[] GenerateBaseTable() - { - ushort[] baseTable = new ushort[512]; - for (int i = 0; i < 256; ++i) - { - sbyte e = (sbyte)(127 - i); - if (e > 24) - { // Very small numbers map to zero - baseTable[i | 0x000] = 0x0000; - baseTable[i | 0x100] = 0x8000; - } - else if (e > 14) - { // Small numbers map to denorms - baseTable[i | 0x000] = (ushort)(0x0400 >> (18 + e)); - baseTable[i | 0x100] = (ushort)((0x0400 >> (18 + e)) | 0x8000); - } - else if (e >= -15) - { // Normal numbers just lose precision - baseTable[i | 0x000] = (ushort)((15 - e) << 10); - baseTable[i | 0x100] = (ushort)(((15 - e) << 10) | 0x8000); - } - else if (e > -128) - { // Large numbers map to Infinity - baseTable[i | 0x000] = 0x7c00; - baseTable[i | 0x100] = 0xfc00; - } - else - { // Infinity and NaN's stay Infinity and NaN's - baseTable[i | 0x000] = 0x7c00; - baseTable[i | 0x100] = 0xfc00; - } - } - - return baseTable; - } - private static sbyte[] GenerateShiftTable() - { - sbyte[] shiftTable = new sbyte[512]; - for (int i = 0; i < 256; ++i) - { - sbyte e = (sbyte)(127 - i); - if (e > 24) - { // Very small numbers map to zero - shiftTable[i | 0x000] = 24; - shiftTable[i | 0x100] = 24; - } - else if (e > 14) - { // Small numbers map to denorms - shiftTable[i | 0x000] = (sbyte)(e - 1); - shiftTable[i | 0x100] = (sbyte)(e - 1); - } - else if (e >= -15) - { // Normal numbers just lose precision - shiftTable[i | 0x000] = 13; - shiftTable[i | 0x100] = 13; - } - else if (e > -128) - { // Large numbers map to Infinity - shiftTable[i | 0x000] = 24; - shiftTable[i | 0x100] = 24; - } - else - { // Infinity and NaN's stay Infinity and NaN's - shiftTable[i | 0x000] = 13; - shiftTable[i | 0x100] = 13; - } - } - - return shiftTable; - } - - public static float HalfToSingle(ushort halfValue) - { - uint result = mantissaTable[offsetTable[halfValue >> 10] + (halfValue & 0x3ff)] + exponentTable[halfValue >> 10]; - return BitConverter.ToSingle(BitConverter.GetBytes(result), 0); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/HalfHelper.cs.meta b/Packages/com.unity.barracuda/Runtime/ONNX/HalfHelper.cs.meta deleted file mode 100644 index 6a44d24..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/HalfHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9f18f6e7d4eea41ceb83f1c74589e5ab -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXExtensions.cs b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXExtensions.cs deleted file mode 100644 index db4cb2a..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Linq; -using Onnx; -using UnityEngine; - -namespace Unity.Barracuda.ONNX { - -static class ONNXExtensions -{ - public static int[] AsInts(this TensorShapeProto shape) - { - return shape.Dim.Select(v => v.DimValue < int.MinValue ? int.MinValue : v.DimValue > int.MaxValue ? int.MaxValue : (int)v.DimValue).ToArray(); - } -} - -} diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXExtensions.cs.meta b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXExtensions.cs.meta deleted file mode 100644 index 2bc23a9..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXExtensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3389b701f5c12a44780263811c992afc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXLayout.cs b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXLayout.cs deleted file mode 100644 index 2a11b40..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXLayout.cs +++ /dev/null @@ -1,468 +0,0 @@ -using Onnx; -using System; -using System.Linq; -using System.Runtime.CompilerServices; -using UnityEngine.Assertions; - -[assembly: InternalsVisibleToAttribute("Barracuda.EditorTests")] -[assembly: InternalsVisibleToAttribute("Unity.Barracuda.Editor")] - -namespace Unity.Barracuda.ONNX -{ - // ONNX specification mandates "channels first" layout of the tensors, while Barracuda uses "channels last" layout just like Tensorflow. - // Moreover Barracuda uses "named dimensions" and expects particular dimension in specific position of the tensor. - // The code below handles conversion between different layouts and mapping to particular "name". - // - // Tensor dimension names: - // N - batch - // C - channels - // H - height - // W - width - // K or M - feature maps aka output channels - // ? - unknown layout - // - // NOTE: "_" stands for dimension that is not present in the specific ONNX tensor. It will make respected dimension of size 1 ("empty") in Barracuda tensor. - internal class ONNXLayout - { - public static int[] AxisPermutationsForMappingONNXLayoutToBarracuda(int onnxRank, string onnxLayout="NCHW") - { - // R dimensions is currently unused and is coming from `sequence` dimension in recurrent networks - // 8D Input tensors: NCTDHW -> SRNTDHWC, SRNCDHW -> SRN_DHWC, SRNC__HW -> SRN__HWC - // 4D Input tensors: NCHW -> __N__HWC, NCW -> __N___WC, NC -> __N____C, C -> _______C - // Convolution kernels: KCHW -> __H__WCK, KCW -> __H__WCK - // Transpose convolutions: CKHW -> __H__WCK, CKW -> __H__WCK - // LSTM weights: RCK -> __C____K - // LSTM weights: RKC -> __C____K - // LSTM biases: RC -> _______C - // GemmTransposeB, MatMul: CK -> __C____K - // Gemm weights KC -> __C____K - - const int _ = -1; - - if (onnxRank == 0) - return new[] {_, _, _, _, _, _, _, _}; - - int maxRank = 6; - if (onnxRank > maxRank) - throw new OnnxLayerImportException($"Only tensors of rank {maxRank} or less are supported for layout {onnxLayout}, but got rank {onnxRank}"); - - else if (onnxLayout == "NC0C1HW") // NC0C1HW -> __N_HWC0C1 - switch (onnxRank) - { - case 5: - return new int[] { _, _, 0, _, 3, 4, 1, 2}; - default: - throw new OnnxLayerImportException($"NC0C1HW layout requires weight tensor of rank 5, but got {onnxRank}"); - } - else if (onnxLayout == "NC0C1C2HW") // NC0C1C2HW -> __NHWC0C1C2 - switch (onnxRank) - { - case 6: - return new int[] { _, _, 0, 4, 5, 1, 2, 3}; - default: - throw new OnnxLayerImportException($"NC0C1C2HW layout requires weight tensor of rank 6, but got {onnxRank}"); - } - else if (onnxLayout == "NCTDHW" || onnxLayout == "NCHW") // NCTDHW -> __NTDHWC, NCHW -> __N__HWC - switch (onnxRank) - { - case 6: - return new int[] { _, _, 0, 2, 3, 4, 5, 1}; - case 5: - return new int[] { _, _, 0, _, 2, 3, 4, 1}; - case 4: - return new int[] { _, _, 0, _, _, 2, 3, 1}; - case 3: - return new int[] { _, _, 0, _, _, _, 2, 1}; - case 2: - return new int[] { _, _, 0, _, _, _, _, 1}; - case 1: - return new int[] { _, _, 0, _, _, _, _, _}; - } - else if (onnxLayout == "CONST") // -> __N__HWC - switch (onnxRank) - { - case 4: - return new int[] { _, _, 0, _, _, 2, 3, 1}; // assume NCHW - case 3: - return new int[] { _, _, _, _, _, 1, 2, 0}; // assume CHW - case 2: - return new int[] { _, _, _, _, _, _, 1, 0}; // assume CW - case 1: - return new int[] { _, _, _, _, _, _, _, 0}; // assume C - } - else if (onnxLayout == "MCDHW" || onnxLayout == "MCHW" || onnxLayout == "KCHW") // -> __H__WCK - switch (onnxRank) - { - case 5: - return new int[] { _, 2, 3, _, _, 4, 1, 0}; - case 4: - return new int[] { _, _, 2, _, _, 3, 1, 0}; - case 3: - return new int[] { _, _, _, _, _, 2, 1, 0}; - default: - throw new OnnxLayerImportException($"MCDHW layout requires kernel weight tensor of rank 3 or higher, but got {onnxRank}"); - } - else if (onnxLayout == "CMHW" || onnxLayout == "CKHW") // -> __H__WCK - switch (onnxRank) - { - case 4: - return new int[] { _, _, 2, _, _, 3, 0, 1}; - case 3: - return new int[] { _, _, _, _, _, 2, 0, 1}; - default: - throw new OnnxLayerImportException($"CMHW layout requires kernel weight tensor of rank 3 or higher, but got {onnxRank}"); - } - else if (onnxLayout == "CHWM" || onnxLayout == "CHWK") // -> __H__WCK - switch (onnxRank) - { - case 4: - return new int[] { _, _, 1, _, _, 2, 0, 3}; - case 3: - return new int[] { _, _, _, _, _, 1, 0, 2}; - default: - throw new OnnxLayerImportException($"CHWM layout requires kernel weight tensor of rank 3 or higher, but got {onnxRank}"); - } - else if (onnxLayout == "CM" || onnxLayout == "CK" || onnxLayout == "RCK") // -> __C____K - switch (onnxRank) - { - case 2: - return new int[] { _, _, 0, _, _, _, _, 1}; - case 3: - return new int[] { _, _, 1, _, _, _, _, 2}; - default: - throw new OnnxLayerImportException($"CM layout requires weight tensor of rank 2 or 3(LSTM), but got {onnxRank}"); - } - else if (onnxLayout == "MC" || onnxLayout == "KC" || onnxLayout == "RKC") // -> __C____K - switch (onnxRank) - { - case 2: - return new int[] { _, _, 1, _, _, _, _, 0}; - case 3: - return new int[] { _, _, 2, _, _, _, _, 1}; - default: - throw new OnnxLayerImportException($"MC layout requires weight tensor of rank 2 or 3(LSTM), but got {onnxRank}"); - } - else if (onnxLayout == "RC") // -> _______C - switch (onnxRank) - { - case 2: - return new int[] {_ ,_ ,_ ,_ ,_ , _, _, 1}; - default: - throw new OnnxLayerImportException($"RC layout requires tensor of rank 2, but got {onnxRank}"); - } - else if (onnxLayout == "C") // -> _______C - switch (onnxRank) - { - case 1: - return new int[] {_ ,_ ,_ ,_ ,_ , _, _, 0}; - default: - throw new OnnxLayerImportException($"C layout requires tensor of rank 1, but got {onnxRank}"); - } - else if (onnxLayout == "ONNX") // Keep ONNX format - switch (onnxRank) - { - case 6: - return new int[] { _, _, 0, 1, 2, 3, 4, 5}; - case 5: - return new int[] { _, _, 0, _, 1, 2, 3, 4}; - case 4: - return new int[] { _, _, 0, _, _, 1, 2, 3}; - case 3: - return new int[] { _, _, 0, _, _, 1, 2, _}; - case 2: - return new int[] { _, _, 0, _, _, 1, _, _}; - case 1: - return new int[] { _, _, 0, _, _, _, _, _}; - } - else if (onnxLayout == "?") - switch (onnxRank) - { - case 8: - return new int[] {0, 1, 2, 3, 4, 5, 6, 7}; - case 7: - return new int[] {0, 1, 2, 3, 4, 5, 6, _}; - case 6: - return new int[] {0, 1, 2, 3, 4, 5, _, _}; - case 5: - return new int[] {0, 1, 2, 3, 4, _, _, _}; - case 4: - return new int[] {0, 1, 2, 3, _, _, _, _}; - case 3: - return new int[] {0, 1, 2, _, _, _, _, _}; - case 2: - return new int[] {0, 1, _, _, _, _, _, _}; - case 1: - return new int[] {0, _, _, _, _, _, _, _}; - } - else - throw new OnnxLayerImportException($"Unknown tensor layout {onnxLayout}"); - - throw new OnnxLayerImportException($"Unsupported combination of tensor layout {onnxLayout} and tensor rank {onnxRank}"); - } - - public static int[] PermuteToBarracuda(int[] shape, string onnxLayout, int defaultValue = 1) - { - var onnxRank = shape.Length; - var permutations = AxisPermutationsForMappingONNXLayoutToBarracuda(onnxRank, onnxLayout); - Assert.IsTrue(shape.Length <= permutations.Length); - Assert.IsTrue(shape.Length == permutations.Count(v => v >= 0)); - var output = new int[permutations.Length]; - for (var i = 0; i < permutations.Length; ++i) - output[i] = permutations[i] >= 0 ? (int)shape[permutations[i]] : defaultValue; - return output; - } - - public static int[] Permute(int[] shape, int[] permutations) - { - Assert.IsTrue(shape.Length <= permutations.Length); - Assert.IsTrue(shape.Count(v => v > 1) <= permutations.Count(v => v >= 0)); - var output = new int[permutations.Length]; - for (var i = 0; i < permutations.Length; ++i) - output[i] = permutations[i] >= 0 ? shape[permutations[i]] : 1; - return output; - } - - public static long[] Permute(long[] shape, int[] permutations) - { - Assert.IsTrue(shape.Length <= permutations.Length); - Assert.IsTrue(shape.Count(v => v > 1) <= permutations.Count(v => v >= 0)); - var output = new long[permutations.Length]; - for (var i = 0; i < permutations.Length; ++i) - output[i] = permutations[i] >= 0 ? shape[permutations[i]] : 1; - return output; - } - - public static int[] InversePermute(int[] permutations) - { - // {0, 2, 3, 1} => {0, 3, 1, 2} - // {2, 3, 1, 0} => {3, 2, 0, 1} - // => {find_index(0), find_index(1), find_index(2), find_index(3)} - var reversePermute = new int[permutations.Length]; - for (var i = 0; i < permutations.Length; ++i) - reversePermute[i] = Array.IndexOf(permutations, i); - return reversePermute; - } - - public static int ConvertAxisToBarracuda(int axis, int onnxRank, string onnxLayout) - { - var permutations = AxisPermutationsForMappingONNXLayoutToBarracuda(onnxRank, onnxLayout); - if (axis < 0) - axis = onnxRank + axis; - return Array.IndexOf(permutations, axis); - } - - private static int Adjust6DAxisForPaddingInChannelFirst(int axis, int padding) - { - //if `axis` is past channels rank, axis index need to be increased by the amount of padding - //to is gonna be added between channels and other features. - return (axis >= 2) ? axis + padding : axis; - } - - public static int[] ExpandONNXPermutationToNCTDHW(int[] onnxPermutation, out int centerPadding) - { - var permutationsNCTDHW = new[] { 0, 1, 2, 3, 4, 5 }; - centerPadding = permutationsNCTDHW.Length - onnxPermutation.Length; - if (onnxPermutation.Length > 0) permutationsNCTDHW[0] = Adjust6DAxisForPaddingInChannelFirst(onnxPermutation[0], centerPadding);//batch - if (onnxPermutation.Length > 1) permutationsNCTDHW[1] = Adjust6DAxisForPaddingInChannelFirst(onnxPermutation[1], centerPadding);//channels - for (int i = 2; i < onnxPermutation.Length; ++i) - permutationsNCTDHW[i + centerPadding] = Adjust6DAxisForPaddingInChannelFirst(onnxPermutation[i], centerPadding); - - return permutationsNCTDHW; - } - - public static int[] ConvertPermutationToLayout(int[] sourcePermutations, string sourceLayout, string targetLayout) - { - //Given a permutation in `sourceLayout` format, this function return the semantically equivalent permutation in `targetLayout`. - //For example if `sourceLayout` is NCHW, `sourcePermutations` is 0132 (swapping H and W), and targetLayout is `NHWC` - //it will return 0213 (swapping of H and W in NHWC layout). - Assert.IsTrue(sourceLayout.Length == sourcePermutations.Length); - Assert.IsTrue(sourceLayout.Length == targetLayout.Length); - - var targetPermutation = new int[sourcePermutations.Length]; - - //For each target dimension - for(int idTarget = 0; idTarget s < 0)) - throw new OnnxLayerImportException($"Expected ONNX shape with all dimensions known, instead got {string.Join(", ",shape)}"); - return new TensorShape(shape); - } - - public static int[] ConvertSymbolicShapeToBarracuda(TensorShapeProto shape, string onnxLayout) - { - // TODO: use dimension denotation from TensorShapeProto to figure, if this particular tensor has specific data layout - // https://github.com/onnx/onnx/blob/master/docs/DimensionDenotation.md - var onnxShape = shape.AsInts(); - return ConvertSymbolicShapeToBarracuda(onnxShape, onnxLayout); - } - - public static int[] ConvertReshapeToBarracuda(int[] onnxShape, int inputRank, out int numDimensionContainingChannelsInformationAfterReshape) - { - //sufflenet and super_resolution_cnn are splitting channels into two dimensions - //care need to be taken as C is channelLast in Barracuda and channelFirst in ONNX: - //An example from shufflenet: - //ONNX => NCHW 1,112,56,56 -> NC1C2HW 1,4,28,56,56 should map to - //Barruda => NHWC 1,56,56,112 -> NHWC1C2 1,56,56,4,28 (and not 1,4,56,56,28) - //Another example from sub_pixel_cnn - //ONNX => NCHW 1,9,224,224 -> NC1C2HW 1,3,3,224,224 should map to - //Barruda => NHWC 1,224,224,9 -> NHWC1C2 1,3,3,224,224 (and not 1,3,224,224,3) - //However we don't support multidimensional features. Thus Barracuda will instead have: - //shufflenet -> NTDHWC with C=45,W=4,H=56,D=56,T=1,N=1 - //sub_pixel_cnn -> NTDHWC with C=224,W=224,H=3,D=3,T=1,N=1 - //further more we need to keep this information for Transpose layer that follow in those architectures. - //indeed convertion from transpose parameters in channelFirst vs channelLast is dependant of - //the number of dimensions channels are represented by. - var outputRank = onnxShape.Length; - if (inputRank == 4 && outputRank == 5) - { - numDimensionContainingChannelsInformationAfterReshape = 2; - return ConvertSymbolicShapeToBarracuda(onnxShape, "NC0C1HW"); - } - if (inputRank == 4 && outputRank == 6) - { - numDimensionContainingChannelsInformationAfterReshape = 3; - return ConvertSymbolicShapeToBarracuda(onnxShape, "NC0C1C2HW"); - } - - numDimensionContainingChannelsInformationAfterReshape = 1; - return ConvertSymbolicShapeToBarracuda(onnxShape, "NCTDHW"); - } - - public static int[] ConvertSymbolicShapeToBarracuda(int[] onnxShape, string onnxLayout) - { - var permutedShape = PermuteToBarracuda(onnxShape, onnxLayout); - Assert.IsTrue(permutedShape.Length == 8); - return Enumerable.Repeat(1, 8 - permutedShape.Length).Concat(permutedShape).ToArray(); - } - - public static int[] SqueezeAxisPermutationForMappingONNXLayoutToBarracuda(int onnxRank, int onnxAxis, string onnxLayout = "NCHW") - { - if (onnxRank > 4) - throw new OnnxLayerImportException($"Only tensors of rank 4 or less are supported, but got rank {onnxRank}"); - - if (onnxLayout != "NCHW") - throw new OnnxLayerImportException($"Only NCHW tensor layout supported {onnxLayout}"); - - var identity = new[] { 0, 1, 2, 3 }; - - if (onnxRank == 4) - { - // axis: 0 1 2 3 - // ONNX: NCHW CHW NHW NCW NCH - // Barracuda: NHWC C_WH N_WH N_WC N_HC - if (onnxAxis == 0) - return new[] { 3, 0, 2, 1 }; - else if (onnxAxis == 1) - return new[] { 0, 3, 2, 1 }; - else if (onnxAxis == 2) - return identity; - else - return new[] { 0, 2, 1, 3 }; - } - else if (onnxRank == 3) - { - // axis: 0 1 2 - // ONNX: NCH CH NH NC - // Barracuda: N_HC C__H N__H N__C - if (onnxAxis == 0) - return new[] { 3, 0, 1, 2 }; - else if (onnxAxis == 1) - return new[] { 0, 1, 3, 2 }; - else - return identity; - } - else if (onnxRank == 2) - { - // axis: 0 1 - // ONNX: NC C N - // Barracuda: N__C C___ N___ - if (onnxAxis == 0) - return new[] { 3, 0, 1, 2 }; - else - return identity; - } - else - { - return identity; - } - } - - public static int[] UnSqueezeAxisPermutationForMappingONNXLayoutToBarracuda(int onnxRank, int onnxAxis, string onnxLayout = "NCHW") - { - if (onnxRank > 4) - throw new OnnxLayerImportException($"Only tensors of rank 4 or less are supported, but got rank {onnxRank}"); - - if (onnxLayout != "NCHW") - throw new OnnxLayerImportException($"Only NCHW tensor layout supported {onnxLayout}"); - - var identity = new[] { 0, 1, 2, 3 }; - - if (onnxRank == 3) - { - // axis: 0 1 2 3 - // ONNX: NCH 1NCH N1CH NC1H NCH1 - // Barracuda: N_HC 1CHN NCH1 N1HC NH1C - if (onnxAxis == 0) - return new[] { 1, 3, 2, 0 }; - else if (onnxAxis == 1) - return new[] { 0, 3, 2, 1 }; - else if (onnxAxis == 2) - return identity; - else - return new[] { 0, 2, 1, 3 }; - } - else if (onnxRank == 2) - { - // axis: 0 1 2 - // ONNX: NC 1NC N1C NC1 - // Barracuda: N__C 1_CN N_C1 N_1C - if (onnxAxis == 0) - return new[] { 1, 2, 3, 0 }; - else if (onnxAxis == 1) - return new[] { 0, 1, 3, 2 }; - else - return identity; - } - else if (onnxRank == 1) - { - // axis: 0 1 - // ONNX: N 1N N1 - // Barracuda: N___ 1__N N__1 - if (onnxAxis == 0) - return new[] { 1, 2, 3, 0 }; - else - return identity; - } - else if (onnxRank == 0) - { - return identity; - } - else - { - throw new OnnxLayerImportException($"Unsqueeze leading to tensor of rank >= 4, Not supported"); - } - } - - } -} diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXLayout.cs.meta b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXLayout.cs.meta deleted file mode 100644 index 4b5c7b7..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXLayout.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7bf10c9d607424a1c9030f5cd50f3d0f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXModelConverter.cs b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXModelConverter.cs deleted file mode 100644 index 7b11478..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXModelConverter.cs +++ /dev/null @@ -1,3461 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using Google.Protobuf; -using Google.Protobuf.Collections; -using Onnx; -using Unity.Barracuda.Compiler.Passes; -using UnityEngine; -using UnityEngine.Assertions; -using UnityEngine.Profiling; - -[assembly: InternalsVisibleTo("Unity.Barracuda.Tests")] - -namespace Unity.Barracuda.ONNX -{ - /// - /// ONNX model converter to Barracuda format. - /// - public class ONNXModelConverter - { - [Flags] - internal enum ImportMode - { - Legacy = 0, // No flags == legacy - Standard = 1 << 0, - - // Additional options - KeepAsNCHW = 1 << 16, - SkipMetadataImport = 1 << 17, - } - - [Flags] - internal enum DataTypeMode - { - Default = 0, - ForceHalf = 1, - ForceFloat = 2 - } - - // Configuration - bool m_TreatErrorsAsWarnings; - bool m_OptimizeModel = true; - bool m_ForceArbitraryBatchSize; - ImportMode m_ImportMode; - - // TF2ONNX known issue: (as of 1.5.4) - // - Conv are framed with Transposes as long as the NCHW flag is not set - // (note this seems that it's going to be fixed https://github.com/onnx/tensorflow-onnx/pull/796) - // - Tensorflow appends :0 to all node names - bool m_FixTf2OnnxExportIssues; - - /// - /// Model imported event - /// - public static event Action ModelImported; - - private readonly Dictionary m_OverrideGlobalInputs = new Dictionary() - { - { "sequence_length:0", new ONNXTensor(new Tensor(1, 1, new[] { 1f }), new [] { 1 }) }, - { "sequence_length", new ONNXTensor(new Tensor(1, 1, new[] { 1f }), new [] { 1 }) } - }; - private readonly HashSet m_ShouldNotBeBaked = new HashSet() - { - // the following nodes handle constant inputs in a custom manner and should not be baked: - "Constant", "Reshape", "Shape", "Slice", "Gather", "Transpose", "Squeeze", "Unsqueeze", "NonZero", "ConstantOfShape", - - // the following nodes are dynamic in nature and can not be baked even when all inputs are constant: - "RandomNormal", "RandomNormalLike", "RandomUniform", "RandomUniformLike" - }; - private readonly HashSet m_AllInputsChannelFirst = new HashSet() - { - // the following onnx nodes have all of there inputs as channel first layout - "Concat", "Add", "Sum", "Sub", "Mul", "Div", "Pow", "Min", "Max", "Mean", "Greater", "Less", "Equal", "Or", "And", "Xor", "Where" - }; - - // Shortcuts - private Dictionary constantTensors { get { return m_ModelTensors.constants; } } - private Dictionary variableTensors { get { return m_ModelTensors.variables; } } - private Dictionary lstmInputs = new Dictionary(); - private Dictionary lstmOutputs = new Dictionary(); - private List layerRequiringUpstreamPatch = new List(); - private void Add(string opType, Action opImportAction) - { - m_NodeImporters.Add(opType, opImportAction); - } - - /// - /// Convert ONNX model and return Barracuda Model object. - /// - /// Location of the input ONNX model. - /// Barracuda Model object. - public Model Convert(string filePath) - { - using (var readStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) - using (var inputStream = new CodedInputStream(readStream)) - return Convert(inputStream); - } - - /// - /// Convert ONNX model and return Barracuda Model object. - /// - /// Memory buffer containing ONNX model. - /// Barracuda Model object. - public Model Convert(byte[] buffer) - { - using (var inputStream = new CodedInputStream(buffer)) - return Convert(inputStream); - } - - // Legacy LSTM importer automagically split input nodes and added output nodes when they didn't exist in the - // network, which is no longer supported - bool IsLegacyMLAgentsLSTMNetwork(ModelProto onnxModel) - { - GraphProto graph = onnxModel.Graph; - // Hallway-lstm.onnx - legacy importer splits recurrent_in to recurrent_in_c and recurrent_in_h - // adds output node recurrent_out_c and recurrent_out_h - if (onnxModel.ProducerName == "tf2onnx" - && graph.Input.Any(i => i.Name.Contains("recurrent_in")) - && graph.Output.Any(o => o.Name.Contains("recurrent_out"))) - return true; - - // Hallway.onnx / Hallway-no-workaround.onnx - legacy importer splits memories to memories_c and memories_h; - // adds output node recurrent_out__c and recurrent_out__h - NodeProto lstmNode = graph.Node.FirstOrDefault(n => n.OpType == "LSTM"); - if (onnxModel.ProducerName == "pytorch" - && graph.Input.Any(i => i.Name.Contains("memories")) - && lstmNode != null - && lstmNode.Output.Count == 3 - && !graph.Node.Any(n => n.Name == lstmNode.Output[1]) // missing output cell and hidden nodes - && !graph.Node.Any(n => n.Name == lstmNode.Output[2])) - return true; - - // Hallway_1_9.onnx - This was supposed to be the candidate for ML-Agents 2.0, but did not have transposes - // in the network, so we will have to import using legacy importer and support during the 1.x ML-Agents - // lifecycle since this already shipped. - lstmNode = graph.Node.FirstOrDefault(n => n.OpType == "LSTM"); - if (onnxModel.ProducerName == "pytorch" - && graph.Input.Any(i => i.Name.Contains("recurrent_in")) - && graph.Output.Any(i => i.Name.Contains("recurrent_out")) - // Input to LSTM node is incorrectly coming directly from a Slice w/o a Transpose - && lstmNode != null - && lstmNode.Input.Any(i => - { - var inputNode = graph.Node.FirstOrDefault(n => n.Output.FirstOrDefault() == i); - return inputNode != null && inputNode.Input.Contains("recurrent_in") && inputNode.OpType == "Slice"; - })) - return true; - - return false; - } - - internal Model Convert(CodedInputStream inputStream) - { - var onnxModel = new ModelProto(); - onnxModel.MergeFrom(inputStream); - - m_FixTf2OnnxExportIssues = onnxModel.ProducerName == "tf2onnx"; - - bool legacyMLAgentsLSTMNetwork = IsLegacyMLAgentsLSTMNetwork(onnxModel); - if (legacyMLAgentsLSTMNetwork) - m_ImportMode = ImportMode.Legacy; - - if (m_ImportMode.HasFlag(ImportMode.Standard)) - UseStandardImporter(); - else - UseLegacyImporter(); - - var model = ConvertOnnxModel(onnxModel); - if (m_ImportMode.HasFlag(ImportMode.Standard)) - { - var preserveLayersPass = new PreserveLayersPass(); - preserveLayersPass.Run(ref model); - - if (m_ImportMode.HasFlag(ImportMode.KeepAsNCHW)) - { - // Since our model is non-runnable due to NHWC-native ops this pass is always required - var runnableNCHWPass = new IntermediateToRunnableNCHWPass(); - runnableNCHWPass.Run(ref model); - } - else - { - var runnableNHWCPass = new IntermediateToRunnableNHWCPass() - { - Optimize = m_OptimizeModel - }; - runnableNHWCPass.Run(ref model); - } - } - - if (legacyMLAgentsLSTMNetwork) - model.Warnings.Add(new Model.ImporterWarning("model", "Using legacy importer since legacy LSTM network was detected; Support will be removed in Barracuda v2.0")); - - ModelImported?.Invoke(onnxModel, model); - - return model; - } - - /// - /// Constructs ONNX model converter - /// - /// Enable/disable various model optimizations while importing model from ONNX format. - /// Treat import errors as warnings. - /// Repair model input batch size. Sometimes needed for ONNX models coming from PyTorch. - public ONNXModelConverter(bool optimizeModel, bool treatErrorsAsWarnings = false, bool forceArbitraryBatchSize = true) - : this(optimizeModel, treatErrorsAsWarnings, forceArbitraryBatchSize, ImportMode.Standard) - { - } - - // Internal constructor to allow setting import mode - internal ONNXModelConverter(bool optimizeModel, bool treatErrorsAsWarnings, bool forceArbitraryBatchSize, ImportMode importMode) - { - m_OptimizeModel = optimizeModel; - m_TreatErrorsAsWarnings = treatErrorsAsWarnings; - m_ForceArbitraryBatchSize = forceArbitraryBatchSize; - m_ImportMode = importMode; - } - - void UseStandardImporter() - { - m_NodeImporters.Clear(); - - var defaultZeroTensor = new ONNXTensor(new Tensor(1, 1, new[] { 0f }), new[] { 1 }); - - Add("Constant", (net, node) => { - node.UnsupportedAttribute("sparse_value"); - Const(node, node.ValueAsTensor); - }); - Add("ConstantOfShape", (net, node) => { - UnityEngine.Debug.Assert(node.InputCount > 0); - - ONNXTensor valueTensor = node.GetOptionalTensor("value", defaultZeroTensor); - var value = valueTensor.ToBarracuda("ONNX").AsFloats()[0]; - - if (node.IsInput0Const) - { - var onnxShape = node.Input0Constant("ONNX").AsInts(); - int onnxRank = onnxShape.Length; - onnxShape = ONNXLayout.ConvertSymbolicShapeToBarracuda(onnxShape, "ONNX"); - var tensor = new Tensor(onnxShape); - tensor.Fill(value); - net.Const(node.Name, tensor, -1, onnxRank); - } - else - { - net.ConstantOfShape(node.Name, node.Input0, value); - } - }); - Add("Reshape", (net, node) => { - int[] onnxShape; - - if (node.InputCount == 1) - { - onnxShape = node.Shape; - if (node.IsInput0Const) - { - // reshape constant source tensor and store it as the new constant - var reshapedTensor = constantTensors[node.Input0].Reshape(onnxShape); - Const(node, reshapedTensor); - } - else - { - net.Reshape(node.Name, node.Input0, onnxShape); - Output(node, rank:onnxShape.Length); - } - } - else - { - if (node.IsInput1Const) - { - onnxShape = node.Input1Constant(onnxLayout: "ONNX", name: "shape").AsInts(); - if (node.IsInput0Const) - { - // reshape constant source tensor and store it as the new constant - var reshapedTensor = constantTensors[node.Input0].Reshape(onnxShape); - Const(node, reshapedTensor); - } - else - { - net.Reshape(node.Name, node.Input0, onnxShape); - Output(node, rank:onnxShape.Length); - } - } - else - { - net.Reshape(node.Name, node.Input0, node.Input1); - } - } - }); - Add("Expand", (net, node) => { - if (node.IsInput1Const) - { - var onnxShape = node.Input1Constant(onnxLayout: "C", name: "shape").AsInts(); - net.Expand(node.Name, node.Input0, onnxShape); - Output(node, rank: onnxShape.Length); - } - else - { - net.Expand(node.Name, node.Input0, node.Input1); - } - }); - Add("Shape", (net, node) => - { - float[] shapeValuesAsFloats; - if (node.IsInput0Const) - { - shapeValuesAsFloats = constantTensors[node.Input0].shape.Select(x => (float)x).ToArray(); - } - else - { - net.Shape(node.Name, node.Input0); - } - }); - Add("Unsqueeze", (net, node) => - { - int[] constAxes = null; - if (node.InputCount >= 2 && node.IsInput1Const) - constAxes = node.Input1Constant(onnxLayout: "ONNX", name: "axes").AsInts(); - else - constAxes = node.Axes; - - if (node.IsInput0Const && constAxes != null) - { - var unsqueezed = constantTensors[node.Input0].Unsqueeze(constAxes); - Const(node, unsqueezed); - } - else if (node.InputCount == 1) - { - net.Unsqueeze(node.Name, node.Input0, node.Axes); - } - else - { - net.Unsqueeze(node.Name, node.Input0, node.Input1); - } - }); - Add("Squeeze", (net, node) => - { - int[] constAxes = null; - if (node.InputCount >= 2 && node.IsInput1Const) - constAxes = node.Input1Constant(onnxLayout: "ONNX", name: "axes").AsInts(); - else - constAxes = node.Axes; - - if (node.IsInput0Const && constAxes != null) - { - - var squeezed = constantTensors[node.Input0].Squeeze(constAxes); - Const(node, squeezed); - } - else if (node.InputCount == 1) - { - net.Squeeze(node.Name, node.Input0, node.Axes); - } - else - { - net.Squeeze(node.Name, node.Input0, node.Input1); - } - }); - Add("Tile", (net, node) => - { - // only 4D Tile support for now - net.Tile(node.Name, node.Input0, node.Input1); - }); - Add("Flatten", (net, node) => { - node.UnsupportedAttribute("axis", 1); // TODO we can support it, insert transposes or if dimensions are ok, == reshape - net.Flatten(node.Name, node.Input0); - Output(node, rank:2); - }); - Add("Concat", (net, node) => { - int axis = node.AxisOptional(0); - - if (node.Inputs.Length == 1) - net.Identity(node.Name, node.Input0); - else - { - net.Concat(node.Name, node.Inputs, axis, true); - } - }); - Add("Split", (net, node) => { - int axis = node.AxisOptional(0); - int[] splits; - try - { - splits = node.GetRequiredIntArray("split"); - } - catch (OnnxLayerImportException) - { - throw new OnnxLayerImportException($"Unsupported default attribute `split` for node {node.Name} of type Split. Value is required."); - } - - Assert.IsTrue(splits.Length == node.Outputs.Length); - int currentSliceStartIndex = 0; - - // Convert `Split` into multiple `StridedSlice` operations. - for (int i = 0; i < splits.Length; ++i) - { - var starts = currentSliceStartIndex; - var ends = starts + splits[i]; - var strides = 1; - - net.StridedSlice(node.Outputs[i], node.Input0, new[] { starts }, new[] { ends }, new[] { strides }, new[] { axis }); - currentSliceStartIndex += splits[i]; - } - }); - Add("Slice", (net, node) => { - int[] starts, ends, axes, steps; - if (node.InputCount > 1) // Slice-10 - { - if (!node.IsInput1Const || !node.IsInput2Const) - { - if(node.InputCount == 5) - net.StridedSlice(node.Name, node.Input0, starts: node.Input1, ends: node.Input2, strides: node.Input4, axes: node.Input3); - else if (node.InputCount == 3) - net.StridedSlice(node.Name, node.Input0, starts: node.Input1, ends: node.Input2, strides: null, axes: null); - } - else - { - var constStarts = node.Input1Constant(onnxLayout: "ONNX", name: "starts"); - var constEnds = node.Input2Constant(onnxLayout: "ONNX", name: "ends"); - var defaultAxes = new Tensor(constStarts.shape, Enumerable.Range(0, constStarts.length).Select(v => (float)v).ToArray()); - var constAxes = node.Input3ConstantOptional(defaultAxes, onnxLayout: "ONNX", name: "axes"); - var constSteps = node.Input4ConstantOptional(constStarts.shape, 1.0f, onnxLayout: "ONNX", name: "steps"); - - starts = constStarts.AsInts(); - ends = constEnds.AsInts(); - axes = constAxes.AsInts(); - steps = constSteps.AsInts(); - net.StridedSlice(node.Name, node.Input0, starts: starts, ends: ends, strides: steps, axes: axes); - } - } - else // Slice-1 - { - starts = node.Starts; - ends = node.Ends; - axes = node.AxesOptional(Enumerable.Range(0, starts.Length).ToArray()); - steps = Enumerable.Repeat(1, starts.Length).ToArray(); - net.StridedSlice(node.Name, node.Input0, starts: starts, ends: ends, strides: steps, axes: axes); - } - }); - Add("Gather", (net, node) => - { - int axis = node.AxisOptional(0); - - if (node.IsInput0Const && node.IsInput1Const) - { - var indices = node.Input1Constant(onnxLayout:"ONNX", name:"indices").AsInts(); - ONNXTensor gatheredTensor = constantTensors[node.Input0].Gather(axis, indices); - Const(node, gatheredTensor); - } - else - { - int input1Rank = node.Input1Rank; - if (node.IsInput1Const) - { - bool isIndicesIntValue = !node.IsInput1Array("indices"); - - // The original rank was cached above since our constant tensor requires a shape of rank 1 and original may have been a scalar - var indices = node.Input1Constant(onnxLayout: "ONNX", name: "indices").AsFloats(); - var shape = isIndicesIntValue ? new int[] { } : new[] { indices.Length }; - var constTensor = new ONNXTensor(new Tensor(new [] { indices.Length, 1, 1, 1, 1, 1, 1, 1 }, indices), shape); - Const(node.Input1, constTensor); - } - - // for import conveintcy, gather with single int values and not int[] implemented with int[] followed by squeeze - if (node.Input1Rank == 0) - { - var gatherLayer = net.Gather(node.Name + "_Squeezed", node.Input0, node.Input1, axis, true); - net.Squeeze(node.Name, gatherLayer, new[] { axis }); - } - else - { - net.Gather(node.Name, node.Input0, node.Input1, axis, true); - } - Output(node.Name, rank: input1Rank + node.Input0Rank - 1); - } - }); - Add("ScatterND", (net, node) => - { - string reduction = node.GetOptionalString("reduction", "none"); - Layer.ScatterNDReductionMode reductionType = Layer.ScatterNDReductionMode.None; - if (reduction == "add") - reductionType = Layer.ScatterNDReductionMode.Add; - else if (reduction == "mul") - reductionType = Layer.ScatterNDReductionMode.Mul; - - net.ScatterND(node.Name, node.Input0, node.Input1, node.Input2, reductionType); - }); - Add("NonMaxSuppression", (net, node) => - { - int centerPointBox = node.GetOptionalInt("center_point_box", 0); - - var boxes = node.GetRequiredInput(0); - var scores = node.GetRequiredInput(1); - object maxOutputBoxesPerClass = 0f; - object iouThreshold = 0f; - object scoreThreshold = 0f; - - if (node.InputCount > 4 && node.IsInput2Const && node.IsInput3Const && node.IsInput4Const - || node.InputCount > 3 && node.IsInput2Const && node.IsInput3Const - || node.InputCount > 2 && node.IsInput2Const) - { - // Use constant version (possibly with defaults) - maxOutputBoxesPerClass = node.Input2ConstantOptional((float)maxOutputBoxesPerClass, "ONNX", nameof(maxOutputBoxesPerClass))[0]; - iouThreshold = node.Input3ConstantOptional((float)iouThreshold, "ONNX", nameof(iouThreshold))[0]; - scoreThreshold = node.Input4ConstantOptional((float)scoreThreshold, "ONNX", nameof(scoreThreshold))[0]; - } - else - { - // Use dynamic tensor version - maxOutputBoxesPerClass = node.Input2Optional; - iouThreshold = node.Input3Optional; - scoreThreshold = node.Input4Optional; - } - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - net.NonMaxSuppression(node.Name, boxes, scores, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, centerPointBox); - Output(node, rank: 2); - }); - Add("OneHot", (net, node) => { - node.UnsupportedAttribute("axis", -1); - - var defaultOffOn = new Tensor(2, 0, new float[] {0, 1}); - - var depth = (int)node.Input1Constant(onnxLayout:"C", name:"depth")[0]; - var offon = node.Input2ConstantOptional(defaultOffOn, onnxLayout:"C", name:"values"); - net.OneHot(node.Name, node.Input0, depth, (int)offon[1], (int)offon[0]); - Output(node, features:depth, rank: node.Input0Rank + 1); - }); - Add("RoiAlign", (net, node) => - { - node.UnsupportedAttribute("mode"); // TODO support - - int output_height = node.GetOptionalInt("output_height", 1); - int output_width = node.GetOptionalInt("output_width", 1); - int sampling_ratio = node.GetOptionalInt("sampling_ratio", 0); - float spatial_scale = node.GetOptionalFloat("spatial_scale", 1.0f); - - net.RoiAlign(node.Name, node.Input0, node.Input1, node.Input2, output_height, output_width, sampling_ratio, spatial_scale); - }); - Add("TopK", (net, node) => { - int axis = node.AxisOptional(-1); - - // TopK-11 introduced these options - bool largest = node.GetOptionalInt("largest", 1) == 1; - // If sorted = false, then the output is undefined - bool sorted = node.GetOptionalInt("sorted", 1) == 1; - - string kName; - if (node.InputCount > 1) // TopK-10 introduced K as an input tensor - { - kName = node.Input1; - } - else - { - // TopK-1 - int k = node.GetRequiredInt("k"); - kName = "Const_TopK"; - var kTensor = new ONNXTensor( - data:new Tensor(new[] { 1, 1, 1, 1 }, new[] { (float)k }, kName), - onnxShape:new [] { 1 }); - - Const(node, kTensor); - } - - Layer indices = net.TopKIndices(node.Outputs[1], node.Input0, kName, axis, largest, sorted); - Output(node.Outputs[1], rank: node.Input0Rank); - net.TopKValues(node.Outputs[0], node.Input0, indices, axis); - Output(node.Outputs[0], rank: node.Input0Rank); - }); - Add("NonZero", (net, node) => { - - if (node.IsInput0Const) - { - var nonZeroTensor = constantTensors[node.Input0].NonZero(); - Const(node, nonZeroTensor); - } - else - { - net.NonZero(node.Name, node.Input0); - Output(node.Outputs[0], rank: 2); - } - }); - Add("LSTM", (net, node) => - { - node.UnsupportedAttribute("activation_alpha"); - node.UnsupportedAttribute("activation_beta"); - node.UnsupportedAttribute("activations", new[] { "Sigmoid", "Tanh", "Tanh" }); // Only Sigmoid is supported for now - node.UnsupportedAttribute("clip"); - node.UnsupportedAttribute("direction", "forward"); // Only forward direction supported - node.UnsupportedAttribute("input_forget"); - node.UnsupportedAttribute("layout"); // alternate layout not supported - - int hiddenSize = node.GetRequiredInt("hidden_size"); - string[] nodeInputs = node.Inputs; - int inputCount = nodeInputs.Length; - - object W = node.Input1; - if (node.IsInput1Const) - W = node.Input1Constant(onnxLayout: "RKC", name: "W"); - - object R = node.Input2; - if (node.IsInput2Const) - R = node.Input2Constant(onnxLayout: "RKC", name: "R"); - - object B = node.Input3Optional; - if (inputCount > 3 && node.IsInput3Const) - { - B = node.Input3Constant(onnxLayout: "RC", name: "B"); - } - else if (string.IsNullOrEmpty((string)B)) - { - var tensor = new Tensor(new TensorShape(1, 8 * hiddenSize)); - tensor.Fill(0); - B = net.Const($"Const_{node.Name}_B", tensor, rank: 2); - } - - int outputCount = node.Outputs.Length; - string[] outputs = { node.Outputs[0], - outputCount > 1 ? node.Outputs[1] : null, - outputCount > 2 ? node.Outputs[2] : null }; - - string initialHidden = inputCount > 5 && !string.IsNullOrEmpty(nodeInputs[5]) ? node.Input5Optional : null; - string initialCell = inputCount > 6 && !string.IsNullOrEmpty(nodeInputs[6]) ? node.Input6Optional : null; - - net.LSTM(node.Name, node.Input0, outputs, W, R, B, hiddenSize, initialHidden, initialCell); - - Output(node.Outputs[0], rank:2); // Actually rank 4, but needs to be 2 for how we handle this layer (re-evaluate?) - - if (outputCount > 1) - Output(node.Outputs[1], rank:2); // Actually rank 3, but needs to be 2 for how we handle this layer (re-evaluate?) - - if (outputCount > 2) - Output(node.Outputs[2], rank:2); // Actually rank 3, but needs to be 2 for how we handle this layer (re-evaluate?) - }); - - // Activation ops - Add("Relu", (net, node) => { net.Relu(node.Name, node.Input0); }); - Add("Softmax", (net, node) => - { - const int defaultAxis = 1; - int axis = node.AxisOptional(defaultAxis); - net.Softmax(node.Name, node.Input0, axis, axisIs8D: true); // keep axis as is - }); - Add("Tanh", (net, node) => { net.Tanh(node.Name, node.Input0); }); - Add("Sqrt", (net, node) => { net.Sqrt(node.Name, node.Input0); }); - Add("Sigmoid", (net, node) => { net.Sigmoid(node.Name, node.Input0); }); - Add("Elu", (net, node) => { net.Elu(node.Name, node.Input0, node.AlphaOptional(1f)); }); - Add("LeakyRelu",(net, node) => { net.LeakyRelu(node.Name, node.Input0, node.AlphaOptional(0.01f)); }); - Add("Selu", (net, node) => { net.Selu(node.Name, node.Input0, node.AlphaOptional(1.67326f), node.GammaOptional(1.0507f)); }); - Add("Swish", (net, node) => { net.Swish(node.Name, node.Input0); }); - Add("PRelu", (net, node) => { net.PRelu(node.Name, node.Input0, node.Input1); }); - Add("LogSoftmax", (net, node) => - { - const int defaultAxis = 1; - int axis = node.AxisOptional(defaultAxis); - net.LogSoftmax(node.Name, node.Input0, axis, axisIs8D: true); // keep axis as is - }); - // TODO: Add("Hardmax", (net, node) => { net.Hardmax(node.Name, node.Input0); node.UnsupportedAttribute("axis", 1); }); - Add("Softplus", (net, node) => { net.Softplus(node.Name, node.Input0); }); - // TODO: Add("Softsign", (net, node) => { net.Softsign(node.Name, node.Input0); }); - Add("HardSigmoid", (net, node) => { net.HardSigmoid(node.Name, node.Input0, node.AlphaOptional(0.2f), node.BetaOptional(0.5f)); }); - Add("Exp", (net, node) => { net.Exp(node.Name, node.Input0); }); - Add("Log", (net, node) => { net.Log(node.Name, node.Input0); }); - Add("Reciprocal", (net, node) => { net.Reciprocal(node.Name, node.Input0); }); - Add("Abs", (net, node) => { net.Abs(node.Name, node.Input0); }); - Add("Neg", (net, node) => { net.Neg(node.Name, node.Input0); }); - Add("Ceil", (net, node) => { net.Ceil(node.Name, node.Input0); }); - Add("Floor", (net, node) => { net.Floor(node.Name, node.Input0); }); - Add("Round", (net, node) => { net.Round(node.Name, node.Input0); }); - Add("Clip", (net, node) => { - float minValue = float.MinValue; - float maxValue = float.MaxValue; - - if (node.InputCount > 1) // Clip-11 - { - minValue = node.Input1ConstantOptional(minValue, onnxLayout:"C", name:"min")[0]; - maxValue = node.Input2ConstantOptional(maxValue, onnxLayout:"C", name:"max")[0]; - } - else - { - minValue = node.MinOptional(minValue); - maxValue = node.MaxOptional(maxValue); - } - net.Clip(node.Name, node.Input0, minValue, maxValue); - }); - Add("Acos", (net, node) => { net.Acos(node.Name, node.Input0); }); - Add("Acosh", (net, node) => { net.Acosh(node.Name, node.Input0); }); - Add("Asin", (net, node) => { net.Asin(node.Name, node.Input0); }); - Add("Asinh", (net, node) => { net.Asinh(node.Name, node.Input0); }); - Add("Atan", (net, node) => { net.Atan(node.Name, node.Input0); }); - Add("Atanh", (net, node) => { net.Atanh(node.Name, node.Input0); }); - Add("Cos", (net, node) => { net.Cos(node.Name, node.Input0); }); - Add("Cosh", (net, node) => { net.Cosh(node.Name, node.Input0); }); - Add("Sin", (net, node) => { net.Sin(node.Name, node.Input0); }); - Add("Sinh", (net, node) => { net.Sinh(node.Name, node.Input0); }); - Add("Tan", (net, node) => { net.Tan(node.Name, node.Input0); }); - Add("Erf", (net, node) => { net.Erf(node.Name, node.Input0); }); - - string[] GetArithmeticOpInputs(ONNXNodeWrapper node, ModelBuilder net) - { - string[] inputs = new string[node.Inputs.Length]; - Array.Copy(node.Inputs, inputs, inputs.Length); - - if (node.IsInput1Const) - { - string onnxLayout = "ONNX"; - string constName = $"Const_{node.Input1}"; - if (!constantTensors.ContainsKey(constName)) - { - Tensor tensorData = node.Input1Constant(onnxLayout, node.Input1); - Layer layer = net.Const(constName, tensorData, rank: node.Input1Rank); - inputs[1] = layer.name; - Const(constName, new ONNXTensor(tensorData, tensorData.shape.ToArray())); - } - } - - return inputs; - } - - // Broadcast ops - Add("Add", (net, node) => { net.Add(node.Name, GetArithmeticOpInputs(node, net)); }); - Add("Sum", (net, node) => { net.Add(node.Name, GetArithmeticOpInputs(node, net)); }); // Sum is implemented via Add - Add("Sub", (net, node) => { net.Sub(node.Name, GetArithmeticOpInputs(node, net)); }); - Add("Mul", (net, node) => { net.Mul(node.Name, GetArithmeticOpInputs(node, net)); }); - Add("Div", (net, node) => { net.Div(node.Name, GetArithmeticOpInputs(node, net)); }); - Add("Pow", (net, node) => { net.Pow(node.Name, node.Inputs); }); - Add("Min", (net, node) => { net.Min(node.Name, node.Inputs); }); - Add("Max", (net, node) => { net.Max(node.Name, node.Inputs); }); - Add("Mean", (net, node) => { net.Mean(node.Name, node.Inputs); }); - - // Logical ops - Add("Greater", (net, node) => { net.Greater(node.Name, node.Input0, node.Input1); }); - Add("Less", (net, node) => { net.Less(node.Name, node.Input0, node.Input1); }); - Add("LessOrEqual", (net, node) => { net.LessEqual(node.Name, node.Input0, node.Input1); }); - Add("Equal", (net, node) => { net.Equal(node.Name, node.Input0, node.Input1); }); - Add("Or", (net, node) => { net.LogicalOr(node.Name, node.Input0, node.Input1); }); - Add("And", (net, node) => { net.LogicalAnd(node.Name, node.Input0, node.Input1); }); - Add("Not", (net, node) => { net.LogicalNot(node.Name, node.Input0); }); - Add("Sign", (net, node) => { net.Sign(node.Name, node.Input0); }); - Add("Xor", (net, node) => { net.LogicalXor(node.Name, node.Input0, node.Input1); }); - Add("Where", (net, node) => { net.Where(node.Name, node.Input0, node.Input1, node.Input2); }); - - // Padding ops - Add("MirrorPad", (net, node) => - { - //Note: MirrorPad is not in onnx spec, it is a custom op from tensorflow implementing there own padding (aka symmetric). - node.UnsupportedAttribute("mode", "symmetric"); - - var value = node.GetOptionalFloat("value", 0.0f); - var autoPad = node.AutoPadMode(); - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - if (node.InputCount == 1) - { - var pads = node.GetRequiredIntArray("pads"); - net.Pad(node.Name, node.Input0, pads, value, Layer.PadMode.Symetric, Layer.AutoPad.NotSet); - } - else - net.Pad(node.Name, node.Input0, node.Input1, node.Input2Optional, Layer.PadMode.Symetric, Layer.AutoPad.NotSet); - - }); - Add("Pad", (net, node) => - { - var value = node.GetOptionalFloat("value", 0.0f); - var modeType = node.PadMode(); - var autoPadType = node.AutoPadMode(); - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - if (node.InputCount == 1) - { - var pads = node.GetRequiredIntArray("pads"); - net.Pad(node.Name, node.Input0, pads, value, modeType, autoPadType); - } - else - net.Pad(node.Name, node.Input0, node.Input1, node.Input2Optional, modeType, autoPadType); - }); - - // Pooling ops - Add("AveragePool", (net, node) => { - node.UnsupportedAttribute("ceil_mode", 0); - node.UnsupportedAttribute("count_include_pad", 0); - net.AvgPool2D(node.Name, node.Input0, node.KernelShape, node.Strides, node.Pads); - }); - Add("MaxPool", (net, node) => { - node.UnsupportedAttribute("ceil_mode", 0); - node.UnsupportedAttribute("dilations", new[] {1, 1}); - node.UnsupportedAttribute("storage_order", 0); - - int[] strides = node.Strides; - int[] pads = node.Pads; - - if (strides.Length == 1) - strides = new[] { 1, strides[0] }; - UnityEngine.Debug.Assert(strides.Length == 2); - - int[] kernelShape = node.KernelShape; - if (kernelShape.Length == 1) - kernelShape = new[] { kernelShape[0], 1 }; - - net.MaxPool2D(node.Name, node.Input0, kernelShape, strides, pads); - }); - Add("GlobalAveragePool", (net, node) => - { - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - net.GlobalAvgPool2D(node.Name, node.Input0); - }); - Add("GlobalMaxPool", (net, node) => - { - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - net.GlobalMaxPool2D(node.Name, node.Input0); - }); - Add("Upsample", (net, node) => - { - UpsampleNCHW(net, node, 1); - }); - Add("Resize", (net, node) => { - var mode = node.ModeOptional("nearest"); - var bilinear = IsModeBilinear(net, node, mode); - if (node.InputCount > 2) // Resize-11/13 - { - node.UnsupportedAttribute("coordinate_transformation_mode", "half_pixel"); - node.UnsupportedAttribute("cubic_coeff_a", -0.75f); - node.UnsupportedAttribute("exclude_outside", 0); - node.UnsupportedAttribute("extrapolation_value", 0f); - node.UnsupportedAttribute("nearest_mode", "round_prefer_floor"); - - // Inputs (3 - 4) - // X : T1 - // roi : T2, It only takes effect when coordinate_transformation_mode is "tf_crop_and_resize" - // scales : tensor(float) - // sizes (optional) : tensor(int64) - // TODO: cropping via roi input - } - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default and size as constants, so this is non-runnable as-is - if (node.InputCount == 4) - { - //Resize-11/13 using target size - net.Resample2D(node.Name, node.Input0, node.Input3, bilinear); - } - else - { - //Resize using scales - UpsampleNCHW(net, node, node.InputCount-1); - } - }); - Add("Transpose", (net, node) => - { - // From https://github.com/onnx/onnx/blob/master/docs/Operators.md#transpose - // By default, reverse the dimensions, otherwise permute the axes according to the values given. - - if (node.IsInput0Const) - { - int inputTensorRank = constantTensors[node.Input0].rank; - var defaultPermutations = new int[inputTensorRank]; - for (int i = 0; i < inputTensorRank; ++i) - defaultPermutations[i] = inputTensorRank - 1 - i; - var permutations = node.GetOptionalIntArray("perm", defaultPermutations); - - var transposedTensor = constantTensors[node.Input0].Permute(permutations); - Const(node, transposedTensor); - } - else - { - var defaultPermutations = new[] { 0, 1, 2, 3, 4, 5 }; - var permutations = node.GetOptionalIntArray("perm", defaultPermutations); - if (permutations.Length > 6) - throw new OnnxLayerImportException($"Transpose support up to 6 dimensions but got a permutations of rank {permutations}."); - - net.Transpose(node.Name, node.Input0, permutations); - } - }); - - Add("DepthToSpace", (net, node) => { - net.DepthToSpace(node.Name, node.Input0, node.BlockSize, node.ModeOptional("DCR")); - }); - - Add("SpaceToDepth", (net, node) => { - net.SpaceToDepth(node.Name, node.Input0, node.BlockSize); - }); - - // Tensor ops - Add("Gemm", (net, node) => { - node.UnsupportedAttribute("alpha", 1.0f); - node.UnsupportedAttribute("beta", 1.0f); - - if (node.IsInput1Const && node.IsInput2Const) - { - var weights = node.Input1Constant(node.TransBOptional() ? "KC" : "CK", name: "B"); - var biases = node.Input2ConstantOptional(Bias(weights.shape), 0.0f, "C", name: "C"); - - var input0 = node.Input0; - - int transposeA = node.GetOptionalInt("transA", 0); - if (transposeA == 1) - { - input0 = input0 + "_transpose"; - net.Transpose(input0, node.Input0, new[] { 1, 0 }); - } - - net.Dense(node.Name, input0, weights, biases); - Output(node, features: weights.channels, rank: 2); // Gemm forces flatten of the input to rank 2 - } - else - { - int transposeA = node.GetOptionalInt("transA", 0); - int transposeB = node.GetOptionalInt("transB", 0); - - var input0 = node.Input0; - var input1 = node.Input1; - - - if (transposeA == 1) - { - input0 = input0 + "_transpose"; - net.Transpose(input0, node.Input0, new[] { 1, 0 }); - } - - if (transposeB == 1) - { - input1 = input1 + "_transpose"; - net.Transpose(input1, node.Input1, new[] { 1, 0 }); - } - - net.MatMul(node.Name, input0, input1); - - if (node.InputCount == 3) - { - net.Add(node.Name + "_bias", new[] { node.Name, node.Input2 }); - } - } - }); - Add("MatMul", (net, node) => { - net.MatMul(node.Name, node.Input0, node.Input1); - Output(node, features: node.Input0Features, rank: Math.Max(node.Input0Rank, node.Input1Rank)); - }); - Add("Conv", (net, node) => { - int[] dilationsDHW = new[] { 1, 1, 1 }; // @TODO trap on wrong values - int[] strides = node.Strides; - int[] pads = node.Pads; - - node.IgnoredAttribute("kernel_shape", "Kernel shape is derived from K tensor weights instead"); - - // Ideally, we'd import kernels/biases in native ONNX layout, but we already have to transpose input since the op doesn't work natively in NCHW - var kernels = node.Input1Constant(onnxLayout: "KCHW", name: "W"); - - var kernelRank = node.Input1Rank; - if (kernelRank == 3) // Conv1D - { - dilationsDHW = node.DilatationsOptional(new[] { 1 }); // @TODO trap on wrong values - UnityEngine.Debug.Assert(dilationsDHW.Length == 1); - dilationsDHW = new[] { 1, 1, dilationsDHW[0] }; - - if (strides.Length == 1) - strides = new[] { strides[0], 1 }; - - if (pads.Length == 2) - pads = new[] { pads[0], 0, pads[1], 0 }; - } - else if (kernelRank == 4) // Conv2D - { - dilationsDHW = node.DilatationsOptional(new[] { 1, 1 }); - UnityEngine.Debug.Assert(dilationsDHW.Length == 2); - dilationsDHW = new[] { 1, dilationsDHW[0], dilationsDHW[1] }; - } - else if (kernelRank == 5) // Conv3D - { - //TODO specific error message for DepthwiseConv3D (or support it). - node.UnsupportedAttribute("group", 1); - - dilationsDHW = node.DilatationsOptional(new[] { 1, 1, 1 }); - UnityEngine.Debug.Assert(dilationsDHW.Length == 3); - pads = node.Pads3D; - strides = node.Strides3D; - } - else - { - Warn(net, node, $"Unsuported Conv kernel rank. Conv1D/2D/3 assumes rank 3/4/5 respectively, but got {kernelRank}."); - } - - UnityEngine.Debug.Assert(dilationsDHW.Length == 3); - if (dilationsDHW[0] != 1 || dilationsDHW[1] != 1 || dilationsDHW[2] != 1) - kernels = DilateKernel(kernels, dilationsDHW); // @TODO inefficient method. Support dilatation in kernel code properly - - var biases = node.Input2ConstantOptional(Bias(kernels.shape), 0.0f, onnxLayout: "C", name: "B"); - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - // TODO assert correctly: with group == 2 or group != in_channel we don't support it - if (node.GroupOptional() > 1) - net.DepthwiseConv2D(node.Name, node.Input0, strides, pads, kernels, biases); - else - { - if (kernelRank < 5) - net.Conv2D(node.Name, node.Input0, strides, pads, kernels, biases); - else - net.Conv3D(node.Name, node.Input0, strides, pads, kernels, biases); - } - - Output(node, features: kernels.channels); - }); - Add("ConvTranspose", (net, node) => { - node.UnsupportedAttribute("group", 1); - node.UnsupportedAttribute("output_shape", new int[0]); - node.IgnoredAttribute("kernel_shape", "Kernel shape is derived from K tensor weights instead"); - - int[] strides = node.Strides; - int[] pads = node.Pads; - int[] outputPadding = node.OutputPadding; - var kernelRank = node.Input1Rank; - if (kernelRank == 3) // ConvTranspose1D - { - node.UnsupportedAttribute("dilations", new[] {1}); - if (strides.Length == 1) - strides = new[] { strides[0], 1 }; - if (pads.Length == 2) - pads = new[] { pads[0], 0, pads[1], 0 }; - if (outputPadding.Length == 1) - outputPadding = new[] { outputPadding[0], 0 }; - } - else if (kernelRank == 4)// ConvTranspose2D - { - node.UnsupportedAttribute("dilations", new[] {1, 1}); - } - else - { - Warn(net, node, $"Unsuported ConvTranspose kernel rank. ConvTranspose1D/2D assumes rank 3/4 respectively, but got {kernelRank}."); - } - - // Ideally, we'd import kernels/biases in native ONNX layout, but we already have to transpose input since the op doesn't work natively in NCHW - var kernels = node.Input1Constant(onnxLayout:"CKHW", name:"W"); - var biases = node.Input2ConstantOptional(Bias(kernels.shape), 0.0f, onnxLayout:"C", name:"B"); - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - net.Conv2DTrans(node.Name, node.Input0, strides, pads, outputPadding, kernels, biases); - Output(node, features:kernels.channels); - }); - Add("BatchNormalization", (net, node) => { - // Ideally, we'd import variances/scales/biases/means in native ONNX layout, but we already have to transpose input since the op doesn't work natively in NCHW - var variance = node.Input4Constant(onnxLayout:"C", name:"var"); - var scale = node.Input1ConstantOptional(variance.shape, 1.0f, onnxLayout:"C", name:"scale"); - var bias = node.Input2ConstantOptional(variance.shape, 0.0f, onnxLayout:"C", name:"B"); - var mean = node.Input3ConstantOptional(variance.shape, 0.0f, onnxLayout:"C", name:"mean"); - if (variance.length != scale.length || scale.length != bias.length || bias.length != mean.length) - Warn(net, node, $"Number of elements in all parameters for BatchNorm must be the same." + - $"Parameter shapes are: {scale.shape}, {bias.shape}, {mean.shape}, {variance.shape}"); - // TODO: Jeremy has one non valid onnx model with #channels > than input_channels, see if we want to support his model? - var fusedData = FuseBatchNormWeights(scale, bias, mean, variance, node.EpsilonOptional(), variance.shape.channels); - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - net.ScaleBias(node.Name, node.Input0, fusedData.Item1, fusedData.Item2); - }); - Add("ImageScaler", (net, node) => - { - var attrBias = node.Bias; - var attrScale = node.ScaleOptional(); - int maxElements = attrBias.Length; - - Tensor scale = new Tensor(1, maxElements); - Tensor bias = new Tensor(1, maxElements); - for (int i = 0; i < maxElements; ++i) - { - scale[i] = attrScale; - bias[i] = attrBias[i]; - } - net.ScaleBias(node.Name, node.Input0, scale, bias); - }); - Add("InstanceNormalization", (net, node) => { - // Ideally, we'd import scales/biases in native ONNX layout, but we already have to transpose input since the op doesn't work natively in NCHW - var scale = node.Input1Constant(onnxLayout:"C", name:"scale"); - var bias = node.Input2ConstantOptional(scale.shape, 0.0f, onnxLayout:"C", name:"B"); - if (scale.length != bias.length) - Warn(net, node, $"Number of elements in all parameters for InstanceNorm must be the same." + - $"Parameter shapes are: {scale.shape}, {bias.shape}"); - if (scale.channels != node.Input0Features && node.Input0Features > 0) - { - Warn(net, node, $"Number of elements in InstanceNorm must match features from the previous layer. Was expecting {node.Input0Features}, but got {scale.channels}."); - var scaleArray = scale.ToReadOnlyArray(); - Array.Resize(ref scaleArray, node.Input0Features); - var biasArray = bias.ToReadOnlyArray(); - Array.Resize(ref biasArray, node.Input0Features); - scale = new Tensor(1, node.Input0Features, scaleArray); - bias = new Tensor(1, node.Input0Features, biasArray); - } - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - net.Normalization(node.Name, node.Input0, scale, bias, node.EpsilonOptional()); - }); - Add("LRN", (net, node) => { - float bias = node.GetOptionalFloat("bias", 1.0f); - int size = node.GetRequiredInt("size"); - net.LRN(node.Name, node.Input0, node.AlphaOptional(0.0001f), node.BetaOptional(0.75f), bias, size); - }); - // random ops - Add("RandomNormal", (net, node) => { - var shape = ONNXLayout.ConvertShapeToBarracuda(onnxShape:node.Shape, onnxLayout:"ONNX"); - net.RandomNormal(node.Name, shape, node.MeanOptional(), node.ScaleOptional(), node.Seed); - Output(node, rank:node.Shape.Length); - }); - Add("RandomNormalLike", (net, node) => { - net.RandomNormal(node.Name, node.Input0, node.MeanOptional(), node.ScaleOptional(), node.Seed); - }); - Add("RandomUniform", (net, node) => { - float high = node.GetOptionalFloat("high", 1.0f); - float low = node.GetOptionalFloat("low", 0.0f); - var shape = ONNXLayout.ConvertShapeToBarracuda(onnxShape:node.Shape, onnxLayout:"ONNX"); - net.RandomUniform(node.Name, shape, low, high, node.Seed); - Output(node, rank:node.Shape.Length); - }); - Add("RandomUniformLike", (net, node) => { - float high = node.GetOptionalFloat("high", 1.0f); - float low = node.GetOptionalFloat("low", 0.0f); - net.RandomUniform(node.Name, node.Input0, low, high, node.Seed); - }); - Add("Multinomial", (net, node) => { - int samples = node.GetOptionalInt("sample_size", 1); - net.Multinomial(node.Name, node.Input0, samples, node.Seed); - }); - Add("Range", (net, node) => - { - if (node.IsInput0Const && node.IsInput1Const && node.IsInput2Const) - { - var startTensor = node.GetRequiredInputAsConstant(node.Input0, "N", "start"); - var limitTensor = node.GetRequiredInputAsConstant(node.Input1, "N", "start"); - var deltaTensor = node.GetRequiredInputAsConstant(node.Input2, "N", "start"); - - Assert.AreEqual(startTensor.length, 1); - Assert.AreEqual(limitTensor.length, 1); - Assert.AreEqual(deltaTensor.length, 1); - - float start = startTensor[0]; - float limit = limitTensor[0]; - float delta = deltaTensor[0]; - - var range = ONNXTensor.Range(start, limit, delta); - Const(node, range); - } - else - { - net.Range(node.Name, node.Input0, node.Input1, node.Input2); - } - }); - // Reduce ops - Add("ReduceMax", (net, node) => { - ReduceNCHW(net, node, Layer.Type.ReduceMax); - }); - Add("ReduceMean", (net, node) => { - ReduceNCHW(net, node, Layer.Type.ReduceMean); - }); - Add("ReduceMin", (net, node) => { - ReduceNCHW(net, node, Layer.Type.ReduceMin); - }); - Add("ReduceProd", (net, node) => { - ReduceNCHW(net, node, Layer.Type.ReduceProd); - }); - Add("ReduceSum", (net, node) => { - ReduceNCHW(net, node, Layer.Type.ReduceSum); - }); - Add("ArgMax", (net, node) => { - node.UnsupportedAttribute("select_last_index"); - ReduceNCHW(net, node, Layer.Type.ArgMax); - }); - Add("ArgMin", (net, node) => { - node.UnsupportedAttribute("select_last_index"); - ReduceNCHW(net, node, Layer.Type.ArgMin); - }); - - - // Ignore, noop during inference - Add("Identity", (net, node) => { net.Identity(node.Name, node.Input0); }); - Add("Cast", (net, node) => { net.Identity(node.Name, node.Input0); }); - Add("Dropout", (net, node) => { net.Identity(node.Name, node.Input0); }); - } - - void UseLegacyImporter() - { - m_NodeImporters.Clear(); - - var defaultZeroTensor = new ONNXTensor(new Tensor(1, 1, new[] { 0f }), new[] { 1 }); - var defaultOneTensor = new ONNXTensor(new Tensor(1, 1, new[] { 1f }), new[] { 1 }); - var toNCHW = new [] { 0, 3, 1, 2 }; - var toNHWC = new [] { 0, 2, 3, 1 }; - var fromN1WCtoNCH = new [] { 0, 3, 2, 1 }; - var fromNCHtoN1WC = new [] { 0, 3, 2, 1 }; - - // TODO: setup m_NodeImporters via initializer list - // TODO: simplify code to avoid passing node.Name over and over again - Add("Constant", (net, node) => { - node.UnsupportedAttribute("sparse_value"); - Const(node, node.ValueAsTensor); - }); - Add("ConstantOfShape", (net, node) => { - Assert.IsTrue(node.InputCount > 0); - var valueTensor = node.GetOptionalTensor("value", defaultZeroTensor); - var onnxShape = node.Input0ConstantONNXShape(name: "input"); - var dataShape = ONNXLayout.ConvertShapeToBarracuda(onnxShape, onnxLayout:"?"); - var tensorData = new Tensor(dataShape); - tensorData.Fill(valueTensor[0]); - var constantOfShape = new ONNXTensor(tensorData, onnxShape); - Const(node, constantOfShape); - }); - Add("Reshape", (net, node) => { - int[] onnxShape; - if (node.InputCount > 1) // Reshape-5 - { - if (node.IsInput1Const) - { - onnxShape = node.Input1Constant(onnxLayout: "C", name: "shape").AsInts(); - } - else - { - int input0Rank = node.Input0Rank; - if (input0Rank <= 4 && variableTensors.TryGetValue(node.Input0, out VariableTensor previousOutput) - && previousOutput.layout != VariableTensor.Layout.ChannelsLast) - { - int outputRank = 4; - Model.Input input1 = net.model.inputs.Where(i => i.name == node.Input1).FirstOrDefault(); - if (!input1.Equals(default)) - { - if (input1.rank == 1) // shape is in the tensor - outputRank = input1.shape[TensorShape.DataBatch]; - } - - // For handling all reshapes correctly with dynamic shapes (e.g. rank 3) perform in NCHW layout - Layer nchwTranspose = net.Transpose($"Transpose_{node.Input0}_For_{node.Name}", node.Input0, input0Rank == 3 ? fromN1WCtoNCH : toNCHW); - Layer reshape = net.Reshape($"{node.Name}_NCHW", nchwTranspose, node.Input1); - net.Transpose(node.Name, reshape, outputRank == 3 ? fromNCHtoN1WC : toNHWC); - Output(node, rank:4); - } - else - { - net.Reshape(node.Name, node.Input0, node.Input1); - } - return; - } - } - else // Reshape-1 - onnxShape = node.Shape; - - if (node.IsInput0Const) - { - // reshape constant source tensor and store it as the new constant - var reshapedTensor = constantTensors[node.Input0].Reshape(onnxShape); - Const(node, reshapedTensor); - } - else - { - Layer reshapeLayer = null; - - int numDimensionContainingChannelsInformationAfterReshape = 1; - var symbolicShape = ONNXLayout.ConvertReshapeToBarracuda(onnxShape, node.Input0Rank, out numDimensionContainingChannelsInformationAfterReshape); - int variableDimension = Array.IndexOf(symbolicShape, -1); - bool containsNoVariableDimensions = variableDimension == -1; - - // special case handling with inferable reshapes - // TODO: remove this once we have full shape inference - // onnx: NCW -> N1CW - // N: is unknown and H,W are inferable - if (node.Input0Rank == 3 && onnxShape.Length == 4 && - onnxShape[0] == 0 && onnxShape[1] == 1 && onnxShape[2] == 0 && onnxShape[3] == 0) - { - // onnx: NCW -> N1CW - // barracuda: N_WC -> NCW1 - net.Transpose(node.Name, node.Input0, new[] { 0, 3, 2, 1 }); - Output(node, features: 1, rank: onnxShape.Length); - return; - } - - - if (containsNoVariableDimensions) - { - if (m_ForceArbitraryBatchSize) - symbolicShape[0] = -1; // force arbitrary batch size - - // Creating any of the spatial dimensions requires to run reshape in NCHW and transpose to NHWC after it to match NCHW behavior. - if (onnxShape.Length > 2 && node.Input0Rank <= 2) - { - int[] onnxPaddedShape = onnxShape; - if (onnxShape.Length == 3) // correct NCH to NCW - onnxPaddedShape = new[] {onnxShape[0], onnxShape[1], 1, onnxShape[2]}; - - reshapeLayer = net.Reshape($"{node.Name}_NCHW", node.Input0, onnxPaddedShape); - reshapeLayer = net.Transpose(node.Name, reshapeLayer, toNHWC); - } - } - else if (onnxShape.Length <= 4 && node.Input0Rank <= 4 - && (onnxShape.Length == 2 || variableDimension != TensorShape.C) - && variableTensors.TryGetValue(node.Input0, out VariableTensor previousOutput) - && previousOutput.layout != VariableTensor.Layout.ChannelsLast) - { - // Collapsing any of the spatial dimensions requires a reshape in NCHW layout - int[] onnxPaddedShape; - if (onnxShape.Length == 3) // correct NCH to NCW - onnxPaddedShape = new[] { onnxShape[0], onnxShape[1], 1, onnxShape[2] }; - else - onnxPaddedShape = onnxShape.Concat(Enumerable.Repeat(1, 4 - onnxShape.Length)).ToArray(); - - Layer nchwTranspose = net.Transpose($"Transpose_{node.Input0}_For_{node.Name}", node.Input0, toNCHW); - reshapeLayer = net.Reshape($"{node.Name}_NCHW", nchwTranspose, onnxPaddedShape); - reshapeLayer = net.Transpose(node.Name, reshapeLayer, toNHWC); - } - - if (reshapeLayer == null) - reshapeLayer = net.Reshape(node.Name, node.Input0, symbolicShape); - - reshapeLayer.axis = numDimensionContainingChannelsInformationAfterReshape; - var features = onnxShape.Length > 1 ? onnxShape[1] : -1; - Output(node, features: features, rank:onnxShape.Length); - } - }); - Add("Expand", (net, node) => { - var onnxShape = node.Input1Constant(onnxLayout: "C", name: "shape").AsInts(); - var symbolicShape = ONNXLayout.ConvertSymbolicShapeToBarracuda(onnxShape, "NCHW"); - bool containsNoVariableDimensions = Array.IndexOf(symbolicShape, -1) == -1; - if (containsNoVariableDimensions && m_ForceArbitraryBatchSize) - symbolicShape[0] = -1; // force arbitrary batch size - - net.Expand(node.Name, node.Input0, symbolicShape); - Output(node, rank:symbolicShape.Length); - }); - Add("Shape", (net, node) => - { - float[] shapeValuesAsFloats; - if (node.IsInput0Const) - { - shapeValuesAsFloats = constantTensors[node.Input0].shape.Select(x => (float)x).ToArray(); - } - else - { - switch (node.Input0Rank) - { - default: - case 4: // NCHW - case 3: // NCW - case 2: // NC - // @TODO: dynamic implementation that would return real shape during execution of the model - // - // meanwhile at import time we assume 0 (taken from input tensor) for the spatial dimensions - // NOTE: this assumption works for common Upsample opset=9 case: - // Upsample.scales = (shape.hw * constant) / shape.hw - // however this would not work for potential (opset=10) cases like: - // Resize.size = shape.hw + constant - - // stored in ONNX layout - var shapeWithChannelsFirst = new[] { 0f, node.Input0Features }; // NC - var fillSpatialDimensionsWithUnknown = 0f; - var numberOfSpatialDimensions = node.Input0Rank - 2; - var shapeFollowedWithSpatialDimensions = Enumerable.Repeat(fillSpatialDimensionsWithUnknown, numberOfSpatialDimensions); - shapeValuesAsFloats = shapeWithChannelsFirst.Concat(shapeFollowedWithSpatialDimensions).ToArray(); - - break; - case 1: // C - shapeValuesAsFloats = new[] {(float)node.Input0Features}; - break; - case 0: // scalar - shapeValuesAsFloats = new[] {0f}; - break; - } - } - - var shapeLength = shapeValuesAsFloats.Length; - Assert.IsTrue(shapeLength == node.Input0Rank); - - var shape = new int[8]; - shape[0] = shapeLength; - var shapeTensor = new ONNXTensor( - // NOTE: stored in single rank ONNX layout - // with data in the 1st dimension - // thus `shapeLength` specifies the length of the 1st dimension - data:new Tensor(shape, shapeValuesAsFloats), - onnxShape:new [] { shapeLength }); - - Const(node, shapeTensor); - Output(node, features:shapeLength, productOfShape:node.Input0); - }); - Add("Unsqueeze", (net, node) => { - if (node.IsInput0Const) - { - var unsqueezed = constantTensors[node.Input0].Unsqueeze(node.Axes); - Const(node, unsqueezed); - } - else - { - // NOTE: axis=0 or 1 will require Transpose between channels and other spatial dimensions when converted to Barracuda layout. - // As we have different layouts between ONNX and Barracuda, Unsqueeze might require actual Transpose not just Reshape! - - var features = node.Input0Features; - var inputRank = node.Input0Rank; - var outputRank = inputRank + 1; - Output(node.Name, features: features, rank: outputRank); - - // ONNX pseudocode here: - // a = Tensor [2, 10] # NC -> barracuda N11C - // b = Unsqueeze(a, axis=0) - // # b is now Tensor [1, 2, 10] # NCHW -> barrada NHWC - // Because ONNX is NCHW, but generally hell knows what goes where and Barracuda is strict NHWC. We end up with: - // `a` would be [2, 1, 1, 10], but `b` would have to be [1, 10, 1, 2]. Note the actual data swap in channels! - int axis = node.Axes[0]; - if (axis < 0) - axis = node.Input0Rank+1 - axis; - - var transpose = ONNXLayout.UnSqueezeAxisPermutationForMappingONNXLayoutToBarracuda(inputRank, axis, "NCHW"); - net.Transpose(node.Name, node.Input0, transpose); - } - }); - Add("Squeeze", (net, node) => { - if (node.IsInput0Const) - { - var squeezed = constantTensors[node.Input0].Squeeze(node.Axes); - Const(node, squeezed); - } - else - { - var features = node.Input0Features; - var inputRank = node.Input0Rank; - var outputRank = inputRank - 1; - Output(node.Name, features: features, rank: outputRank); - - // See Unsqueeze above for explanation - int axis = node.Axes[0]; - if (axis < 0) - axis = node.Input0Rank + 1 - axis; - - var transpose = ONNXLayout.SqueezeAxisPermutationForMappingONNXLayoutToBarracuda(inputRank, axis, "NCHW"); - net.Transpose(node.Name, node.Input0, transpose); - } - }); - Add("Flatten", (net, node) => { - node.UnsupportedAttribute("axis", 1); - if (variableTensors.TryGetValue(node.Input0, out var inputTensor) && inputTensor.layout == VariableTensor.Layout.ChannelsLast) - net.Flatten(node.Name, node.Input0); - else - { - Layer nchwTranspose = net.Transpose($"Transpose_{node.Input0}_For_{node.Name}", node.Input0, node.Input0Rank == 3 ? fromN1WCtoNCH : toNCHW); - net.Flatten(node.Name, nchwTranspose); - // No need to transpose back b/c final shape is always NC (rank 2) - } - - Output(node, rank:2); - }); - Add("Concat", (net, node) => { - int axis = node.AxisOptional(0); - - if (node.Inputs.Length == 1) - net.Identity(node.Name, node.Input0); - else - { - // TODO: write dedicated ONNXTensor.Concat() so that output shape is exact to ONNX - // if (node.AreAllInputsConst) - // Const(node, ONNXTensor.Concat(node.Inputs.Select(i => constantTensors[i]).ToArray(), axis)); - - axis = ONNXLayout.ConvertAxisToBarracuda(axis, onnxRank: node.Input0Rank, onnxLayout: "NCHW"); - net.Concat(node.Name, node.Inputs, axis, true); - - bool lastAxis = (axis == -1 || axis == TensorShape.C || axis == node.Input0Rank - 1); // last axis in Barracuda is feature axis - if (lastAxis) - { - var featuresConcatenated = node.Inputs.Sum(i => variableTensors[i].features); - Output(node, features: featuresConcatenated); - } - } - }); - Add("Split", (net, node) => { - - int axis = node.AxisOptional(0); - int[] splits; - try { - splits = node.GetRequiredIntArray("split"); - } catch (OnnxLayerImportException) { - throw new OnnxLayerImportException($"Unsupported default attribute `split` for node {node.Name} of type Split. Value is required."); - } - - Assert.IsTrue(splits.Length == node.Outputs.Length); - axis = ONNXLayout.ConvertAxisToBarracuda(axis, onnxRank:node.Input0Rank, onnxLayout:"NCHW"); - int currentSliceStartIndex = 0; - - //Convert `Split` into multiple `StridedSlice` operations. - for (int i = 0; i < splits.Length; ++i) - { - var starts = new int[] {0, 0, 0, 0, 0, 0, 0, 0}; - var ends = new int[] {0, 0, 0, 0, 0, 0, 0, 0}; - var strides = new int[] {1, 1, 1, 1, 1, 1, 1, 1}; - starts[axis] = currentSliceStartIndex; - ends[axis] = starts[axis] + splits[i]; - net.StridedSlice(node.Outputs[i], node.Input0,starts,ends,strides); - currentSliceStartIndex += splits[i]; - } - }); - Add("Slice", (net, node) => { - int[] starts, ends, axes, steps; - if (node.InputCount > 1) // Slice-10 - { - var constStarts = node.Input1Constant(onnxLayout:"C", name:"starts"); - var constEnds = node.Input2Constant(onnxLayout:"C", name:"ends"); - var defaultAxes = new Tensor(constStarts.shape, Enumerable.Range(0, constStarts.length).Select(v => (float)v).ToArray()); - var constAxes = node.Input3ConstantOptional(defaultAxes, onnxLayout:"C", name:"axes"); - var constSteps = node.Input4ConstantOptional(constStarts.shape, 1.0f, onnxLayout:"C", name:"steps"); - - starts = constStarts.AsInts(); - ends = constEnds.AsInts(); - axes = constAxes.AsInts(); - steps = constSteps.AsInts(); - } - else // Slice-1 - { - starts = node.Starts; - ends = node.Ends; - axes = node.AxesOptional(Enumerable.Range(0, starts.Length).ToArray()); - steps = Enumerable.Repeat(1, starts.Length).ToArray(); - } - - Assert.IsTrue(starts.Length == ends.Length); - var onnxRank = node.Input0Rank; - var onnxStarts = Enumerable.Repeat(0, onnxRank).ToArray(); - var onnxEnds = Enumerable.Repeat(int.MaxValue, onnxRank).ToArray(); // by default copy the whole axis till the end - var onnxSteps = Enumerable.Repeat(1, onnxRank).ToArray(); - - // NOTE: begin=0, end=0, stride=1 <= full range from existing axis - // begin=0, end=inf,stride=1 <= full range from existing axis - // begin=0, end=X, stride=1 <= full range from existing axis, if X==last element on this axis - // begin=0, end=0, stride=0 <= new axis OR shrink axis to single 1st element - // begin=N, end=N, stride=0 <= shrink axis to single Nth element - // These notes are copied from TensorExtensions.ApplyStridedSlice(...) - - for (int i = 0; i < axes.Length; ++i) - { - var axis = axes[i]; - if (axis < 0) - axis += onnxRank; - axis = Math.Min(Math.Max(axis, 0), onnxRank); - - onnxStarts[axis] = starts[i]; - onnxEnds[axis] = ends[i]; - onnxSteps[axis] = steps[i]; - } - - if (node.IsInput0Const) - { - var slicedTensor = constantTensors[node.Input0].Slice(starts:onnxStarts, ends:onnxEnds, steps:onnxSteps); - Const(node, slicedTensor); - } - else - { - net.StridedSlice(node.Name, node.Input0, - starts:ONNXLayout.PermuteToBarracuda(onnxStarts, onnxLayout:"NCHW",0), - ends:ONNXLayout.PermuteToBarracuda(onnxEnds, onnxLayout:"NCHW",int.MaxValue), - strides:ONNXLayout.PermuteToBarracuda(onnxSteps, onnxLayout:"NCHW",1)); - } - }); - Add("Tile", (net, node) => - { - // TODO: Implement Tile in ONNXTensor for const - var onnxRepeats = node.Input1Constant(onnxLayout: "C", name: "repeats").AsInts(); - var repeats = ONNXLayout.ConvertSymbolicShapeToBarracuda(onnxRepeats, onnxLayout: "NCHW"); - - var features = node.Input0Features; - features *= repeats[1]; - - Output(node.Name, rank: node.Input0Rank, features: features); - // only 4D Tile support for now - net.Tile(node.Name, node.Input0, new[] { repeats[2], repeats[5], repeats[6], repeats[7] }); - }); - Add("Gather", (net, node) => - { - int axis = node.AxisOptional(0); - - if (node.IsInput0Const && node.IsInput1Const) - { - var indices = node.Input1Constant(onnxLayout:"C", name:"indices").AsInts(); - - // If the previous node was a shape and we're gathering an inferred value, then don't treat the shape as a constant - if (node.Input0.IndexOf("shape", StringComparison.OrdinalIgnoreCase) >= 0 - && indices.Length == 1 && indices[0] > 0 - && constantTensors[node.Input0].ToBarracuda("C")[indices[0]] == 0 // Must resolve at runtime - && variableTensors.TryGetValue(node.Input0, out VariableTensor input0Tensor) - && variableTensors.TryGetValue(input0Tensor.productOfShape, out VariableTensor shapeInputTensor)) - { - axis = ONNXLayout.ConvertAxisToBarracuda(indices[0], shapeInputTensor.rank, "NCHW"); - net.Shape(node.Name, input0Tensor.productOfShape, axis); - D.Log($"Re-writing {node.Name} to a Shape+Axis layer (results in a scalar)"); - } - else - { - ONNXTensor gatheredTensor = constantTensors[node.Input0].Gather(axis, indices); - Const(node, gatheredTensor); - } - } - else - { - int input1Rank = node.Input1Rank; - if (node.IsInput1Const) - { - // The original rank was cached above since our constant tensor requires a shape of rank 1 and original may have been a scalar - var indices = node.Input1Constant(onnxLayout: "C", name: "indices").AsFloats(); - var constTensor = new ONNXTensor(new Tensor(new [] { indices.Length, 1, 1, 1, 1, 1, 1, 1 }, indices), new [] { indices.Length }); - Const(node.Input1, constTensor); - } - - axis = ONNXLayout.ConvertAxisToBarracuda(axis, onnxRank:node.Input0Rank, onnxLayout:"NCHW"); - net.Gather(node.Name, node.Input0, node.Input1, axis, true); - Output(node.Name, rank: input1Rank + node.Input0Rank - 1); - } - }); - Add("NonMaxSuppression", (net, node) => - { - int centerPointBox = node.GetOptionalInt("center_point_box", 0); - - var boxes = node.GetRequiredInput(0); - var scores = node.GetRequiredInput(1); - object maxOutputBoxesPerClass = 0f; - object iouThreshold = 0f; - object scoreThreshold = 0f; - - if (node.InputCount > 4 && node.IsInput2Const && node.IsInput3Const && node.IsInput4Const - || node.InputCount > 3 && node.IsInput2Const && node.IsInput3Const - || node.InputCount > 2 && node.IsInput2Const) - { - // Use constant version (possibly with defaults) - maxOutputBoxesPerClass = node.Input2ConstantOptional((float)maxOutputBoxesPerClass, "C", nameof(maxOutputBoxesPerClass))[0]; - iouThreshold = node.Input3ConstantOptional((float)iouThreshold, "C", nameof(iouThreshold))[0]; - scoreThreshold = node.Input4ConstantOptional((float)scoreThreshold, "C", nameof(scoreThreshold))[0]; - } - else - { - // Use dynamic tensor version - maxOutputBoxesPerClass = node.Input2Optional; - iouThreshold = node.Input3Optional; - scoreThreshold = node.Input4Optional; - } - - net.NonMaxSuppression(node.Name, boxes, scores, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, centerPointBox); - Output(node, rank: 2); - }); - Add("OneHot", (net, node) => { - node.UnsupportedAttribute("axis", -1); - - var defaultOffOn = new Tensor(2, 0, new float[] {0, 1}); - - var depth = (int)node.Input1Constant(onnxLayout:"C", name:"depth")[0]; - var offon = node.Input2ConstantOptional(defaultOffOn, onnxLayout:"C", name:"values"); - net.OneHot(node.Name, node.Input0, depth, (int)offon[1], (int)offon[0]); - Output(node, features: depth, rank: node.Input0Rank + 1); - }); - Add("TopK", (net, node) => { - int axis = node.AxisOptional(-1); - axis = ONNXLayout.ConvertAxisToBarracuda(axis, onnxRank:node.Input0Rank, onnxLayout:"NCHW"); - - // TopK-11 introduced these options - bool largest = node.GetOptionalInt("largest", 1) == 1; - // If sorted = false, then the output is undefined - bool sorted = node.GetOptionalInt("sorted", 1) == 1; - - string kName; - if (node.InputCount > 1) // TopK-10 introduced K as an input tensor - { - kName = node.Input1; - } - else - { - // TopK-1 - int k = node.GetRequiredInt("k"); - kName = "Const_TopK"; - var kTensor = new ONNXTensor( - data:new Tensor(new[] { 1, 1, 1, 1 }, new[] { (float)k }, kName), - onnxShape:new [] { 1 }); - - Const(node, kTensor); - } - - Layer indices = net.TopKIndices(node.Outputs[1], node.Input0, kName, axis, largest, sorted); - Output(node.Outputs[1], rank: node.Input0Rank); - net.TopKValues(node.Outputs[0], node.Input0, indices, axis); - Output(node.Outputs[0], rank: node.Input0Rank); - }); - - Add("NonZero", (net, node) => { - - if (node.IsInput0Const) - { - var nonZeroTensor = constantTensors[node.Input0].NonZero(); - Const(node, nonZeroTensor); - } - else - { - net.NonZero(node.Name, node.Input0); - Output(node.Outputs[0], rank: 2); - } - }); - - // LSTM - - // - it = f(Xt*Wi + Ht_1*Ri + Wbi + Rbi) - // - ft = f(Xt*Wf + Ht_1*Rf + Wbf + Rbf) - // - ct = g(Xt*Wc + Ht_1*Rc + Wbc + Rbc), c means j in our formula - // - Ct = ft . Ct_ + it . ct - // - ot = f(Xt*Wo + Ht_1*Ro + Wbo + Rbo) - // - Ht = ot . h(Ct) - - Add("LSTM", (net, node) => - { - var W = node.Input1Constant(onnxLayout: "RKC", name: "W"); - var R = node.Input2Constant(onnxLayout: "RKC", name: "R"); - var B = node.Input3Constant(onnxLayout: "RC", name: "B"); - - // gate order [iofj] - - var ops = new ReferenceCPUOps(); - var w_i = ops.StridedSlice(W, new[] {0,0,0,0}, new[] {W.batch,1,1,W.channels/4 }, new[] {1, 1, 1, 1}); - var w_o = ops.StridedSlice(W, new[] {0,0,0,W.channels/4}, new[] {W.batch,1,1,2*W.channels/4 }, new[] {1, 1, 1, 1}); - var w_f = ops.StridedSlice(W, new[] {0,0,0,2*W.channels/4}, new[] {W.batch,1,1,3*W.channels/4 }, new[] {1, 1, 1, 1}); - var w_j = ops.StridedSlice(W, new[] {0,0,0,3*W.channels/4}, new[] {W.batch,1,1,4*W.channels/4 }, new[] {1, 1, 1, 1}); - - var r_i = ops.StridedSlice(R, new[] {0,0,0,0}, new[] {R.batch,1,1,R.channels/4 }, new[] {1, 1, 1, 1}); - var r_o = ops.StridedSlice(R, new[] {0,0,0,R.channels/4}, new[] {R.batch,1,1,2*R.channels/4 }, new[] {1, 1, 1, 1}); - var r_f = ops.StridedSlice(R, new[] {0,0,0,2*R.channels/4}, new[] {R.batch,1,1,3*R.channels/4 }, new[] {1, 1, 1, 1}); - var r_j = ops.StridedSlice(R, new[] {0,0,0,3*R.channels/4}, new[] {R.batch,1,1,4*R.channels/4 }, new[] {1, 1, 1, 1}); - - var wb_i = ops.StridedSlice(B, new[] {0,0,0,0}, new[] {1,1,1,B.channels/8 }, new[] {1, 1, 1, 1}); - var wb_o = ops.StridedSlice(B, new[] {0,0,0,B.channels/8}, new[] {1,1,1,2*B.channels/8 }, new[] {1, 1, 1, 1}); - var wb_f = ops.StridedSlice(B, new[] {0,0,0,2*B.channels/8}, new[] {1,1,1,3*B.channels/8 }, new[] {1, 1, 1, 1}); - var wb_j = ops.StridedSlice(B, new[] {0,0,0,3*B.channels/8}, new[] {1,1,1,4*B.channels/8 }, new[] {1, 1, 1, 1}); - - var rb_i = ops.StridedSlice(B, new[] {0,0,0,4*B.channels/8}, new[] {1,1,1,5*B.channels/8 }, new[] {1, 1, 1, 1}); - var rb_o = ops.StridedSlice(B, new[] {0,0,0,5*B.channels/8}, new[] {1,1,1,6*B.channels/8 }, new[] {1, 1, 1, 1}); - var rb_f = ops.StridedSlice(B, new[] {0,0,0,6*B.channels/8}, new[] {1,1,1,7*B.channels/8 }, new[] {1, 1, 1, 1}); - var rb_j = ops.StridedSlice(B, new[] {0,0,0,7*B.channels/8}, new[] {1,1,1,8*B.channels/8 }, new[] {1, 1, 1, 1}); - - - var memSize = r_i.flatHeight; - - var baseLSTMName = ResolveLstmInputName(node); - var initial_h = $"{baseLSTMName}_h"; - var initial_c = $"{baseLSTMName}_c"; - - var baseLSTMOutputName = ResolveLstmOutputName(node); - var output_h = $"{baseLSTMOutputName}_h"; - var output_c = $"{baseLSTMOutputName}_c"; - - - var i_mad_w = net.Dense($"{node.Name}_bc_i_mad_w", node.Input0, w_i, wb_i); - var i_mad_r = net.Dense($"{node.Name}_bc_i_mad_r", initial_h, r_i, rb_i); - var i_mad = net.Add($"{node.Name}_bc_i_mad", new [] {i_mad_w, i_mad_r}); - - var j_mad_w = net.Dense($"{node.Name}_bc_j_mad_w", node.Input0, w_j, wb_j); - var j_mad_r = net.Dense($"{node.Name}_bc_j_mad_r", initial_h, r_j, rb_j); - var j_mad = net.Add($"{node.Name}_bc_j_mad", new [] {j_mad_w, j_mad_r}); - - var f_mad_w = net.Dense($"{node.Name}_bc_f_mad_w", node.Input0, w_f, wb_f); - var f_mad_r = net.Dense($"{node.Name}_bc_f_mad_r", initial_h, r_f, rb_f); - var f_mad = net.Add($"{node.Name}_bc_f_mad", new [] {f_mad_w, f_mad_r}); - - var o_mad_w = net.Dense($"{node.Name}_bc_o_mad_w", node.Input0, w_o, wb_o); - var o_mad_r = net.Dense($"{node.Name}_bc_o_mad_r", initial_h, r_o, rb_o); - var o_mad = net.Add($"{node.Name}_bc_o_mad", new [] {o_mad_w, o_mad_r}); - - var i = net.Sigmoid($"{node.Name}_bc_i_sigmoid", i_mad); - var j = net.Tanh($"{node.Name}_bc_j_tanh", j_mad); - var f = net.Sigmoid($"{node.Name}_bc_f_sigmoid", f_mad); - var o = net.Sigmoid($"{node.Name}_bc_o_sigmoid", o_mad); - - var state_c_mul = net.Mul($"{node.Name}_bc_state_c_mul", new[] {initial_c, f.name}); - var i_j_mul = net.Mul($"{node.Name}_bc_i_j_mul", new[] {i, j}); - var state_c = net.Add(output_c, new[] {state_c_mul, i_j_mul}); - var state_c_tanh = net.Tanh($"{node.Name}_bc_state_c_tanh", state_c); - var state_h = net.Mul(output_h, new[] {o, state_c_tanh}); - - net.Identity(node.Outputs[0], state_h); - net.Identity(node.Outputs[1], state_h); - net.Identity(node.Outputs[2], state_c); - - net.Memory(initial_c, state_c, new TensorShape(-1,1,1,memSize)); - net.Memory(initial_h, state_h, new TensorShape(-1,1,1,memSize)); - - Output(node.Outputs[0], features:wb_o.channels, rank:2); - Output(node.Outputs[1], features:wb_o.channels, rank:2); - Output(node.Outputs[2], features:wb_o.channels, rank:2); - - }); - - // Activation ops - Add("Relu", (net, node) => { net.Relu(node.Name, node.Input0); }); - Add("Softmax", (net, node) => - { - const int defaultAxis = 1; - int axis = node.AxisOptional(defaultAxis); // Leave in NCHW form and transpose instead - if (axis < 0) - axis = node.Input0Rank + axis; - - string input = node.Input0; - string output = node.Name; - - int rank = node.Input0Rank; - if(rank == 2) - { - axis = axis == 0 ? 0 : 3; // NC => N__C - } - else if (rank == 3) - { - axis = axis == 0 ? 0 : (axis == 1 ? 3 : axis); // NCW => N_WC - } - else - { - axis = axis == 0 ? 0 : (axis == 1 ? 3 : axis-1); // NCHW => NHWC - } - - - Layer layer = net.Softmax(output, input, axis); - }); - Add("Tanh", (net, node) => { net.Tanh(node.Name, node.Input0); }); - Add("Sqrt", (net, node) => { net.Sqrt(node.Name, node.Input0); }); - Add("Sigmoid", (net, node) => { net.Sigmoid(node.Name, node.Input0); }); - Add("Elu", (net, node) => { net.Elu(node.Name, node.Input0, node.AlphaOptional(1f)); }); - Add("LeakyRelu",(net, node) => { net.LeakyRelu(node.Name, node.Input0, node.AlphaOptional(0.01f)); }); - Add("Selu", (net, node) => { net.Selu(node.Name, node.Input0, node.AlphaOptional(1.67326f), node.GammaOptional(1.0507f)); }); - Add("Swish", (net, node) => { net.Swish(node.Name, node.Input0); }); - Add("PRelu", (net, node) => { net.PRelu(node.Name, node.Input0, node.Input1); }); - Add("LogSoftmax", (net, node) => { net.LogSoftmax(node.Name, node.Input0); node.UnsupportedAttribute("axis", 1); }); - // TODO: Add("Hardmax", (net, node) => { net.Hardmax(node.Name, node.Input0); node.UnsupportedAttribute("axis", 1); }); - Add("Softplus", (net, node) => { net.Softplus(node.Name, node.Input0); }); - // TODO: Add("Softsign", (net, node) => { net.Softsign(node.Name, node.Input0); }); - // TODO: Add("HardSigmoid", (net, node) => { net.HardSigmoid(node.Name, node.Input0, node.AlphaOptional(0.2f), node.BetaOptional(0.5f)); }); - Add("Exp", (net, node) => { net.Exp(node.Name, node.Input0); }); - Add("Log", (net, node) => { net.Log(node.Name, node.Input0); }); - Add("Reciprocal", (net, node) => { net.Reciprocal(node.Name, node.Input0); }); - Add("Abs", (net, node) => { net.Abs(node.Name, node.Input0); }); - Add("Neg", (net, node) => { net.Neg(node.Name, node.Input0); }); - Add("Ceil", (net, node) => { net.Ceil(node.Name, node.Input0); }); - Add("Floor", (net, node) => { net.Floor(node.Name, node.Input0); }); - Add("Round", (net, node) => { net.Round(node.Name, node.Input0); }); - Add("Clip", (net, node) => { - float minValue = float.MinValue; - float maxValue = float.MaxValue; - - if (node.InputCount > 1) // Clip-11 - { - minValue = node.Input1ConstantOptional(minValue, onnxLayout:"C", name:"min")[0]; - maxValue = node.Input2ConstantOptional(maxValue, onnxLayout:"C", name:"max")[0]; - } - else - { - minValue = node.MinOptional(minValue); - maxValue = node.MaxOptional(maxValue); - } - net.Clip(node.Name, node.Input0, minValue, maxValue); - }); - Add("Acos", (net, node) => { net.Acos(node.Name, node.Input0); }); - Add("Acosh", (net, node) => { net.Acosh(node.Name, node.Input0); }); - Add("Asin", (net, node) => { net.Asin(node.Name, node.Input0); }); - Add("Asinh", (net, node) => { net.Asinh(node.Name, node.Input0); }); - Add("Atan", (net, node) => { net.Atan(node.Name, node.Input0); }); - Add("Atanh", (net, node) => { net.Atanh(node.Name, node.Input0); }); - Add("Cos", (net, node) => { net.Cos(node.Name, node.Input0); }); - Add("Cosh", (net, node) => { net.Cosh(node.Name, node.Input0); }); - Add("Sin", (net, node) => { net.Sin(node.Name, node.Input0); }); - Add("Sinh", (net, node) => { net.Sinh(node.Name, node.Input0); }); - Add("Tan", (net, node) => { net.Tan(node.Name, node.Input0); }); - - string[] GetCorrectedConstants(ONNXNodeWrapper node, ModelBuilder net) - { - string[] inputs = new string[node.Inputs.Length]; - Array.Copy(node.Inputs, inputs, inputs.Length); - - if (node.IsInput1Const) - { - string onnxLayout; - switch (node.Input1Rank) - { - case 1: - onnxLayout = "C"; - break; - default: - onnxLayout = "NCHW"; - break; - } - - string constName = $"Const_{node.Input1}"; - if (!constantTensors.ContainsKey(constName)) - { - Tensor tensorData = node.Input1Constant(onnxLayout, node.Input1); - - if(node.Input0Rank == 3 && node.Input1Rank == 1) - { - // 1,1,1,C -> 1,1,C,1 - tensorData = tensorData.Reshape(new int[] { 1, 1, tensorData.channels, 1 }); - } - - Layer layer = net.Const(constName, tensorData); - inputs[1] = layer.name; - Const(constName, new ONNXTensor(tensorData, tensorData.shape.ToArray())); - } - } - - return inputs; - } - - // Broadcast ops - Add("Add", (net, node) => { net.Add(node.Name, GetCorrectedConstants(node, net)); }); - Add("Sum", (net, node) => { net.Add(node.Name, GetCorrectedConstants(node, net)); }); // Sum is implemented via Add - Add("Sub", (net, node) => { net.Sub(node.Name, GetCorrectedConstants(node, net)); }); - Add("Mul", (net, node) => { net.Mul(node.Name, GetCorrectedConstants(node, net)); }); - Add("Div", (net, node) => { net.Div(node.Name, GetCorrectedConstants(node, net)); }); - Add("Pow", (net, node) => { net.Pow(node.Name, node.Inputs); }); - Add("Min", (net, node) => { net.Min(node.Name, node.Inputs); }); - Add("Max", (net, node) => { net.Max(node.Name, node.Inputs); }); - Add("Mean", (net, node) => { net.Mean(node.Name, node.Inputs); }); - - // Logical ops - Add("Greater", (net, node) => { net.Greater(node.Name, node.Input0, node.Input1); }); - Add("Less", (net, node) => { net.Less(node.Name, node.Input0, node.Input1); }); - Add("LessOrEqual", (net, node) => { net.LessEqual(node.Name, node.Input0, node.Input1); }); - Add("Equal", (net, node) => { net.Equal(node.Name, node.Input0, node.Input1); }); - Add("Or", (net, node) => { net.LogicalOr(node.Name, node.Input0, node.Input1); }); - Add("And", (net, node) => { net.LogicalAnd(node.Name, node.Input0, node.Input1); }); - Add("Not", (net, node) => { net.LogicalNot(node.Name, node.Input0); }); - Add("Xor", (net, node) => { net.LogicalXor(node.Name, node.Input0, node.Input1); }); - Add("Where", (net, node) => { net.Where(node.Name, node.Input0, node.Input1, node.Input2); }); - - // Padding ops - Add("Pad", (net, node) => - { - // TODO refactor pad handling to truncate only in NCHWToNHWCPass - var mode = node.ModeOptional("constant"); - var pads = node.Pads; - switch (mode) - { - case "constant": - var value = node.GetOptionalFloat("value", 0.0f); - if (pads.Length > 4) - net.Border3D(node.Name, node.Input0, pads, value); - else - net.Border2D(node.Name, node.Input0, pads, value); - break; - case "reflect": net.Pad2DReflect(node.Name, node.Input0, pads); break; - case "edge": net.Pad2DEdge(node.Name, node.Input0, pads); break; - } - }); - - // Pooling ops - Add("AveragePool", (net, node) => { - node.UnsupportedAttribute("ceil_mode", 0); - node.UnsupportedAttribute("count_include_pad", 0); - net.AvgPool2D(node.Name, node.Input0, node.KernelShape, node.Strides, node.Pads); - }); - Add("MaxPool", (net, node) => { - node.UnsupportedAttribute("ceil_mode", 0); - node.UnsupportedAttribute("dilations", new[] {1, 1}); - node.UnsupportedAttribute("storage_order", 0); - - int[] strides = node.Strides; - int[] pads = node.Pads; - - if (strides.Length == 1) - strides = new[] { 1, strides[0] }; - Assert.IsTrue(strides.Length == 2); - - int[] kernenShape = node.KernelShape; - if (kernenShape.Length == 1) - kernenShape = new[] { kernenShape[0], 1 }; - - net.MaxPool2D(node.Name, node.Input0, kernenShape, strides, pads); - }); - Add("GlobalAveragePool", (net, node) => { net.GlobalAvgPool2D(node.Name, node.Input0); }); - Add("GlobalMaxPool", (net, node) => { net.GlobalMaxPool2D(node.Name, node.Input0); }); - Add("Upsample", (net, node) => { - // @TODO: the same for Resize node - string mode = node.ModeOptional("nearest"); - if (node.InputCount == 2 && !node.IsInput1Const) - if (node.Input0Rank <= 4) - net.Upsample2D(node.Name, node.Input0, node.Input1, IsModeBilinear(net, node, mode)); - else - net.Upsample3D(node.Name, node.Input0, node.Input1, IsModeBilinear(net, node, mode)); - else - Resample(net, node, node.Name, node.Input0, node.Scales, mode); - }); - Add("Resize", (net, node) => { - if (node.InputCount > 2) // Resize-11 - { - node.UnsupportedAttribute("coordinate_transformation_mode", "half_pixel"); - node.UnsupportedAttribute("cubic_coeff_a", -0.75f); - node.UnsupportedAttribute("exclude_outside", 0); - node.UnsupportedAttribute("extrapolation_value", 0f); - node.UnsupportedAttribute("nearest_mode", "round_prefer_floor"); - - // Inputs (3 - 4) - // X : T1 - // roi : T2, It only takes effect when coordinate_transformation_mode is "tf_crop_and_resize" - // scales : tensor(float) - // sizes (optional) : tensor(int64) - - // TODO: cropping via roi input - // TODO: support sizes - } - - if (node.InputCount > 3) - { - var mode = node.ModeOptional("nearest"); - var bilinear = IsModeBilinear(net, node, mode); - net.Resample2D(node.Name, node.Input0, node.Sizes, bilinear); - } - else - { - Resample(net, node, node.Name, node.Input0, node.Scales, node.ModeOptional("nearest")); - } - }); - Add("Transpose", (net, node) => - { - // From https://github.com/onnx/onnx/blob/master/docs/Operators.md#transpose - // By default, reverse the dimensions, otherwise permute the axes according to the values given. - - if (node.IsInput0Const) - { - int inputTensorRank = constantTensors[node.Input0].rank; - var defaultPermutations = new int[inputTensorRank]; - for (int i = 0; i < inputTensorRank; ++i) - defaultPermutations[i] = inputTensorRank - 1 - i; - var permutations = node.GetOptionalIntArray("perm", defaultPermutations); - - var transposedTensor = constantTensors[node.Input0].Permute(permutations); - Const(node, transposedTensor); - } - else - { - var defaultPermutations = new[] {5, 4, 3, 2, 1, 0}; - var permutations = node.GetOptionalIntArray("perm", defaultPermutations); - if (permutations.Length > 6) - throw new OnnxLayerImportException($"Transpose support up to 6 dimensions but got a permutations of rank {permutations}."); - - if (Enumerable.SequenceEqual(permutations, new[] { 0, 3, 1, 2 }) || // NHWC -> NCHW - Enumerable.SequenceEqual(permutations, new[] { 0, 2, 3, 1 })) // NCHW -> NHWC - { - // @TODO: reorder uptream nodes and global input dimensions accordingly from NHWC -> NCHW - net.Identity(node.Name, node.Input0); - - if (permutations[1] == 3) // NHWC -> NCHW - Output(node, layout: VariableTensor.Layout.ChannelsFirst); - else if (permutations[1] == 2) // NCHW -> NHWC - { - Output(node, layout: VariableTensor.Layout.ChannelsLast); - layerRequiringUpstreamPatch.Add(node.Name); - } - else - Assert.IsTrue("Reached unexpected branch" == ""); - } - else if (Enumerable.SequenceEqual(permutations, new[] { 0, 2, 1 })) // NWC <-> NCW - { - // @TODO: reorder uptream nodes and global input dimensions accordingly from NHWC -> NCHW - if (m_FixTf2OnnxExportIssues) - { - Warn(net, node, $"Use '--inputs-as-nchw' flag when exporting model from Tensorflow with tf2onnx"); - net.Identity(node.Name, node.Input0); - - // flip layout - if (node.Input0Layout == VariableTensor.Layout.ChannelsLast) - Output(node, layout: VariableTensor.Layout.ChannelsFirst); - else - { - Output(node, layout: VariableTensor.Layout.ChannelsLast); - layerRequiringUpstreamPatch.Add(node.Name); - } - } - else - { - int[] barracudaPermutation = { 0, 1, 3, 2 }; - net.Transpose(node.Name, node.Input0, barracudaPermutation); - } - } - else if (Enumerable.SequenceEqual(permutations, new[] { 1, 0, 2 })) // batch <-> seq_length - { - // LSTM layout is problematic as it's usually flanked by a few Transposed if exported from TF - // @TODO investigate if better solution - net.Identity(node.Name, node.Input0); - } - else - { - //Here we assume `Channels` are represented by only one dimensions and it that it is the 2nd one. - //however in some case (example: shufflenet, sub-pixel-cnn) reshape-transpose-reshape pattern lead - //to channels being represented by two dimenssion this is handled in - //FixReshapeTransposePatternWhenChannelsAreSplitIntoMultipleDimensions() - - //Expand received permutation to 6D adding padding between Channels and other feature dimensions. - int numDimensionDimensionsThatWerePaddedAtCenterOfTranspose = 0; - var permutationsNCTDHW = ONNXLayout.ExpandONNXPermutationToNCTDHW(permutations, out numDimensionDimensionsThatWerePaddedAtCenterOfTranspose); - - //From channel first to channel last. - var permutationsNTDHWC = ONNXLayout.ConvertPermutationToLayout(permutationsNCTDHW, "NCTDHW", "NTDHWC"); - - //6d to 8d - int[] permuteSRNTDHWC = new int[TensorShape.MaxRank]; - permuteSRNTDHWC[0] = 0; - permuteSRNTDHWC[1] = 1; - for (int i = 0; i < 6; ++i) - permuteSRNTDHWC[i+2] = 2+permutationsNTDHWC[i]; - - var layer = net.Transpose(node.Name, node.Input0, permuteSRNTDHWC); - layer.axis = numDimensionDimensionsThatWerePaddedAtCenterOfTranspose; - } - } - }); - - Add("DepthToSpace", (net, node) => { - net.DepthToSpace(node.Name, node.Input0, node.BlockSize, node.ModeOptional("DCR")); - }); - - Add("SpaceToDepth", (net, node) => { - net.SpaceToDepth(node.Name, node.Input0, node.BlockSize); - }); - - // Tensor ops - Add("Gemm", (net, node) => { - node.UnsupportedAttribute("alpha", 1.0f); - node.UnsupportedAttribute("beta", 1.0f); - node.UnsupportedAttribute("transA", 0); - var onnxLayout = node.TransBOptional() ? "KC" : "CK"; - var weights = node.Input1Constant(onnxLayout, name:"B"); - var biases = node.Input2ConstantOptional(Bias(weights.shape), 0.0f, onnxLayout:"C", name:"C"); - // Change data layout from "channels first" to "channels last" - weights = SwapSpatialDimensionsAndFeaturesInMatMulWeights(weights, weights.flatHeight, node.Input0Layout); - net.Dense(node.Name, node.Input0, weights, biases); - Output(node, features:weights.channels, rank:2); // Gemm forces flatten of the input to rank 2 - }); - Add("MatMul", (net, node) => { - if (node.InputCount == 2 && !node.IsInput1Const || node.Input0Rank != 2 || node.Input1Rank != 2) - { - // if inputs are const, need to transpose them - if(node.IsInput1Const) - { - var Y = constantTensors[node.Input1].ToBarracuda("NCTDHW"); - net.Const(node.Input1, Y); - } - net.MatMul(node.Name, node.Input0, node.Input1); - Output(node, features: node.Input0Features, rank: Math.Max(node.Input0Rank, node.Input1Rank)); - } - else - { - var weights = node.Input1Constant(onnxLayout: "CK", name: "B"); - var biases = node.DefaultTensor(Bias(weights.shape), 0.0f); - // Change data layout from "channels first" to "channels last" - weights = SwapSpatialDimensionsAndFeaturesInMatMulWeights(weights, node.Input0Features, node.Input0Layout); - net.Dense(node.Name, node.Input0, weights, biases); - Output(node, features: weights.channels, rank: 2); // MatMul forces flatten of the input to rank 2 - } - }); - Add("Conv", (net, node) => { - int[] dilationsDHW = new[] { 1, 1, 1 }; // @TODO trap on wrong values - int[] strides = node.Strides; - int[] pads = node.Pads; - - node.IgnoredAttribute("kernel_shape", "Kernel shape is derived from K tensor weights instead"); - var kernels = node.Input1Constant(onnxLayout: "KCHW", name: "W"); - - var kernelRank = node.Input1Rank; - if (kernelRank == 3) // Conv1D - { - dilationsDHW = node.DilatationsOptional(new[] { 1 }); // @TODO trap on wrong values - Assert.IsTrue(dilationsDHW.Length == 1); - dilationsDHW = new[] { 1, 1, dilationsDHW[0] }; - - if (strides.Length == 1) - strides = new[] { strides[0], 1 }; - - if (pads.Length == 2) - pads = new[] { pads[0], 0, pads[1], 0 }; - } - else if (kernelRank == 4) // Conv2D - { - dilationsDHW = node.DilatationsOptional(new[] { 1, 1 }); - Assert.IsTrue(dilationsDHW.Length == 2); - dilationsDHW = new[] { 1, dilationsDHW[0], dilationsDHW[1] }; - } - else if (kernelRank == 5) // Conv3D - { - //TODO specific error message for DepthwiseConv3D (or support it). - node.UnsupportedAttribute("group", 1); - - dilationsDHW = node.DilatationsOptional(new[] { 1, 1, 1 }); - Assert.IsTrue(dilationsDHW.Length == 3); - pads = node.Pads3D; - strides = node.Strides3D; - } - else - { - Warn(net, node, $"Unsuported Conv kernel rank. Conv1D/2D/3 assumes rank 3/4/5 respectively, but got {kernelRank}."); - } - - Assert.IsTrue(dilationsDHW.Length == 3); - if (dilationsDHW[0] != 1 || dilationsDHW[1] != 1 || dilationsDHW[2] != 1) - kernels = DilateKernel(kernels, dilationsDHW); // @TODO inefficient method. Support dilatation in kernel code properly - - var biases = node.Input2ConstantOptional(Bias(kernels.shape), 0.0f, onnxLayout: "C", name: "B"); - - if (node.GroupOptional() > 1) - net.DepthwiseConv2D(node.Name, node.Input0, strides, pads, kernels, biases); - else - { - if (kernelRank < 5) - net.Conv2D(node.Name, node.Input0, strides, pads, kernels, biases); - else - net.Conv3D(node.Name, node.Input0, strides, pads, kernels, biases); - } - - Output(node, features: kernels.channels); - }); - Add("ConvTranspose", (net, node) => { - node.UnsupportedAttribute("dilations", new[] {1, 1}); - node.UnsupportedAttribute("group", 1); - node.UnsupportedAttribute("output_shape", new int[0]); - node.IgnoredAttribute("kernel_shape", "Kernel shape is derived from K tensor weights instead"); - var kernels = node.Input1Constant(onnxLayout:"CKHW", name:"W"); - var biases = node.Input2ConstantOptional(Bias(kernels.shape), 0.0f, onnxLayout:"C", name:"B"); - net.Conv2DTrans(node.Name, node.Input0, node.Strides, node.Pads, node.OutputPadding, kernels, biases); - Output(node, features:kernels.channels); - }); - Add("BatchNormalization", (net, node) => { - var variance = node.Input4Constant(onnxLayout:"C", name:"var"); - var scale = node.Input1ConstantOptional(variance.shape, 1.0f, onnxLayout:"C", name:"scale"); - var bias = node.Input2ConstantOptional(variance.shape, 0.0f, onnxLayout:"C", name:"B"); - var mean = node.Input3ConstantOptional(variance.shape, 0.0f, onnxLayout:"C", name:"mean"); - if (variance.length != scale.length || scale.length != bias.length || bias.length != mean.length) - Warn(net, node, $"Number of elements in all parameters for BatchNorm must be the same." + - $"Parameter shapes are: {scale.shape}, {bias.shape}, {mean.shape}, {variance.shape}"); - if (variance.channels != node.Input0Features && node.Input0Features > 0) - Warn(net, node, $"Number of elements in BatchNorm must match features from the previous layer. Was expecting {node.Input0Features}, but got {variance.channels}."); - var fusedData = FuseBatchNormWeights(scale, bias, mean, variance, node.EpsilonOptional(), node.Input0Features); - net.ScaleBias(node.Name, node.Input0, fusedData.Item1, fusedData.Item2); - }); - Add("ImageScaler", (net, node) => - { - var attrBias = node.Bias; - var attrScale = node.ScaleOptional(); - int maxElements = attrBias.Length; - - Tensor scale = new Tensor(1, maxElements); - Tensor bias = new Tensor(1, maxElements); - for (int i = 0; i < maxElements; ++i) - { - scale[i] = attrScale; - bias[i] = attrBias[i]; - } - net.ScaleBias(node.Name, node.Input0, scale, bias); - }); - Add("InstanceNormalization", (net, node) => { - var scale = node.Input1Constant(onnxLayout:"C", name:"scale"); - var bias = node.Input2ConstantOptional(scale.shape, 0.0f, onnxLayout:"C", name:"B"); - if (scale.length != bias.length) - Warn(net, node, $"Number of elements in all parameters for InstanceNorm must be the same." + - $"Parameter shapes are: {scale.shape}, {bias.shape}"); - if (scale.channels != node.Input0Features && node.Input0Features > 0) - { - Warn(net, node, $"Number of elements in InstanceNorm must match features from the previous layer. Was expecting {node.Input0Features}, but got {scale.channels}."); - var scaleArray = scale.ToReadOnlyArray(); - Array.Resize(ref scaleArray, node.Input0Features); - var biasArray = bias.ToReadOnlyArray(); - Array.Resize(ref biasArray, node.Input0Features); - scale = new Tensor(1, node.Input0Features, scaleArray); - bias = new Tensor(1, node.Input0Features, biasArray); - } - net.Normalization(node.Name, node.Input0, scale, bias, node.EpsilonOptional()); - }); - Add("LRN", (net, node) => { - float bias = node.GetOptionalFloat("bias", 1.0f); - int size = node.GetRequiredInt("size"); - net.LRN(node.Name, node.Input0, node.AlphaOptional(0.0001f), node.BetaOptional(0.75f), bias, size); - }); - // random ops - Add("RandomNormal", (net, node) => { - var shape = ONNXLayout.ConvertShapeToBarracuda(onnxShape:node.Shape, onnxLayout:"NCHW"); - net.RandomNormal(node.Name, shape, node.MeanOptional(), node.ScaleOptional(), node.Seed); - Output(node, rank:node.Shape.Length); - }); - Add("RandomNormalLike", (net, node) => { - net.RandomNormal(node.Name, node.Input0, node.MeanOptional(), node.ScaleOptional(), node.Seed); - }); - Add("RandomUniform", (net, node) => { - float high = node.GetOptionalFloat("high", 1.0f); - float low = node.GetOptionalFloat("low", 0.0f); - var shape = ONNXLayout.ConvertShapeToBarracuda(onnxShape:node.Shape, onnxLayout:"NCHW"); - net.RandomUniform(node.Name, shape, low, high, node.Seed); - Output(node, rank:node.Shape.Length); - }); - Add("RandomUniformLike", (net, node) => { - float high = node.GetOptionalFloat("high", 1.0f); - float low = node.GetOptionalFloat("low", 0.0f); - net.RandomUniform(node.Name, node.Input0, low, high, node.Seed); - }); - Add("Multinomial", (net, node) => { - int samples = node.GetOptionalInt("sample_size", 1); - net.Multinomial(node.Name, node.Input0, samples, node.Seed); - }); - - // Reduce ops - Add("ReduceMax", (net, node) => { - Reduce(net, node, Layer.Type.ReduceMax); - }); - Add("ReduceMean", (net, node) => { - Reduce(net, node, Layer.Type.ReduceMean); - }); - Add("ReduceMin", (net, node) => { - Reduce(net, node, Layer.Type.ReduceMin); - }); - Add("ReduceProd", (net, node) => { - Reduce(net, node, Layer.Type.ReduceProd); - }); - Add("ReduceSum", (net, node) => { - Reduce(net, node, Layer.Type.ReduceSum); - }); - Add("ArgMax", (net, node) => { - node.UnsupportedAttribute("select_last_index"); - Reduce(net, node, Layer.Type.ArgMax); - }); - Add("ArgMin", (net, node) => { - node.UnsupportedAttribute("select_last_index"); - Reduce(net, node, Layer.Type.ArgMin); - }); - - - // Ignore, noop during inference - Add("Identity", (net, node) => { net.Identity(node.Name, node.Input0); }); - Add("Cast", (net, node) => { net.Identity(node.Name, node.Input0); }); - Add("Dropout", (net, node) => { net.Identity(node.Name, node.Input0); }); - } - - private string ResolveLstmOutputName(ONNXNodeWrapper node) - { - var baseLSTMOutputName = $"recurrent_out_{node.Name}"; - if (lstmOutputs.ContainsKey(node.Name)) - { - var actualName = lstmOutputs[node.Name]; - if (actualName.EndsWith(":0")) - actualName = actualName.Substring(0, actualName.Length - 2); - - if (actualName.EndsWith("_h") || actualName.EndsWith("_c")) - baseLSTMOutputName = actualName.Substring(0, actualName.Length - 2); - else - baseLSTMOutputName = actualName; - } - - return baseLSTMOutputName; - } - - private string ResolveLstmInputName(ONNXNodeWrapper node) - { - var baseLSTMName = $"recurrent_in_{node.Name}"; - if (lstmInputs.ContainsKey(node.Name)) - { - var actualName = lstmInputs[node.Name]; - if (actualName.EndsWith(":0")) - actualName = actualName.Substring(0, actualName.Length - 2); - - if (actualName.EndsWith("_h") || actualName.EndsWith("_c")) - baseLSTMName = actualName.Substring(0, actualName.Length - 2); - else - baseLSTMName = actualName; - } - - return baseLSTMName; - } - - // Fuse training time BatchNorm tensors into Scale & Bias - internal static Tuple FuseBatchNormWeights(Tensor gamma, Tensor beta, Tensor mean, Tensor variance, float epsilon, int maxElements = -1) - { - // https://github.com/Tencent/ncnn/blob/master/src/layer/batchnorm.cpp - // float sqrt_var = sqrt(var_data[i]); - // a_data[i] = bias_data[i] - slope_data[i] * mean_data[i] / sqrt_var; - // b_data[i] = slope_data[i] / sqrt_var; - // ... - // ptr[i] = b * ptr[i] + a; - Assert.IsTrue(gamma.channels == gamma.length); // assert 1d tensor - Assert.IsTrue(gamma.shape == beta.shape); - Assert.IsTrue(gamma.shape == mean.shape); - Assert.IsTrue(gamma.shape == variance.shape); - if (maxElements <= 0 || gamma.length < maxElements) // clip to the smallest valid number of channels - maxElements = gamma.length; - Tensor scale = new Tensor(1, maxElements); - Tensor bias = new Tensor(1, maxElements); - for (int i = 0; i < maxElements; ++i) - { - scale[i] = gamma[i] / Mathf.Sqrt(variance[i] + epsilon); - bias[i] = beta[i] - gamma[i] * mean[i] / Mathf.Sqrt(variance[i] + epsilon); - } - return Tuple.Create(scale, bias); - } - - // TODO move that in custom pass if need be - // Transpose channels first to channels last data in MatMul/GEMM weight tensor - internal static Tensor SwapSpatialDimensionsAndFeaturesInMatMulWeights(Tensor weights, int featureCount, VariableTensor.Layout layout) - { - if (featureCount == 0) // wild card feature: after Reduce, runtime correct weights. TODO: remove when full dims are known - return weights; - - Assert.IsTrue(featureCount <= weights.flatHeight); - - var weightsAssumeChannelsFirstLayout = (layout != VariableTensor.Layout.ChannelsLast); - if (featureCount != weights.flatHeight && weightsAssumeChannelsFirstLayout) - { - var shape = weights.shape; - var implicitSpatialDimensionsInWeights = shape.flatHeight / featureCount; - Assert.IsTrue(shape.flatHeight % featureCount == 0); - // reshape: __C____K -> __C__HWK - weights = weights.Reshape( - new TensorShape(featureCount, implicitSpatialDimensionsInWeights, 1, shape.channels)); - // permute: __C__HWK -> __H__WCK - var permutations = - TensorExtensions.Get8DPermutationsForNHWCPermutationsAndShape(weights.shape, new int[] {1, 0, 2, 3}); - weights = ONNXTensor.Permute(weights, permutations); - // reshape: __H__WCK -> __C____K - weights = weights.Reshape(shape); - } - return weights; - } - - internal static Model PatchFromIncorrectlyAssumedChannelsFirstToChannelsLastLayoutUpstream(Model model, List layerRequiringUpstreamPatch) - { - HashSet patchedInputIndices = new HashSet(); - HashSet patchedLayerAxis = new HashSet(); - - var inputIndexByName = new Dictionary(); - for (var i = 0; i < model.inputs.Count; ++i) - inputIndexByName.Add(model.inputs[i].name, i); - - // NOTE: although original input had NHWC layout - // (most probably exported from Tensorflow without '--inputs-as-nchw' flag) - // earlier when parsing input and axis we made incorrect assumption that they were NCHW - // now we need to revert that assumption! - foreach (var rootNodeForPatch in layerRequiringUpstreamPatch) - { - int inputIndex = -1; - var upstream = ModelAnalyzer.FindUpstreamLayers(model, new[] {rootNodeForPatch}); - foreach (var layer in upstream) - { - // patch axis - if (!patchedLayerAxis.Contains(layer.name) && ( - layer.type == Layer.Type.Concat || - layer.type == Layer.Type.Gather || - layer.type == Layer.Type.TopKValues))//TODO handle ReduceXX and StridedSlice - { - patchedLayerAxis.Add(layer.name); - if (layer.axis == 6) layer.axis = TensorShape.C; - else if (layer.axis == TensorShape.C) layer.axis = 6; - } - //patch inputs - foreach (var inputName in layer.inputs) - { - if (inputIndexByName.TryGetValue(inputName, out inputIndex) && - !patchedInputIndices.Contains(inputIndex)) - { - // example (NCHW): -1,2,2,16 -> (incorrect) -1,2,16,2 -> (fix) -1,2,2,16 - // example (NCW): -1,2,16 -> (incorrect) -1,1,16,2 -> (fix) -1,1,2,16 - patchedInputIndices.Add(inputIndex); - var inputDesc = model.inputs[inputIndex]; - inputDesc.shape = ONNXLayout.Permute(inputDesc.shape, new[] {-1, -1, 2, -1, -1, 7, 5, 6}); - model.inputs[inputIndex] = inputDesc; - } - } - // @TODO: figure out, if there is any case where we would have to propagate fixed layout assumption downstream? - } - } - - return model; - } - - // TODO: use Burst for this - internal static Tensor DilateKernel(Tensor kernel, int[] dilationsDHW) - { - //TODO: slow path in C# consider refactoring in Burst - Assert.IsTrue(dilationsDHW.Length == 3); - Assert.IsTrue(dilationsDHW[0] > 0); - Assert.IsTrue(dilationsDHW[1] > 0); - Assert.IsTrue(dilationsDHW[2] > 0); - - // https://arxiv.org/pdf/1603.07285.pdf - Tensor dilatedKernel = new Tensor(new TensorShape(1, - kernel.shape.kernelSpatialDepth + (kernel.shape.kernelSpatialDepth - 1) * (dilationsDHW[0] - 1), - kernel.shape.kernelHeight + (kernel.shape.kernelHeight - 1) * (dilationsDHW[1] - 1), - 1, - 1, - kernel.shape.kernelWidth + (kernel.shape.kernelWidth - 1) * (dilationsDHW[2] - 1), - kernel.shape.kernelDepth, - kernel.shape.kernelCount)); - - for (int c = 0; c < dilatedKernel.kernelDepth; ++c) - for (int k = 0; k < dilatedKernel.kernelCount; ++k) - { - for (int d = 0; d < kernel.shape.kernelSpatialDepth; ++d) - for (int y = 0; y < kernel.shape.kernelHeight; ++y) - for (int x = 0; x < kernel.shape.kernelWidth; ++x) - { - int od = d * dilationsDHW[0]; - int oy = y * dilationsDHW[1]; - int ox = x * dilationsDHW[2]; - - int strideD = d == (kernel.shape.kernelSpatialDepth - 1) ? 1 : dilationsDHW[0]; - int strideY = y == (kernel.shape.kernelHeight - 1) ? 1 : dilationsDHW[1]; - int strideX = x == (kernel.shape.kernelWidth - 1) ? 1 : dilationsDHW[2]; - - for (int dx = 0; dx < strideX; dx++) - for (int dy = 0; dy < strideY; dy++) - for (int dd = 0; dd < strideD; dd++) - { - dilatedKernel[ 0, od +dd, oy + dy, 0, 0, ox + dx, c, k] = 0.0f; - } - - float v = kernel[ 0, d, y, 0, 0, x, c, k]; - dilatedKernel[0, od, oy, 0, 0, ox, c, k] = v; - } - } - - return dilatedKernel; - } - - internal static TensorShape Bias(TensorShape shape) - { - return new TensorShape(1, 1, 1, shape.channels); - } - - internal static bool IsModeBilinear(ModelBuilder net, ONNXNodeWrapper node, string mode) - { - bool bilinear = false; - if (mode == "linear" || mode == "bilinear") - bilinear = true; - else if (mode != "nearest") - Warn(net, node, $"Mode `{mode}` is not supported for type {node.OperatorType}."); - - return bilinear; - } - - internal static Layer UpsampleNCHW(ModelBuilder net, ONNXNodeWrapper node, int scaleInputIndex) - { - string mode = node.ModeOptional("nearest"); - var bilinear = IsModeBilinear(net, node, mode); - - // NOTE: Intermediate NCHW -- op is implemented expecting NHWC by default, so this is non-runnable as-is - if (scaleInputIndex != 0 && node.InputCount > scaleInputIndex && !node.IsInputConst(scaleInputIndex)) - { - // TODO: Input1 may be rank 1, which means that this would require a swizzle in the actual data - if (node.Input0Rank <= 4) - return net.Upsample2D(node.Name, node.Input0, node.GetRequiredInput(scaleInputIndex), bilinear); - else - return net.Upsample3D(node.Name, node.Input0, node.GetRequiredInput(scaleInputIndex), bilinear); - } - else - return UpsampleFromConstNCHW(net, node, node.Name, node.Input0, node.ConvertScales(), mode); - } - - internal static Layer UpsampleFromConstNCHW(ModelBuilder net, ONNXNodeWrapper node, string name, object input, float[] scales, string mode) - { - if (!scales.All(x => x > 0.0f)) - Warn(net, node, $"Only positive scale values are supported."); - - if (scales.Length == 4 && - scales[0] == 1.0f && - scales[1] == 1.0f && - scales[2] < 1.0f && - scales[3] < 1.0f && - IsModeBilinear(net, node, mode)) - { - var scales2D = scales.Skip(2); - if (!scales2D.All(x => Mathf.Approximately(1f / x, Mathf.Round(1f / x)))) - Warn(net, node, $"Only inverse of scale values which produce integer are currently supported. Inverse of scale value will be rounded to closest integer."); - - var noPad = new[] { 0, 0, 0, 0 }; - var inverseScalesRoundedToInt = scales2D.Select(x => (int)Mathf.Round(1f / x)).ToArray(); - return net.AvgPool2D(name, input, inverseScalesRoundedToInt, inverseScalesRoundedToInt, noPad); - } - else - { - if (!scales.All(x => Mathf.Approximately(x, Mathf.Round(x)))) - Warn(net, node, $"Only integer scale values are currently supported. Scale value will be rounded to closest integer value."); - - var scalesRoundedToInt = scales.Select(x => (int)Mathf.Round(x)).ToArray(); - if (scales.Length > 5) - Warn(net, node, ">3D upsampling are not supported yet!"); - if (scales.Length == 5) - return net.Upsample3D(name, input, scalesRoundedToInt, IsModeBilinear(net, node, mode)); - else - return net.Upsample2D(name, input, scalesRoundedToInt, IsModeBilinear(net, node, mode)); - } - } - - internal static Layer Resample(ModelBuilder net, ONNXNodeWrapper node, string name, object input, float[] scales, string mode) - { - if (!scales.All(x => x > 0.0f)) - Warn(net, node, $"Only positive scale values are supported."); - - if (scales.All(x => x < 1.0f)) - { - if (!scales.All(x => Mathf.Approximately(1f/x, Mathf.Round(1f/x)))) - Warn(net, node, $"Only inverse of scale values which produce integer are currently supported. Inverse of scale value will be rounded to closest integer."); - - var noPad = new[] {0, 0, 0, 0}; - var inverseScalesRoundedToInt = scales.Select(x => (int)Mathf.Round(1f/x)).ToArray(); - // @TODO: nearest, actually this is bilinear downsampling - if (scales.Length > 2) - Warn(net, node, ">2D downsampling are not supported yet!"); - return net.AvgPool2D(name, input, inverseScalesRoundedToInt, inverseScalesRoundedToInt, noPad); - } - else - { - if (!scales.All(x => Mathf.Approximately(x, Mathf.Round(x)))) - Warn(net, node, $"Only integer scale values are currently supported. Scale value will be rounded to closest integer value."); - - var scalesRoundedToInt = scales.Select(x => (int)Mathf.Round(x)).ToArray(); - if (scales.Length > 3) - Warn(net, node, ">3D upsampling are not supported yet!"); - if (scales.Length > 2) - return net.Upsample3D(name, input, scalesRoundedToInt, IsModeBilinear(net, node, mode)); - else - return net.Upsample2D(name, input, scalesRoundedToInt, IsModeBilinear(net, node, mode)); - } - } - - private static int[] GetPermutationToMatchReduceWithDroppedDimensionsFromONNX(int[] droppedONNXAxis, int rank) - { - Assert.IsTrue(droppedONNXAxis.Length>0); - - //Barracuda always have all dimensions, however in ONNX it is not the case one can drop dimensions, - //Here we handle the case of ReduceXXX ops when they do so. - //An example: - //ONNX -> NCHW - //Reduce on C with keepDims=False. - //ONNX -> NHW - //However ONNX tensor semantic are deducted by position to be mapped to Barracuda in the following way: - //ONNX 1D -> N -> Barracuda N,1,1,1 - //ONNX 2D -> NC -> Barracuda N,1,1,C - //ONNX 3D -> NCW -> Barracuda N,1,W,C - //ONNX 4D -> NCHW -> Barracuda N,H,W,C - //Thus the output tensor above (NHW) will be mapped to N,1,W,C in Barracuda - //while Reduce in Barracuda would rather output N,H,W,1 if keepDim would be true. - //Here we find the transpose needed in Barracuda to match the ONNX behavior as seen by Barracuda. - //ie the transpose from N,H,W,1 to N,1,W,C in this case aka 0,3,2,1. - - //ONNX input Layout from rank - string onnxLayout; - switch (rank) - { - case 1: onnxLayout = "N"; - break; - case 2: onnxLayout = "NC"; - break; - case 3: onnxLayout = "NCW"; - break; - case 4: onnxLayout = "NCHW"; - break; - default: - //TODO support 8D - throw new OnnxLayerImportException($"Reduce ops support up to 4D at the moment, however received an input of rank {rank}."); - } - - //ONNX Layout once dimensions are dropped (example: NHW if C was dropped) - string onnxLayoutDimensionsDropped = onnxLayout; - foreach (var axis in droppedONNXAxis) - { - var onnxAxis = axis; - if (onnxAxis < 0) - onnxAxis = rank + axis; - string semanticToRemove = onnxLayout[onnxAxis].ToString(); - onnxLayoutDimensionsDropped = onnxLayoutDimensionsDropped.Replace(semanticToRemove, string.Empty); - } - Assert.IsTrue(onnxLayoutDimensionsDropped.Length>0); - - //Find all missing dimensions that will be unitary in Barracuda - var missingDimensions = new List(); - foreach (var dim in "NHWC") - { - if (!onnxLayoutDimensionsDropped.Contains(dim)) - missingDimensions.Add(dim); - } - - //Find semantic of onnx layout with dropped dimension in Barracuda - var barracudaSemanticLayoutFromONNXReduce = new char[4]; - switch (onnxLayoutDimensionsDropped.Length) - { - case 1: - //ONNX 1D -> N -> Barracuda N,1,1,1 - barracudaSemanticLayoutFromONNXReduce[0] = onnxLayoutDimensionsDropped[0]; - barracudaSemanticLayoutFromONNXReduce[1] = missingDimensions[0]; - barracudaSemanticLayoutFromONNXReduce[2] = missingDimensions[1]; - barracudaSemanticLayoutFromONNXReduce[3] = missingDimensions[2]; - break; - case 2: - //ONNX 2D -> NC -> Barracuda N,1,1,C - barracudaSemanticLayoutFromONNXReduce[0] = onnxLayoutDimensionsDropped[0]; - barracudaSemanticLayoutFromONNXReduce[1] = missingDimensions[0]; - barracudaSemanticLayoutFromONNXReduce[2] = missingDimensions[1]; - barracudaSemanticLayoutFromONNXReduce[3] = onnxLayoutDimensionsDropped[1]; - break; - case 3: - //3D -> NCW -> Barracuda N,1,W,C - barracudaSemanticLayoutFromONNXReduce[0] = onnxLayoutDimensionsDropped[0]; - barracudaSemanticLayoutFromONNXReduce[1] = missingDimensions[0]; - barracudaSemanticLayoutFromONNXReduce[2] = onnxLayoutDimensionsDropped[2]; - barracudaSemanticLayoutFromONNXReduce[3] = onnxLayoutDimensionsDropped[1]; - break; - } - - //Find permutation from NHWC Barracuda layout when mapped from ONNX with dropped dimensions. - var permutation = new int[4]; - for(int idTarget = 0; idTarget= 2) - axes = node.Input1Constant(onnxLayout: "ONNX", name: "axes").AsInts(); - - // Sort high to low since we are reducing rank in each iteration - // var axes = node.AxesOptional(new[] { 0 }).OrderByDescending(a => a).ToArray(); - int reducedDim = 0; - foreach (var onnxAxis in axes) - { - //TODO support 8D inputs - //var axis = ONNXLayout.ConvertAxisToBarracuda(onnxAxis, onnxRank: rank, onnxLayout: "ONNX"); - var axis = onnxAxis; - if (reducedDim != 0) - axis--; - - var nameR = $"{node.Name}__axis{onnxAxis}"; - input = net.Reduce(reduceType, nameR, input, axis, true, keepdims); - //if (axis == TensorShape.C) // This is actually W - // features = 1; // this operation collapse all features to 1 - Output(nameR, features: features, rank: rank); - - // Without keepdims, we will be reducing rank every axis iteration - if((keepdims == 0)) - { - rank--; - reducedDim++; - } - } - - net.Identity(node.Name, input); - } - - internal void Reduce(ModelBuilder net, ONNXNodeWrapper node, Layer.Type reduceType) - { - var keepdims = node.GetOptionalInt("keepdims", 1); - - var features = node.Input0Features; - var rank = node.Input0Rank; - object input = node.Input0; - - var axes = node.HasAttribute("axes") ? node.AxesOptional(new[] { 0 }) : new[] {node.AxisOptional(0)}; - foreach (var onnxAxis in axes) - { - //TODO support 8D inputs - var axis = ONNXLayout.ConvertAxisToBarracuda(onnxAxis, onnxRank: rank, onnxLayout: "NCHW"); - if (node.Input0Layout == VariableTensor.Layout.ChannelsLast && node.Input0Rank == 4) - axis = TensorExtensions.Convert4DTo8DAxis(onnxAxis); - - var nameR = $"{node.Name}__axis{axis}"; - input = net.Reduce(reduceType, nameR, input, axis, true, keepdims); - if (axis == TensorShape.C) - features = 1; // this operation collapse all features to 1 - Output(nameR, features: features, rank: rank); - } - - if (keepdims != 1 && rank > 1 && (node.Input0Layout != VariableTensor.Layout.ChannelsLast)) // keepdims removes dimensions in the context of onnx thus we need to repack/transpose to match behavior. - { - var nameT = $"{node.Name}__transpose"; - var transpose = GetPermutationToMatchReduceWithDroppedDimensionsFromONNX(axes, rank); - input = net.Transpose(nameT, input, transpose); - - rank = rank - axes.Length; - //TODO: features count is wrong and should potentially be deduced from input + transpose - Output(nameT, features: 0, rank: rank); - } - - net.Identity(node.Name, input); - //TODO: features count is wrong and should potentially be deduced from input - Output(node.Name, features: 0, rank: rank); - } - - private ONNXModelTensors m_ModelTensors = new ONNXModelTensors(); - private readonly Dictionary> m_NodeImporters = - new Dictionary>(); - - // NOTE: It's questionable whether we should be doing this since the ONNX specification requires the graph to be - // topologically sorted, but at least one network encountered that was exported from keras2onnx v1.7.0 produced - // an incorrectly sorted graph. related example: https://github.com/onnx/keras-onnx/issues/184 - void SortTopologically(ModelProto onnxModel, List sortedGraph) - { - var nodesToSort = new Queue(); - GraphProto onnxGraph = onnxModel.Graph; - foreach (NodeProto node in onnxGraph.Node) - { - nodesToSort.Enqueue(node); - } - - var requeueNodes = new Queue(); - while (nodesToSort.Count > 0) - { - NodeProto node = nodesToSort.Dequeue(); - - var allInputsExist = true; - foreach (string input in node.Input) - { - if (string.IsNullOrEmpty(input)) - continue; - - if (!sortedGraph.Exists(n => n.Output.Any(o => o == input)) - && !onnxGraph.Input.Any(i => i.Name == input) - && !onnxGraph.Initializer.Any(i => i.Name == input)) - { - allInputsExist = false; - break; - } - } - - if (!allInputsExist) - { - if (nodesToSort.Count != 0) - { - // Mark for re-processing again when (potentially) all inputs have been processed - // We use a separate list, so we don't continually spin on nodes that are missing inputs - if (!requeueNodes.Contains(node)) - requeueNodes.Enqueue(node); - continue; - } - - // Something must've gone wrong - throw new OnnxImportException($"Missing inputs to node {node.Name}, but there are no nodes to process."); - } - - if (!sortedGraph.Contains(node)) - sortedGraph.Add(node); - - // Now that we have at least processed a single new node, let's requeue - while (requeueNodes.Count > 0) - nodesToSort.Enqueue(requeueNodes.Dequeue()); - } - } - - private Model ConvertOnnxModel(ModelProto onnxModel) - { - var model = new Model(); - bool standardImport = m_ImportMode.HasFlag(ImportMode.Standard); - model.layout = standardImport ? "iNCHW" : "NHWC"; - var modelBuilder = new ModelBuilder(model); - - // Builds list of nodes that should not be included into the final Barracuda Model, mostly for LSTMs - var nodesToSkip = standardImport ? new HashSet() : BuildNodeSkipList(onnxModel.Graph); - - // Import any (optional) metadata properties - if (!m_ImportMode.HasFlag(ImportMode.SkipMetadataImport)) - { - RepeatedField metadataProps = onnxModel.MetadataProps; - Dictionary metadata = model.Metadata; - for (int p = 0; p < metadataProps.Count; p++) - { - StringStringEntryProto prop = metadataProps[p]; - metadata.Add(prop.Key, prop.Value); - } - } - - // Convert graph inputs & outputs - var initializersByName = onnxModel.Graph.Initializer.ToDictionary(i => i.Name, i => true); - foreach (ValueInfoProto i in onnxModel.Graph.Input) - { - // skip input tensors that have initializer data, they are constant tensors not global inputs - // also skip nodes that should be trimmed - if (initializersByName.ContainsKey(i.Name) || (!standardImport && nodesToSkip.Contains(i.Name))) - continue; - - if (!standardImport && m_OverrideGlobalInputs.ContainsKey(i.Name)) - { - Const(i.Name, m_OverrideGlobalInputs[i.Name]); - continue; - } - - int[] onnxShape = i.Type.TensorType.Shape.AsInts(); - modelBuilder.Input(i.Name, ONNXLayout.ConvertSymbolicShapeToBarracuda(onnxShape, onnxLayout:standardImport ? "ONNX" : "NCHW"), onnxShape.Length); - var shapeValues = i.Type.TensorType.Shape.Dim.Select(d => d.DimValue).ToArray(); - Output(i.Name, onnxShape: shapeValues, onnxLayout:"NCHW"); - } - foreach (ValueInfoProto o in onnxModel.Graph.Output) - modelBuilder.Output(o.Name); - - // Read constants from initializer list - foreach (TensorProto initializer in onnxModel.Graph.Initializer) - Const(initializer.Name, new ONNXTensor(initializer)); - - // Nodes are supposed to be sorted, but this isn't always the case - var sortedGraph = new List(); - if (standardImport) - { - SortTopologically(onnxModel, sortedGraph); - } - else - { - // for the legacy import pipeline, let's keep it as it was - sortedGraph.AddRange(onnxModel.Graph.Node); - } - - // Convert graph nodes - foreach (NodeProto onnxNode in sortedGraph) - { - if (!standardImport && nodesToSkip.Contains(ONNXNodeWrapper.GetName(onnxNode))) - continue; - - var node = new ONNXNodeWrapper(onnxNode, m_ModelTensors, model.Warnings); - var nodeId = node.Name; - var opType = node.OperatorType; - - Output(node); - - bool injectDummy = false; - if (m_NodeImporters.ContainsKey(opType)) - { - try - { - if (!standardImport && node.AreAllInputsConst && !m_ShouldNotBeBaked.Contains(opType)) - { - Profiler.BeginSample($"Bake {opType} {node.Name}"); - var bakedTensor = BakeNodeIntoConstant(opType, node); - Const(node.Name, bakedTensor); - var printTensor = bakedTensor.ToBarracuda("NCHW"); - D.Log($"Baked node {nodeId} into constant of shape {printTensor.shape} and values: {printTensor.DataToString()}"); - Profiler.EndSample(); - } - else - { - Profiler.BeginSample($"Import {opType} {node.Name}"); - m_NodeImporters[opType](modelBuilder, node); - Profiler.EndSample(); - } - } - catch (Exception e) - { - // We support the layer but something went wrong while importing it - // We log the problem and insert an identity layer - string message = $"Unexpected error while parsing layer {nodeId} of type {opType}."; - Err(model, nodeId, message, - extendedMessage:"Will replace it by an Identity layer.", - debugMessage:$"{e.Message}\n\nJson: {onnxNode}\n{e.StackTrace}\n"); - injectDummy = true; - } - } - else - { - // We don't support this type of layer - // We log the problem and insert an identity layer - string message = $"Unknown type {opType} encountered while parsing layer {nodeId}."; - Err(model, nodeId, message, extendedMessage:"Will replace it by an Identity layer."); - injectDummy = true; - } - - if (injectDummy) - { - var originalLayerHadInputs = (node.InputCount > 0); - if (originalLayerHadInputs) - { - var originalLayerHadConstantInput = node.IsInput0Const; - if (originalLayerHadConstantInput) - Const(nodeId, constantTensors[node.Input0]); // copy constant - else - modelBuilder.Identity(nodeId, node.Input0); - } - else // if errorneous layer had no inputs, inject dummy constant which does not require any inputs - modelBuilder.Const(nodeId, new Tensor()); - } - - m_ModelTensors.CompleteUninitializedFields(node); - } - - // Convert constant tensors - var requiredConstants = new HashSet(ModelAnalyzer.FindBrokenLinks(model)); - // ML-Agents metadata is stored in otherwise unreferenced constants - var unreferencedConstantsContainMLAgentsMetadata = UnreferencedNodes(onnxModel.Graph); - requiredConstants.UnionWith(unreferencedConstantsContainMLAgentsMetadata); // keep ML-Agents metadata - int insertionIndex = 0; // insert constants at the beginning of the model - foreach(var entry in constantTensors) - { - if (requiredConstants.Contains(entry.Key)) // skip if constant is unused - { - modelBuilder.Const(entry.Key, entry.Value.ToBarracuda(standardImport ? "ONNX" : - GetONNXLayoutForConstant(model, entry.Key)), - insertionIndex++, rank: entry.Value.rank); - } - } - - if (m_ImportMode == ImportMode.Legacy) - { - foreach (Layer l in model.layers) - { - if (requiredConstants.Contains(l.name)) - l.flags |= Layer.Flags.Preserve; - } - - model = ModelOptimizer.Optimize(model, allowFusing: m_OptimizeModel, keepLayers:requiredConstants); // keep ML-Agents metadata - model = FixReshapeTransposePatternWhenChannelsAreSplitIntoMultipleDimensions(model); - - if (!m_FixTf2OnnxExportIssues) - model = PatchFromIncorrectlyAssumedChannelsFirstToChannelsLastLayoutUpstream(model, layerRequiringUpstreamPatch); - } - - // strip :0 at the end of string name for TF import - if (m_FixTf2OnnxExportIssues) - model = TrimTensorflowNames(model); - - if (m_ImportMode == ImportMode.Legacy) - Validate(model); - - // Parse meta data - var irVersion = onnxModel.IrVersion; // legacy - if (onnxModel.OpsetImport?.Count > 0) - irVersion = onnxModel.OpsetImport[0].Version; - model.ProducerName = $"{onnxModel.ProducerName} v{onnxModel.ProducerVersion}"; - model.IrSource = "ONNX"; - model.IrVersion = $"{irVersion}"; - - return model; - } - - private bool IsLayerInputChannelDependant(Layer.Type opType, int index) - { - return index == 0 || //First input is usually channel order dependants - opType == Layer.Type.Add || //however some operator have all input channel dependants - opType == Layer.Type.Sub || - opType == Layer.Type.Mul || - opType == Layer.Type.Div || - opType == Layer.Type.Pow || - opType == Layer.Type.Min || - opType == Layer.Type.Max || - opType == Layer.Type.Mean || - opType == Layer.Type.Greater || - opType == Layer.Type.GreaterEqual || - opType == Layer.Type.Less || - opType == Layer.Type.LessEqual || - opType == Layer.Type.Equal || - opType == Layer.Type.LogicalOr || - opType == Layer.Type.LogicalAnd || - opType == Layer.Type.LogicalXor || - opType == Layer.Type.Where || - opType == Layer.Type.Concat; - } - - private string GetONNXLayoutForConstant(Model model, string nodeName) - { - int constLayoutRequestCount = 0; - int nctdhwRequestCount = 0; - - //find all layer using that constant as an input. - foreach (var l in model.layers) - { - for (int i = 0; i < l.inputs.Length; ++i) - { - if (l.inputs[i] == nodeName) - { - if (IsLayerInputChannelDependant(l.type, i)) - ++nctdhwRequestCount; - else - ++constLayoutRequestCount; - } - } - } - - if (nctdhwRequestCount != 0 && constLayoutRequestCount != 0) - { - Err(model, nodeName, $"{nodeName} is both used as channel order dependant constant and a plain constant, this is not supported at the moment."); - } - - return nctdhwRequestCount>constLayoutRequestCount?"NCTDHW":"CONST"; - } - - private ONNXTensor BakeNodeIntoConstant(string opType, ONNXNodeWrapper node) - { - var model = new Model(); - var net = new ModelBuilder(model); - - // add all inputs as constants - Assert.IsTrue(node.AreAllInputsConst); - for (var i = 0; i < node.InputCount; ++i) - { - var assumeOnnxLayout = (m_AllInputsChannelFirst.Contains(opType) || i == 0) ? "NCTDHW" : "CONST"; - var input = node.Inputs[i]; - net.Const(input, - constantTensors[input].ToBarracuda(assumeOnnxLayout)); - } - - // add node that we are going to bake into the constant - m_NodeImporters[opType](net, node); - - // bake - var useCPUforBaking = WorkerFactory.Device.CPU; - using (var worker = WorkerFactory.CreateWorker(model, useCPUforBaking)) - { - var bakedConstant = worker.Execute().PeekOutput(); - - // convert from Barracuda back into ONNX layout - Tensor onnxData = bakedConstant; - onnxData = ONNXTensor.Permute(bakedConstant, new int[] {0,1,2,7,3,4,5,6}); // S,R,N,T,D,H,W,C (channelLast)-> S,R,N,C,H,W (channelFirst) - var onnxShape = onnxData.shape.ToArray(); - - return new ONNXTensor(onnxData, onnxShape).SqueezeAll(); - } - } - - static private void Validate(Model model) - { - // Model should not contain any broken links in the end - var unconnectedInputs = ModelAnalyzer.FindBrokenLinks(model); - Assert.IsTrue(unconnectedInputs.Length == 0); - if (unconnectedInputs.Length > 0) - { - var message = $"Broken links: {string.Join(", ", unconnectedInputs)}"; - Warn(model, "", message); - } - } - - private HashSet UnreferencedNodes(GraphProto graph) - { - var allNodes = new HashSet(); - var allInputs = new HashSet(); - foreach (var node in graph.Node) - { - allNodes.Add(ONNXNodeWrapper.GetName(node)); - foreach (var input in node.Input) - allInputs.Add(input); - } - - // Remove all global output nodes - foreach (ValueInfoProto o in graph.Output) - allNodes.Remove(o.Name); - - // Remove all nodes that are referenced by Inputs to get the set of unreferenced ones - var unreferencedNodes = allNodes; - unreferencedNodes.ExceptWith(allInputs); - return unreferencedNodes; - } - - private void BacktraceNodeInputs(Dictionary nameToNode, - NodeProto[] startingNodes, - Action regularNodeCallback, - Action inputNodeCallback) - { - HashSet nodesToCheck = new HashSet(startingNodes); - - while (nodesToCheck.Count > 0) - { - var el = nodesToCheck.First(); - regularNodeCallback(el); - nodesToCheck.Remove(el); - - if (el.Input.Count > 0) - { - if (nameToNode.ContainsKey(el.Input[0])) - nodesToCheck.Add(nameToNode[el.Input[0]]); // regular node - else - inputNodeCallback(el); - } - } - } - - // TODO: Remove along with legacy importer in Barracuda 2.0 - private HashSet BuildNodeSkipList(GraphProto graph) - { - var res = new HashSet(); - var nameToNode = graph.Node.ToDictionary(i => ONNXNodeWrapper.GetName(i), i => i); - - var outputToLSTMNode = new Dictionary(); - - // Skip all LSTM _h & _c inputs as they will be accessible directly via Model.memories - foreach (NodeProto onnxNode in graph.Node) - { - if (onnxNode.OpType == "LSTM") - { - var lstmNodeName = ONNXNodeWrapper.GetName(onnxNode); - var initial_h = onnxNode.Input[5]; - var initial_c = onnxNode.Input[6]; - List startingNodes = new List(); - if (nameToNode.ContainsKey(initial_h)) - startingNodes.Add(nameToNode[initial_h]); - if (nameToNode.ContainsKey(initial_c)) - startingNodes.Add(nameToNode[initial_c]); - BacktraceNodeInputs( - nameToNode, - startingNodes.ToArray(), - el => { res.Add(ONNXNodeWrapper.GetName(el)); }, - el => { lstmInputs[lstmNodeName] = el.Input[0]; res.Add(el.Input[0]);} - ); - - outputToLSTMNode[onnxNode.Output[1]] = lstmNodeName; // _h - outputToLSTMNode[onnxNode.Output[2]] = lstmNodeName; // _c - } - } - - // Also trace from outputs to LSTM nodes to figure out names of the output _h and _c nodes - foreach (var output in graph.Output) - { - if (!nameToNode.ContainsKey(output.Name)) - continue; - - // As LSTM has 3 outputs and backtracing is done only via output[0] - // then output[1] and output[2] will be treated as leaf input nodes - BacktraceNodeInputs( - nameToNode, - new[] {nameToNode[output.Name]}, - el => { }, - el => - { - var inputName = el.Input[0]; - if (outputToLSTMNode.ContainsKey(inputName)) - { - lstmOutputs[outputToLSTMNode[inputName]] = output.Name; - } - } - ); - } - - return res; - } - - static private string ApplyPermutationToLayout(string layout, int[] permutation) - { - Assert.IsTrue(layout.Length == permutation.Length); - - char[] permutedLayout = new char[layout.Length]; - for (int i = 0; i < layout.Length; ++i) - { - permutedLayout[i] = layout[permutation[i]]; - } - - return new string(permutedLayout); - } - - static private int[] FindPermutationFromLayouts(string layout, string permutedLayout) - { - Assert.IsTrue(layout.Length == permutedLayout.Length); - - int[] permutation = new int[layout.Length]; - for (int i = 0; i < layout.Length; ++i) - { - permutation[i] = layout.IndexOf(permutedLayout[i]); - } - - return permutation; - } - - static private Model FixReshapeTransposePatternWhenChannelsAreSplitIntoMultipleDimensions(Model model) - { - var transposes = model.layers.Where(l => l.type == Layer.Type.Transpose).ToList(); - foreach (var transposeLayer in transposes) - { - var previousLayer = model.layers.Find(l => l.name == transposeLayer.inputs[0]); - if (previousLayer == null) - continue; - - if (previousLayer.type != Layer.Type.Reshape) - continue; - - var numChannelDimensionBeforeTranspose = previousLayer.axis; - if (numChannelDimensionBeforeTranspose <= 1) - continue; - - int centerPaddingThatWasAddedInPermutation = transposeLayer.axis; - Assert.IsTrue(centerPaddingThatWasAddedInPermutation <= 1); - Assert.IsTrue(centerPaddingThatWasAddedInPermutation >= 0); - - //NOTE: See also ConvertReshapeToBarracuda() for mode detail on the problem. - //In some network like shufflenet, superresolution_cnn and yolov3 a reshape is used - //before a transpose to split the channels resulting in a tensor with - //multiple dimension used for channels, this is a problem when importing to - //barracuda as the semantic of the dimensions are changed and this change the - //way channel first to channel last conversion should happen. The code below - //is a limited to support for that. - Assert.IsTrue(numChannelDimensionBeforeTranspose == 2 || numChannelDimensionBeforeTranspose == 3); - - var permutationSRNTDHWC = transposeLayer.pool; - if (permutationSRNTDHWC.Length != 8) - { - Warn(model, transposeLayer.name, - $"Expecting a permutation of rank 8 after Reshape '{previousLayer.name}' itself outputting more than one channel dimension. Permutation can't be patched to account for the extra channel dimensions."); - continue; - } - - //Find layouts before transpose in both channel order - string layoutBeforeTranspose_ChannelFirst = (numChannelDimensionBeforeTranspose == 3) ? "SRN123HW" : "SRN1T2HW"; - string layoutBeforeTranspose_ChannelLast = (numChannelDimensionBeforeTranspose == 3) ? "SRNHW123" : "SRNTHW12"; - - //Find layout after transpose in channel first - int[] permutation_ChannelFirst = ONNXLayout.ConvertPermutationToLayout(permutationSRNTDHWC, "SRNTDHWC","SRNCTDHW"); - string layoutAfterTranspose_ChannelFirst = ApplyPermutationToLayout(layoutBeforeTranspose_ChannelFirst, permutation_ChannelFirst); - - //Find layout after transpose in channel last - //TODO/HEURISTIC: We differentiate the various case by knowing if channels and features are interleaved during permutations. - //This is a work around to create the right permutation for the shufflenet/super-resolution and yolov3, it does not generalise well however. - //In next version of the importer we might need to introduce transposes in channel last mode to generalise fully. - int[] channelFirstToLastPermutation = null; - if (numChannelDimensionBeforeTranspose == 3) - { - //super resolution -> final reshape will pick only 1 dimension as channel -> regular channel first to last transposition. - channelFirstToLastPermutation = FindPermutationFromLayouts("SRN1TDHW", "SRNTDHW1"); - } - else if (IsPermutationMixingChannelsAndOtherFeatures(layoutBeforeTranspose_ChannelFirst, permutation_ChannelFirst)) - { - //yolov3 -> final reshape does not pick any dimension as channel -> no transposition. - channelFirstToLastPermutation = FindPermutationFromLayouts("SRNTUDHW", "SRNTUDHW"); - } - else - { - //shufflenet -> final reshape take 2 dimension and merge them so both need to be affected by channel first to last transposition - channelFirstToLastPermutation = FindPermutationFromLayouts("SRN1T2HW", "SRNTHW12"); - } - string layoutAfterTranspose_ChannelLast = ApplyPermutationToLayout(layoutAfterTranspose_ChannelFirst, channelFirstToLastPermutation); - - //Finally compute and return permutation in channel last - int[] permutation_ChannelLast = FindPermutationFromLayouts(layoutBeforeTranspose_ChannelLast, layoutAfterTranspose_ChannelLast); - transposeLayer.pool = permutation_ChannelLast; - } - - return model; - } - - static private bool IsPermutationMixingChannelsAndOtherFeatures(string layout, int[] permutation) - { - //Convention here is that channels are described as numbers, while other features by letters. - Assert.IsTrue(layout.Length == permutation.Length); - for (int i = 0; i < permutation.Length; ++i) - { - bool sourceIsAChannel = Char.IsNumber(layout[i]); - bool targetIsAChannel = Char.IsNumber(layout[permutation[i]]); - if (sourceIsAChannel != targetIsAChannel) - return true; - } - return false; - } - - static private Model TrimTensorflowNames(Model model) - { - model.inputs = model.inputs.Select(i => { - i.name = TrimTensorflowName(i.name); - return i; - }).ToList(); - - model.outputs = model.outputs.Select(o => { - return TrimTensorflowName(o); - }).ToList(); - - model.memories = model.memories.Select(m => { - m.input = TrimTensorflowName(m.input); - m.output = TrimTensorflowName(m.output); - return m; - }).ToList(); - - model.layers = model.layers.Select(l => { - l.name = TrimTensorflowName(l.name); - for(int i = 0; i < l.datasets.Length; i++) - l.datasets[i].name = TrimTensorflowName(l.datasets[i].name); - for(int i = 0; i < l.inputs.Length; i++) - l.inputs[i] = TrimTensorflowName(l.inputs[i]); - if (l.outputs != null) - { - for (int i = 0; i < l.outputs.Length; i++) - l.outputs[i] = TrimTensorflowName(l.outputs[i]); - } - return l; - }).ToList(); - - return model; - } - - static private string TrimTensorflowName(string name) - { - if (name.EndsWith(":0")) - return name.Remove(name.Length-2); - return name; - } - - // Helpers to keep track of model tensors - private void Const(ONNXNodeWrapper node, ONNXTensor onnxTensor) - { - m_ModelTensors.AddConstant(node.Name, onnxTensor); - } - private void Const(string name, ONNXTensor onnxTensor) - { - m_ModelTensors.AddConstant(name, onnxTensor); - } - - private void Output(ONNXNodeWrapper node, int features = -1, int rank = -1, - VariableTensor.Layout layout = VariableTensor.Layout.Unknown) - { - Output(node.Name, features, rank, layout); - } - private void Output(string name, int features = -1, int rank = -1, - VariableTensor.Layout layout = VariableTensor.Layout.Unknown) - { - m_ModelTensors.AddVariable(name, features, rank, layout); - } - private void Output(string name, ONNXTensor onnxTensor) - { - m_ModelTensors.AddVariable(name, onnxTensor); - } - private void Output(string name, long[] onnxShape, string onnxLayout) - { - m_ModelTensors.AddVariable(name, onnxShape, onnxLayout); - } - - private void Output(ONNXNodeWrapper node, int features, string productOfShape) - { - m_ModelTensors.AddVariable(node.Name, features, productOfShape); - } - - // Logging helpers - private static void Warn(ModelBuilder builder, ONNXNodeWrapper node, string message) - { - Warn(builder.model, node.Name, message); - } - - private static void Warn(Model model, string layerName, string message) - { - model.Warnings.Add(new Model.ImporterWarning(layerName,message)); - Debug.LogWarning(message); - } - - private void Err(Model model, string layerName, string message, string extendedMessage = "", string debugMessage = "") - { - if (m_TreatErrorsAsWarnings) - { - model.Warnings.Add(new Model.ImporterWarning(layerName,$"{message} {extendedMessage}")); - Debug.LogWarning($"{message} {extendedMessage}\n{debugMessage}"); - } - else - throw new OnnxImportException($"{message}\n{debugMessage}"); - } - } - - /// - /// ONNX import exception - /// - public class OnnxImportException : Exception - { - /// - /// Create `OnnxImportException` - /// - /// message - public OnnxImportException(string message) : base(message) { } - } - - /// - /// ONNX layer import exception - /// - public class OnnxLayerImportException : Exception - { - /// - /// Create `OnnxLayerImportException` - /// - /// message - public OnnxLayerImportException(string message) : base(message) { } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXModelConverter.cs.meta b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXModelConverter.cs.meta deleted file mode 100644 index 00c60fe..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXModelConverter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b00b71dd0fb8e4f49b71a2e5feaf517a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXNodeWrapper.cs b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXNodeWrapper.cs deleted file mode 100644 index 1bb197c..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXNodeWrapper.cs +++ /dev/null @@ -1,609 +0,0 @@ -using Onnx; -using UnityEngine; -using UnityEditor; -using System; -using System.Linq; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using UnityEngine.Assertions; - -[assembly: InternalsVisibleToAttribute("Barracuda.EditorTests")] - -namespace Unity.Barracuda.ONNX -{ - internal class ONNXNodeWrapper - { - // Layer identification (name and op) - public static string GetName(NodeProto node) - { - // prefer node.output over the node.name - return node.Output.Count > 0 ? node.Output[0] : node.Name; - } - public string Name { get { return GetName(m_ONNXNode); } } - public string OperatorType { get { return m_ONNXNode.OpType; } } - public bool IsConstant { get { return OperatorType == "Constant"; } } - public bool IsTerminatorForProductOfShape { get { return OperatorType == "Reshape"; } } - - // Outputs - public string[] Outputs { get { return m_ONNXNode.Output.ToArray(); }} - - // Inputs - public int InputCount { get { return m_ONNXNode.Input.Count; } } - public string[] Inputs { get { return m_ONNXNode.Input.ToArray(); } } - public string Input0 { get { return GetRequiredInput(0); } } - public string Input1 { get { return GetRequiredInput(1); } } - public string Input2 { get { return GetRequiredInput(2); } } - public string Input3 { get { return GetRequiredInput(3); } } - public string Input4 { get { return GetRequiredInput(4); } } - public string Input5 { get { return GetRequiredInput(5); } } - public string Input6 { get { return GetRequiredInput(6); } } - public string Input0Optional { get { return InputCount > 0 ? GetRequiredInput(0) : ""; } } - public string Input1Optional { get { return InputCount > 1 ? GetRequiredInput(1) : ""; } } - public string Input2Optional { get { return InputCount > 2 ? GetRequiredInput(2) : ""; } } - public string Input3Optional { get { return InputCount > 3 ? GetRequiredInput(3) : ""; } } - public string Input4Optional { get { return InputCount > 4 ? GetRequiredInput(4) : ""; } } - public string Input5Optional { get { return InputCount > 5 ? GetRequiredInput(5) : ""; } } - public string Input6Optional { get { return InputCount > 6 ? GetRequiredInput(6) : ""; } } - public bool IsInput0Const { get { return IsInputConst(0); } } - public bool IsInput1Const { get { return IsInputConst(1); } } - public bool IsInput2Const { get { return IsInputConst(2); } } - public bool IsInput3Const { get { return IsInputConst(3); } } - public bool IsInput4Const { get { return IsInputConst(4); } } - public bool IsInput5Const { get { return IsInputConst(5); } } - public bool IsInput6Const { get { return IsInputConst(6); } } - public bool AreAllInputsConst { get { - for (var i = 0; i < InputCount; ++i) - if (!IsInputConst(i)) - return false; - return true; - } } - - public int Input0Features { get { return m_ONNXModelTensors.variables[Input0].features; } } - public int Input1Features { get { return m_ONNXModelTensors.variables[Input1].features; } } - public int Input2Features { get { return m_ONNXModelTensors.variables[Input2].features; } } - public int Input3Features { get { return m_ONNXModelTensors.variables[Input3].features; } } - public int Input4Features { get { return m_ONNXModelTensors.variables[Input4].features; } } - public int Input5Features { get { return m_ONNXModelTensors.variables[Input5].features; } } - public int Input6Features { get { return m_ONNXModelTensors.variables[Input6].features; } } - public int Input0Rank { get { return m_ONNXModelTensors.variables[Input0].rank; } } - public int Input1Rank { get { return m_ONNXModelTensors.variables[Input1].rank; } } - public VariableTensor.Layout Input0Layout { get { return m_ONNXModelTensors.variables[Input0].layout; } } - public Tensor Input0Constant(string onnxLayout, string name = "X") { return GetRequiredInputAsConstant(Input0, onnxLayout, name); } - public int[] Input0ConstantONNXShape(string name) { return GetRequiredInputConstantONNXShape(Input0, name); } - public Tensor Input1Constant(string onnxLayout, string name) { return GetRequiredInputAsConstant(Input1, onnxLayout, name); } - public Tensor Input2Constant(string onnxLayout, string name) { return GetRequiredInputAsConstant(Input2, onnxLayout, name); } - public Tensor Input3Constant(string onnxLayout, string name) { return GetRequiredInputAsConstant(Input3, onnxLayout, name); } - public Tensor Input4Constant(string onnxLayout, string name) { return GetRequiredInputAsConstant(Input4, onnxLayout, name); } - public Tensor Input5Constant(string onnxLayout, string name) { return GetRequiredInputAsConstant(Input5, onnxLayout, name); } - public Tensor Input6Constant(string onnxLayout, string name) { return GetRequiredInputAsConstant(Input6, onnxLayout, name); } - public Tensor Input1ConstantOptional(Tensor defaultValue, string onnxLayout, string name) { try { return GetRequiredInputAsConstant(Input1, onnxLayout, name); } catch (Exception) { return defaultValue; } } - public Tensor Input2ConstantOptional(Tensor defaultValue, string onnxLayout, string name) { try { return GetRequiredInputAsConstant(Input2, onnxLayout, name); } catch (Exception) { return defaultValue; } } - public Tensor Input3ConstantOptional(Tensor defaultValue, string onnxLayout, string name) { try { return GetRequiredInputAsConstant(Input3, onnxLayout, name); } catch (Exception) { return defaultValue; } } - public Tensor Input4ConstantOptional(Tensor defaultValue, string onnxLayout, string name) { try { return GetRequiredInputAsConstant(Input4, onnxLayout, name); } catch (Exception) { return defaultValue; } } - public Tensor Input1ConstantOptional(TensorShape shape, float defaultValue, string onnxLayout, string name) { try { return GetRequiredInputAsConstant(Input1, onnxLayout, name); } catch (Exception) { return DefaultTensor(shape, defaultValue); } } - public Tensor Input2ConstantOptional(TensorShape shape, float defaultValue, string onnxLayout, string name) { try { return GetRequiredInputAsConstant(Input2, onnxLayout, name); } catch (Exception) { return DefaultTensor(shape, defaultValue); } } - public Tensor Input3ConstantOptional(TensorShape shape, float defaultValue, string onnxLayout, string name) { try { return GetRequiredInputAsConstant(Input3, onnxLayout, name); } catch (Exception) { return DefaultTensor(shape, defaultValue); } } - public Tensor Input4ConstantOptional(TensorShape shape, float defaultValue, string onnxLayout, string name) { try { return GetRequiredInputAsConstant(Input4, onnxLayout, name); } catch (Exception) { return DefaultTensor(shape, defaultValue); } } - public Tensor Input1ConstantOptional(float defaultValue, string onnxLayout, string name) { return Input1ConstantOptional(new TensorShape(1, 1), defaultValue, onnxLayout, name); } - public Tensor Input2ConstantOptional(float defaultValue, string onnxLayout, string name) { return Input2ConstantOptional(new TensorShape(1, 1), defaultValue, onnxLayout, name); } - public Tensor Input3ConstantOptional(float defaultValue, string onnxLayout, string name) { return Input3ConstantOptional(new TensorShape(1, 1), defaultValue, onnxLayout, name); } - public Tensor Input4ConstantOptional(float defaultValue, string onnxLayout, string name) { return Input4ConstantOptional(new TensorShape(1, 1), defaultValue, onnxLayout, name); } - - // Attributes - public float Alpha { get { return GetRequiredFloat("alpha"); } } - public float Beta { get { return GetRequiredFloat("beta"); } } - public float Gamma { get { return GetRequiredFloat("gamma"); } } - public float Epsilon { get { return GetRequiredFloat("epsilon"); } } - public float Mean { get { return GetRequiredFloat("mean"); } } - public float Scale { get { return GetRequiredFloat("scale"); } } - public float Seed { get { return GetOptionalFloat("seed", 1337f); } } // seed is always optional and defaults to 'auto generated' - public ONNXTensor ValueAsTensor { get { return GetRequiredTensor("value"); } } - public int Axis { get { return GetRequiredInt("axis"); } } - public int BlockSize { get { return GetRequiredInt("blocksize"); } } - public int Group { get { return GetRequiredInt("group"); } } - public int[] Shape { get { return GetRequiredIntArray("shape"); } } - public int[] Starts { get { return GetRequiredIntArray("starts"); } } - public int[] Ends { get { return GetRequiredIntArray("ends"); } } - public int[] Axes { get { return GetRequiredIntArray("axes"); } } - public float[] Bias { get { return GetRequiredFloatArray("bias"); } } - public int[] KernelShape { get { return GetRequiredIntArray("kernel_shape"); } } - public int[] Strides { get { return GetOptionalIntArray("strides", new[] {1,1}); } } - public int[] Strides3D { get { return GetOptionalIntArray("strides", new[] {1,1,1}); } } - public int[] OutputPadding { get { return GetOptionalIntArray("output_padding", new[] {0,0}); } } - internal bool SupportsAutoPad { get { return OperatorType != "Pad"; } } - internal bool SupportsSpatialOnlyPads { get { return OperatorType != "Pad"; } } - public int[] Pads { get { return ConvertPadsToBarracuda(); } } - public int[] Pads3D { get { return ConvertPadsToBarracuda(new int[] {0,0,0,0,0,0}); } } - public float[] Scales { get { return ConvertScalesToBarracuda(); } } - public int[] Sizes { get { return ConvertSizesToBarracuda(); } } - public float AlphaOptional(float defaultValue) { return GetOptionalFloat("alpha", defaultValue); } - public float BetaOptional(float defaultValue) { return GetOptionalFloat("beta", defaultValue); } - public float GammaOptional(float defaultValue) { return GetOptionalFloat("gamma", defaultValue); } - public float EpsilonOptional(float defaultValue=1e-5f) { return GetOptionalFloat("epsilon", defaultValue); } - public float MeanOptional(float defaultValue=0f) { return GetOptionalFloat("mean", defaultValue); } - public float ScaleOptional(float defaultValue=1f) { return GetOptionalFloat("scale", defaultValue); } - public bool TransAOptional(bool defaultValue=false) { return GetOptionalInt("transA", defaultValue?1:0) != 0;} - public bool TransBOptional(bool defaultValue=false) { return GetOptionalInt("transB", defaultValue?1:0) != 0;} - public int AxisOptional(int defaultValue) { return GetOptionalInt("axis", defaultValue); } - public int GroupOptional(int defaultValue=1) { return GetOptionalInt("group", defaultValue); } - public int[] KernelShapeOptional(int[] defaultValue) { return GetOptionalIntArray("kernel_shape", defaultValue); } - public int[] AxesOptional(int[] defaultValue) { return GetOptionalIntArray("axes", defaultValue); } - public float MinOptional(float defaultValue) { return GetOptionalFloat("min", defaultValue); } - public float MaxOptional(float defaultValue) { return GetOptionalFloat("max", defaultValue); } - public string ModeOptional(string defaultValue) { return GetOptionalString("mode", defaultValue); } - public int[] DilatationsOptional(int[] defaultValue) { return GetOptionalIntArray("dilations", defaultValue); } - - // --------------------------------------------------------------------------------- - // Implementation - private NodeProto m_ONNXNode; - private ONNXModelTensors m_ONNXModelTensors; - private List m_ImporterWarnings; - - public ONNXNodeWrapper(NodeProto ONNXNode, ONNXModelTensors ONNXModelTensors, - List importerWarnings) - { - m_ONNXNode = ONNXNode; - m_ONNXModelTensors = ONNXModelTensors; - m_ImporterWarnings = importerWarnings; - } - - // Logging helpers - public void Warn(string message) - { - m_ImporterWarnings.Add(new Model.ImporterWarning(Name, message)); - Debug.LogWarning(message); - } - - public bool HasAttribute(string name) - { - AttributeProto attr; - return TryFindAttribute(name, out attr); - } - - public void UnsupportedAttribute(string name) - { - AttributeProto attr; - if (TryFindAttribute(name, out attr)) - Warn($"Unsupported attribute {name}, node {Name} of type {OperatorType}. Value will be ignored."); - } - public void UnsupportedAttribute(string name, int defaultValue) - { - if (GetOptionalInt(name, defaultValue) != defaultValue) - Warn($"Unsupported attribute {name}, node {Name} of type {OperatorType}. Value will be ignored and defaulted to {defaultValue}."); - } - public void UnsupportedAttribute(string name, float defaultValue) - { - if (GetOptionalFloat(name, defaultValue) != defaultValue) - Warn($"Unsupported attribute {name}, node {Name} of type {OperatorType}. Value will be ignored and defaulted to {defaultValue}."); - } - public void UnsupportedAttribute(string name, string defaultValue) - { - if (GetOptionalString(name, defaultValue) != defaultValue) - Warn($"Unsupported attribute {name}, node {Name} of type {OperatorType}. Value will be ignored and defaulted to {defaultValue}."); - } - public void UnsupportedAttribute(string name, int[] defaultValue) - { - var valueArray = GetOptionalIntArray(name, defaultValue); - if (!Enumerable.SequenceEqual(valueArray, defaultValue)) - Warn($"Unsupported attribute {name}, node {Name} of type {OperatorType}. Value will be ignored and defaulted to [{string.Join(", ", defaultValue)}]."); - } - public void UnsupportedAttribute(string name, string[] defaultValue) - { - var stringArray = GetOptionalStringArray(name, defaultValue); - if (!Enumerable.SequenceEqual(stringArray, defaultValue)) - Warn($"Unsupported attribute {name}, node {Name} of type {OperatorType}. Value will be ignored and defaulted to [{string.Join(", ", defaultValue)}]."); - } - public void UnsupportedAttribute(string name, Func predicate, int[] defaultValue) - { - var valueArray = GetOptionalIntArray(name, defaultValue); - if (!Enumerable.All(valueArray, predicate)) - Warn($"Unsupported attribute {name}, node {Name} of type {OperatorType}. Value will be ignored and defaulted to [{string.Join(", ", defaultValue)}]."); - } - public void IgnoredAttribute(string name, string reasonToIgnore) - { - } - - // Input helpers - internal string GetRequiredInput(int inputIndex) - { - if ((inputIndex >= m_ONNXNode.Input.Count) || (m_ONNXNode.Input[inputIndex] == "")) - throw new OnnxLayerImportException($"required Input {inputIndex} was not found."); - - return m_ONNXNode.Input[inputIndex]; - } - internal bool IsInput1Array(string name) - { - if (Input1 == "") - throw new OnnxLayerImportException("Input value is marked as required, but it is missing in the model."); - - ONNXTensor onnxTensor; - if (!m_ONNXModelTensors.constants.TryGetValue(Input1, out onnxTensor)) - throw new OnnxLayerImportException( - $"Currently only constant tensors are supported for `{name}` input in node of type {OperatorType}. Instead {Name}.{name} is pointing to non constant node {Input1}."); - - return onnxTensor.rank != 0; - } - internal Tensor GetRequiredInputAsConstant(string input, string onnxLayout, string onnxName) - { - if (input == "") - throw new OnnxLayerImportException("Input value is marked as required, but it is missing in the model."); - - ONNXTensor onnxTensor; - if (!m_ONNXModelTensors.constants.TryGetValue(input, out onnxTensor)) - throw new OnnxLayerImportException( - $"Currently only constant tensors are supported for `{onnxName}` input in node of type {OperatorType}. Instead {Name}.{onnxName} is pointing to non constant node {input}."); - - return onnxTensor.ToBarracuda(onnxLayout); - } - internal int[] GetRequiredInputConstantONNXShape(string input, string onnxName) - { - if (input == "") - throw new OnnxLayerImportException("Input value is marked as required, but it is missing in the model."); - - ONNXTensor onnxTensor; - if (!m_ONNXModelTensors.constants.TryGetValue(input, out onnxTensor)) - throw new OnnxLayerImportException( - $"Currently only constant tensors are supported for `{onnxName}` input in node of type {OperatorType}. Instead {Name}.{onnxName} is pointing to non constant node {input}."); - - return onnxTensor.shape; - } - - internal bool IsInputConst(int inputIndex) - { - var input = GetRequiredInput(inputIndex); - return m_ONNXModelTensors.constants.ContainsKey(input); - } - - // Attribute helpers - internal bool TryFindAttribute(string name, out AttributeProto attr) - { - return TryFindAttribute(name, AttributeProto.Types.AttributeType.Undefined, out attr); - } - internal bool TryFindAttribute(string name, AttributeProto.Types.AttributeType type, out AttributeProto attr) - { - const AttributeProto.Types.AttributeType undefined = AttributeProto.Types.AttributeType.Undefined; - var attributes = m_ONNXNode.Attribute; - for (var i = 0; i < attributes.Count; ++i) - { - attr = attributes[i]; - if (attr.Name == name && (attr.Type == type || attr.Type == undefined || type == undefined)) - return true; - } - attr = null; - return false; - } - internal AttributeProto FindAttribute(string name, AttributeProto.Types.AttributeType type = AttributeProto.Types.AttributeType.Undefined) - { - AttributeProto attr = null; - if (TryFindAttribute(name, type, out attr)) - return attr; - - throw new OnnxLayerImportException($"Couldn't find attribute {name} of type {type}"); - } - public float GetOptionalFloat(string name, float defaultValue) - { - try { return GetRequiredFloat(name); } - catch (OnnxLayerImportException) { return defaultValue; } - } - public float GetRequiredFloat(string name) - { - return FindAttribute(name, AttributeProto.Types.AttributeType.Float).F; - } - public float[] GetOptionalFloatArray(string name, float[] defaultValue) - { - try { return GetRequiredFloatArray(name); } - catch (OnnxLayerImportException) { return defaultValue; } - } - public float[] GetRequiredFloatArray(string name) - { - var attribute = FindAttribute(name,AttributeProto.Types.AttributeType.Floats); - return attribute.Floats.ToArray(); - } - public ONNXTensor GetOptionalTensor(string name, ONNXTensor defaultValue) - { - try { return GetRequiredTensor(name); } - catch (OnnxLayerImportException) { return defaultValue; } - } - public ONNXTensor GetRequiredTensor(string name) - { - var tensorProto = FindAttribute(name, AttributeProto.Types.AttributeType.Tensor).T; - return new ONNXTensor(tensorProto); - } - public int GetOptionalInt(string name, int defaultValue) - { - try { return GetRequiredInt(name); } - catch (OnnxLayerImportException) { return defaultValue; } - } - public int GetRequiredInt(string name) - { - long v = FindAttribute(name, AttributeProto.Types.AttributeType.Int).I; - return v < int.MinValue ? int.MinValue : v > int.MaxValue ? int.MaxValue : (int)v; - } - public int[] GetOptionalIntArray(string name, int[] defaultValue) - { - try { return GetRequiredIntArray(name); } - catch (OnnxLayerImportException) { return defaultValue; } - } - public int[] GetRequiredIntArray(string name) - { - var attribute = FindAttribute(name,AttributeProto.Types.AttributeType.Ints); - return attribute.Ints.Select(v => v < int.MinValue ? int.MinValue : v > int.MaxValue ? int.MaxValue : (int)v).ToArray(); - } - public string GetOptionalString(string name, string defaultValue) - { - try { return GetRequiredString(name); } - catch (OnnxLayerImportException) { return defaultValue; } - } - public string GetRequiredString(string name) - { - var raw = FindAttribute(name, AttributeProto.Types.AttributeType.String).S; - return raw.ToStringUtf8(); - } - public string[] GetOptionalStringArray(string name, string[] defaultValue) - { - try { return GetRequiredStringArray(name); } - catch (OnnxLayerImportException) { return defaultValue; } - } - public string[] GetRequiredStringArray(string name) - { - var attribute = FindAttribute(name,AttributeProto.Types.AttributeType.Strings); - return attribute.Strings.Select(s => s.ToStringUtf8()).ToArray(); - } - - public Layer.AutoPad AutoPadMode() - { - var autoPad = GetOptionalString("auto_pad", "NOTSET"); - Layer.AutoPad autoPadType = Layer.AutoPad.NotSet; - if (autoPad == "VALID") - autoPadType = Layer.AutoPad.Valid; - else if (autoPad == "SAME_UPPER") - autoPadType = Layer.AutoPad.SameUpper; - else if (autoPad == "SAME_LOWER") - autoPadType = Layer.AutoPad.SameLower; - - return autoPadType; - } - - public Layer.PadMode PadMode() - { - var mode = ModeOptional("constant"); - var modeType = Layer.PadMode.Constant; - switch (mode) - { - case "constant": - modeType = Layer.PadMode.Constant; - break; - case "reflect": - modeType = Layer.PadMode.Reflect; - break; - case "edge": - modeType = Layer.PadMode.Edge; - break; - } - return modeType; - } - - // Complex attribute helpers - private int[] ConvertPadsToBarracuda(int[] defaultValues = null) - { - var noPadding = defaultValues??new[] {0,0,0,0}; - if (SupportsAutoPad) - { - // known_paddings = { - // 'VALID' : [0,0,0,0], - // 'SAME_UPPER' : [-1], - // 'SAME_LOWER' : [-2], - // } - var autoPad = GetOptionalString("auto_pad", "NOTSET"); - if (autoPad == "VALID") - return noPadding; - else if (autoPad == "SAME_UPPER") - return new[] { -1 }; - else if (autoPad == "SAME_LOWER") - return new[] { -2 }; - else {} // TODO: Assert NOTSET - } - - var pads = GetOptionalIntArray("pads", noPadding); - if (pads.Length % 2 != 0) - throw new OnnxLayerImportException( - $"Attribute pads of unsupported length {pads.Length} in {Name} ot fype {OperatorType}."); - - var starts = pads.Take(pads.Length / 2).ToArray(); - var ends = pads.Skip(pads.Length / 2).ToArray(); - - if (SupportsSpatialOnlyPads) - { - // See: https://github.com/onnx/onnx/blob/master/docs/Operators.md#AveragePool - // Padding for the beginning and ending along each spatial axis, it can take any value greater than or equal to 0. - // The value represent the number of pixels added to the beginning and end part of the corresponding axis. - } - else - { - // Padding containts non-spatial dimensions including N and C - - // See: https://github.com/onnx/onnx/blob/master/docs/Operators.md#Pad - // `pads` should be a 1D tensor of shape [2 * input_rank]. - - Assert.IsTrue(starts.Length == ends.Length); - - bool[] dimHavePadding = new bool[starts.Length]; - for (int i = 0; i < starts.Length; ++i) { - dimHavePadding[i] = starts[i] != 0 && ends[i] != 0; - } - - if (dimHavePadding.SequenceEqual(new bool []{ false, true, true, false })) - { - // Look like this padding operator is defined over NHWC layout - // We skip first and last dimension thus - starts = starts.Skip(1).Take(2).ToArray(); - ends = ends.Skip(1).Take(2).ToArray(); - } - else - { - if ((starts.Length < 2) || - (starts[0] != 0) || (starts[1] != 0) || // N - (ends[0] != 0) || (ends[1] != 0)) // C - Warn("Only spatial (H and W) padding is currently supported." + - " Non spatial padding (N and C) will be ignored and default to 0."); - // Skip non-spatial dimensions N, C (NCHW layout) - starts = starts.Skip(2).ToArray(); - ends = ends.Skip(2).ToArray(); - } - } - - // See: https://github.com/onnx/onnx/blob/master/docs/Operators.md#Pad - // ONNX `pads` format should be as follow [x1_begin, x2_begin...x1_end, x2_end,...], - // where xi_begin the number of pixels added at the beginning of axis `i` and xi_end, - // the number of pixels added at the end of axis `i`. - - // Convert ONNX pad layout of [z, y, x ..., z', y', x'] to Barracuda layout [x, y, z ..., x', y', z'] - // where x is x1_begin, y is x2_begin ... - // x' is x1_end, y' is x2_end ... - - Assert.IsTrue(starts.Length == ends.Length); - switch (starts.Length) - { - case 0: return new [] { 0, 0, 0, 0 }; - case 1: return new [] { starts[0], 0, - ends[0], 0 }; // 1D W => W_ - case 2: return new [] { starts[1], starts[0], - ends[1], ends[0] }; // 2D HW => WH - case 3: return new [] { starts[2], starts[1], starts[0], - ends[2], ends[1], ends[0] };// 3D DHW => WHD - default: - throw new OnnxLayerImportException( - $"Attribute pads of unsupported length {pads.Length} in {Name} ot type {OperatorType}."); - } - } - internal float[] ConvertScales() - { - float[] scales; - if (InputCount > 2) // Resize-11 - { - Assert.IsTrue(OperatorType == "Resize"); - scales = Input2Constant(onnxLayout: "C", name: "scales").AsFloats(); - } - else if (InputCount > 1) // Resize-10, Upsample-9 - { - scales = Input1Constant(onnxLayout: "C", name: "scales").AsFloats(); - } - else - { - Assert.IsTrue(OperatorType == "Upsample"); - scales = GetOptionalFloatArray("scales", new float[0]); // Upsample-7 - if (scales?.Length == 0) // Upsample-1 - { - scales = new[] { 1, // N - 1, // C - GetRequiredFloat("height_scale"), - GetRequiredFloat("width_scale") }; - } - } - Assert.IsTrue(scales != null); - - return scales; - } - internal int[] ConvertSizes() - { - int[] sizes = null; - Assert.IsTrue(OperatorType == "Resize"); - Assert.IsTrue(InputCount == 4); - - if (IsInput3Const) - { - sizes = Input3Constant(onnxLayout: "C", name: "sizes").AsInts(); - Assert.IsTrue(sizes != null); - Assert.IsTrue(sizes.Length == 4); - - if ((sizes[0] != 1) || (sizes[1] != 1)) - Warn("Only spatial (H and W) resizing is currently supported." + - " Non spatial sizes (N and C) will be ignored and default to identity."); - } - else - throw new OnnxLayerImportException( - $"Only constant size values are currently supported in {Name} ot type {OperatorType}."); - - return sizes; - } - - private float[] ConvertScalesToBarracuda() - { - float[] scales; - if (InputCount > 2) // Resize-11 - { - Assert.IsTrue(OperatorType == "Resize"); - scales = Input2Constant(onnxLayout:"C", name:"scales").AsFloats(); - } - else if (InputCount > 1) // Resize-10, Upsample-9 - { - scales = Input1Constant(onnxLayout:"C", name:"scales").AsFloats(); - } - else - { - Assert.IsTrue(OperatorType == "Upsample"); - scales = GetOptionalFloatArray("scales", new float[0]); // Upsample-7 - if (scales?.Length == 0) // Upsample-1 - { - scales = new[] { 1, // N - 1, // C - GetRequiredFloat("height_scale"), - GetRequiredFloat("width_scale") }; - } - } - Assert.IsTrue(scales != null); - - if ((scales.Length < 2) || - (scales[0] != 1) || (scales[1] != 1)) - Warn("Only spatial (H and W) padding is currently supported." + - " Non spatial scales (N and C) will be ignored and default to 1."); - - // Skip non-spatial dimensions N, C (NCHW layout) - scales = scales.Skip(2).ToArray(); - - switch (scales.Length) - { - case 0: return new [] { 1f, 1f }; - case 1: return new [] { scales[0], 1 }; // 1D W => W_ - case 2: return new [] { scales[1], scales[0] }; // 2D HW => WH - case 3: return new [] { scales[2], scales[1], scales[0] }; // 3D DHW => WHD - default: - throw new OnnxLayerImportException( - $"Attribute pads of unsupported length {scales.Length} in {Name} ot type {OperatorType}."); - } - } - - private int[] ConvertSizesToBarracuda() - { - int[] sizes = null; - Assert.IsTrue(OperatorType == "Resize"); - Assert.IsTrue(InputCount == 4); - - if (IsInput3Const) - { - sizes = Input3Constant(onnxLayout: "C", name: "sizes").AsInts(); - Assert.IsTrue(sizes != null); - Assert.IsTrue(sizes.Length == 4); - - if ((sizes[0] != 1) || (sizes[1] != 1)) - Warn("Only spatial (H and W) resizing is currently supported." + - " Non spatial sizes (N and C) will be ignored and default to identity."); - - // Skip non-spatial dimensions N, C, return WH (NCHW layout) - sizes = sizes.Skip(2).Reverse().ToArray(); - } - else - throw new OnnxLayerImportException( - $"Only constant size values are currently supported in {Name} ot type {OperatorType}."); - - return sizes; - } - - public Tensor DefaultTensor(TensorShape tensorShape, float defaultValue) - { - var shape = tensorShape; - var data = Enumerable.Repeat(defaultValue, tensorShape.length).ToArray(); - return new Tensor(shape, data); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXNodeWrapper.cs.meta b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXNodeWrapper.cs.meta deleted file mode 100644 index 021b8b6..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXNodeWrapper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4f5db8a9388b64e8297f3495039b6332 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXTensor.cs b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXTensor.cs deleted file mode 100644 index 1d770d4..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXTensor.cs +++ /dev/null @@ -1,579 +0,0 @@ -using Onnx; -using UnityEngine; -using UnityEngine.Profiling; -using System; -using System.Linq; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using UnityEngine.Android; -using UnityEngine.Assertions; - -[assembly: InternalsVisibleToAttribute("Barracuda.EditorTests")] - -namespace Unity.Barracuda.ONNX -{ - // Combines information about ONNX tensor and data read from TensorProto - internal struct ONNXTensor - { - public int[] shape => m_Shape; - public int rank => shape.Length; - public Tensor data => m_Data; - - Tensor m_Data; - int[] m_Shape; - - public ONNXTensor(TensorProto onnxTensor) - { - // read shape - var onnxShape = onnxTensor.Dims.Select(v => v < int.MinValue ? int.MinValue : v > int.MaxValue ? int.MaxValue : (int)v).ToArray(); - - if (onnxShape.Any(s => s == 0)) - { - // empty tensor, not data - m_Shape = onnxShape; - m_Data = null; - } - else - { - // read data - var shape = ONNXLayout.ConvertShapeToBarracuda(onnxShape, onnxLayout:"?"); - float[] data; - if ((onnxTensor.RawData != null) && (!onnxTensor.RawData.IsEmpty)) - { - var byteArray = new byte[onnxTensor.RawData.Length]; - onnxTensor.RawData.CopyTo(byteArray, 0); - - // Double - if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Double) - { - var typedData = new double[shape.length]; - Assert.IsTrue((sizeof(double) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => v < int.MinValue ? (float)int.MinValue : v > int.MaxValue ? (float)int.MaxValue : (float)v).ToArray(); - } - // Float32 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Float) - { - data = new float[shape.length]; - Assert.IsTrue((sizeof(float) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, data, 0, byteArray.Length); - } - // Float16 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Float16) - { - var typedData = new UInt16[shape.length]; - Assert.IsTrue((sizeof(UInt16) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => HalfHelper.HalfToSingle(v)).ToArray(); - } - // Int8 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Int8) - { - var typedData = new sbyte[shape.length]; - Assert.IsTrue((sizeof(sbyte) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => (float)v).ToArray(); - } - // Int16 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Int16) - { - var typedData = new short[shape.length]; - Assert.IsTrue((sizeof(short) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => (float)v).ToArray(); - } - // Int32 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Int32) - { - var typedData = new int[shape.length]; - Assert.IsTrue((sizeof(int) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => (float)v).ToArray(); - } - // Int64 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Int64) - { - var typedData = new long[shape.length]; - Assert.IsTrue((sizeof(long) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => v < (long)int.MinValue ? (float)int.MinValue : v > (long)int.MaxValue ? (float)int.MaxValue : (float)v).ToArray(); - } - // UInt8 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Uint8) - { - var typedData = new byte[shape.length]; - Assert.IsTrue((sizeof(byte) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => (float)v).ToArray(); - } - // UInt16 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Uint16) - { - var typedData = new ushort[shape.length]; - Assert.IsTrue((sizeof(ushort) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => (float)v).ToArray(); - } - // UInt32 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Uint32) - { - var typedData = new uint[shape.length]; - Assert.IsTrue((sizeof(uint) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => (float)v).ToArray(); - } - // UInt64 - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Uint64) - { - var typedData = new ulong[shape.length]; - Assert.IsTrue((sizeof(ulong) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => v > uint.MaxValue ? (float)uint.MaxValue : (float)v).ToArray(); - } - // Bool - else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Bool) - { - var typedData = new bool[shape.length]; - Assert.IsTrue((sizeof(bool) * shape.length) == onnxTensor.RawData.Length); - Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); - data = typedData.Select(v => v ? 1.0f : 0.0f).ToArray(); - } - else - throw new OnnxLayerImportException($"Tensor data type {(TensorProto.Types.DataType)onnxTensor.DataType} is not supported."); - } - // Float32 - else if ((onnxTensor.FloatData != null) && (onnxTensor.FloatData.Count != 0)) - { - Assert.IsTrue(shape.length == onnxTensor.FloatData.Count); - data = new float[shape.length]; - onnxTensor.FloatData.CopyTo(data, 0); - } - // Int32 - else if ((onnxTensor.Int32Data != null) && (onnxTensor.Int32Data.Count != 0)) - { - Assert.IsTrue(shape.length == onnxTensor.Int32Data.Count); - data = onnxTensor.Int32Data.Select(v => (float)v).ToArray(); - } - // Int64 - else if ((onnxTensor.Int64Data != null) && (onnxTensor.Int64Data.Count != 0)) - { - Assert.IsTrue(shape.length == onnxTensor.Int64Data.Count); - data = onnxTensor.Int64Data.Select(v => v < int.MinValue ? (float)int.MinValue : v > int.MaxValue ? (float)int.MaxValue : (float)v).ToArray(); - } - else - { - throw new OnnxLayerImportException("Could not read tensor data for constant tensor."); - } - - m_Data = new Tensor(shape, new SharedArrayTensorData(data)); - m_Shape = onnxShape; - } - } - - public ONNXTensor(Tensor data, int[] onnxShape) - { - m_Data = data; - m_Shape = onnxShape; - } - - public bool IsEmpty() - { - return m_Shape.Any(s => s == 0); - } - - public ONNXTensor Reshape(int[] onnxShape) - { - var symbolicShape = ONNXLayout.ConvertSymbolicShapeToBarracuda(onnxShape, "?"); - var reshapedData = m_Data.Reshape(symbolicShape); - for (var i = 0; i < onnxShape.Length; ++i) - { - if (onnxShape[i] < 0) - onnxShape[i] = reshapedData.shape[i]; - Assert.IsTrue(onnxShape[i] == reshapedData.shape[i]); - } - return new ONNXTensor(reshapedData, onnxShape); - } - - public ONNXTensor Permute(int[] permutations) - { - // transpose both data & shape - var transposedData = Permute(m_Data, permutations); - var transposedShape = ONNXLayout.Permute(m_Shape, permutations); - return new ONNXTensor(transposedData, transposedShape); - } - - public ONNXTensor NonZero() - { - //https://github.com/onnx/onnx/blob/master/docs/Operators.md#NonZero - //https://numpy.org/doc/stable/reference/generated/numpy.nonzero.html - //Return the indices of the elements that are non-zero. Iterating row major c style. - - // pad with 1s to visit all elements at least once in the loop. - int[] paddedONNXShape = new int[] {1, 1, 1, 1, 1, 1, 1, 1}; - for (int d = 0; d < rank; ++d) - paddedONNXShape[d] = shape[d]; - - // collect all non zero item - List nonZeroIndices = new List(); - for (var it = new TensorIterator(m_Data.shape); it.IsValid(); it.Next()) - { - if (Math.Abs(m_Data[it.index]) > Single.Epsilon) - nonZeroIndices.Add(new int[] {it.d0,it.d1,it.d2,it.d3,it.d4,it.d5,it.d6,it.d7}); - } - - // store indices in dest tensor - Tensor result = new Tensor(new TensorShape(rank, nonZeroIndices.Count)); - for(int i = 0; i < nonZeroIndices.Count; ++i) - { - for (int d = 0; d < rank; ++d) - result[d,i] = nonZeroIndices[i][d]; - } - - return new ONNXTensor(result, new int[] {rank, nonZeroIndices.Count}); - } - - public ONNXTensor SqueezeAll() - { - var newShape = m_Shape.Where(x => x > 1).ToArray(); - if (newShape.Length == 0) - newShape = new[] { 1 }; - return Reshape(newShape); - } - - public ONNXTensor Squeeze(int[] axes) - { - var newShape = m_Shape.ToList(); - foreach (var axis in axes) - { - // axis in [-rank,rank-1] - var axisInRange = axis >= 0 ? axis : 4 + axis; - if (newShape[axisInRange] == 1) - newShape[axisInRange] = -1; - } - newShape.RemoveAll(x => x == -1); - for (int i = newShape.Count; i < 4; i++) - newShape.Add(1); - - return Reshape(newShape.ToArray()); - } - - public ONNXTensor Unsqueeze(int[] axes) - { - var newShape = m_Shape.ToList(); - foreach (var axis in axes) - { - // axis in [-rank,rank-1] - var axisInRange = axis >= 0 ? axis : 4 + axis; - newShape.Insert(axis, 1); - } - return Reshape(newShape.ToArray()); - } - - public ONNXTensor Slice(int[] starts, int[] ends, int[] steps) - { - Assert.IsTrue(starts.Length == ends.Length); - Assert.IsTrue(starts.Length == steps.Length); - - var newShape = new int[starts.Length]; - // handle negative indices, negative steps - for (var i = 0; i < m_Shape.Length; ++i) - { - if (starts[i] < 0) - starts[i] = (int)m_Shape[i] + starts[i]; - if (ends[i] < 0) - ends[i] = (int)m_Shape[i] + ends[i]; - if (steps[i] == 0) - { - starts[i] = 0; - ends[i] = 1; - steps[i] = 1; - } - ends[i] = Math.Min((int)m_Shape[i], ends[i]); - } - - // calculate shape for sliced tensor - for (var i = 0; i < m_Shape.Length; ++i) - newShape[i] = (ends[i] - starts[i]) / steps[i]; - - int[] newONNXShapePadded = new int[] {1, 1, 1, 1, 1, 1, 1, 1}; - for (int d = 0; d < newShape.Length; ++d) - newONNXShapePadded[d] = newShape[d]; - Tensor result = new Tensor(newONNXShapePadded); - - // pad to the number of the loops - 4 - starts = starts.Concat(Enumerable.Repeat(0, 4 - starts.Length)).ToArray(); - ends = ends.Concat (Enumerable.Repeat(1, 4 - ends.Length)).ToArray(); // we need to keep 1, to visit all elements at least once - steps = steps.Concat (Enumerable.Repeat(1, 4 - steps.Length)).ToArray(); - - for (int b = starts[0], bo = 0; b < ends[0]; b += steps[0], bo++) - for (int y = starts[1], yo = 0; y < ends[1]; y += steps[1], yo++) - for (int x = starts[2], xo = 0; x < ends[2]; x += steps[2], xo++) - for (int c = starts[3], co = 0; c < ends[3]; c += steps[3], co++) - result[bo, yo, xo, co] = m_Data[b, y, x, c]; - - return new ONNXTensor(result, newShape.ToArray()); - } - - public ONNXTensor Gather(int axis, int[] indices) - { - //Atm support up to 4D tensors. - Assert.IsTrue(indices.Length < 5); - - // good explanation can be found here: - // https://stackoverflow.com/questions/50999977/what-does-the-gather-function-do-in-pytorch-in-layman-terms - int[] newONNXShape = m_Shape.Select(i => (int)i).ToArray(); - newONNXShape[axis] = indices.Length; - - // pad with 1s to visit all elements at least once in the loop. - int[] newONNXShapePadded = new int[] {1, 1, 1, 1, 1, 1, 1, 1}; - for (int d = 0; d < newONNXShape.Length; ++d) - newONNXShapePadded[d] = newONNXShape[d]; - - Tensor result = new Tensor(newONNXShapePadded); - - for (int b = 0; b < newONNXShapePadded[0]; ++b) - for (int y = 0; y < newONNXShapePadded[1]; ++y) - for (int x = 0; x < newONNXShapePadded[2]; ++x) - for (int c = 0; c < newONNXShapePadded[3]; ++c) - { - if (axis == 0) - result[b, y, x, c, 0, 0, 0, 0] = m_Data[indices[b], y, x, c, 0, 0, 0, 0]; - else if (axis == 1) - result[b, y, x, c, 0, 0, 0, 0] = m_Data[b, indices[y], x, c, 0, 0, 0, 0]; - else if (axis == 2) - result[b, y, x, c, 0, 0, 0, 0] = m_Data[b, y, indices[x], c, 0, 0, 0, 0]; - else - result[b, y, x, c, 0, 0, 0, 0] = m_Data[b, y, x, indices[c], 0, 0, 0, 0]; - } - - return new ONNXTensor(result, newONNXShape.ToArray()); - } - - public float this[int index] - { - get { return m_Data[index]; } - } - - public Tensor ToBarracuda(string onnxLayout) - { - Profiler.BeginSample("ONNXTensor.ToBarracuda"); - if (onnxLayout == "?") - throw new OnnxLayerImportException("Unknown ONNX layout in not supported when converting constant tensor to Barracuda"); - - Assert.IsTrue(m_Shape.All(v => v > 0)); - var permutations = ONNXLayout.AxisPermutationsForMappingONNXLayoutToBarracuda(rank, onnxLayout); - Assert.IsTrue(rank <= permutations.Length); - - var outTensor = Permute(m_Data, permutations); - Profiler.EndSample(); - return outTensor; - } - - internal static ONNXTensor Range(float start, float limit, float delta) - { - int nbElements = Mathf.Max((int)Mathf.Ceil((limit - start) / delta), 0); - Tensor output = new Tensor(nbElements, 1); - - for (int i = 0; i < nbElements; ++i) - { - output[i] = start + (i * delta); - } - return new ONNXTensor(output, new[] { nbElements }); - } - - internal static Tensor Permute(Tensor inTensor, int[] permutations) // TODO: unify Permute() arguments - { - var padPermutationsToBarracudaRank = TensorShape.MaxRank - permutations.Length; - if (padPermutationsToBarracudaRank > 0) - permutations = permutations.Concat(Enumerable.Range(permutations.Length, padPermutationsToBarracudaRank)).ToArray(); - Assert.IsTrue(permutations.Length == TensorShape.MaxRank); - - // See: https://stackoverflow.com/a/32034565 - Profiler.BeginSample("ONNXTensor.Permute"); - var outTensor = new Tensor(ONNXLayout.Permute(inTensor.shape.ToArray(), permutations)); - Assert.IsTrue(outTensor.length == inTensor.length); - - // {0, 2, 3, 1} => {0, 3, 1, 2} - // {2, 3, 1, 0} => {3, 2, 0, 1} - // => {find_index(0), find_index(1), find_index(2), find_index(3)} - var reversePermute = new int[permutations.Length]; - for (var i = 0; i < permutations.Length; ++i) - reversePermute[i] = Array.IndexOf(permutations, i); - - // outTensor strides - var tempOutStrides = new int[TensorShape.MaxRank+1]; - tempOutStrides[8] = 1; - for (int i = 7; i >= 0; --i) - tempOutStrides[i] = tempOutStrides[i+1] * outTensor.shape[i]; - - var outStride = new int[reversePermute.Length]; - for (var i = 0; i < reversePermute.Length; ++i) - outStride[i] = tempOutStrides[reversePermute[i] + 1]; - - for (var it = new TensorIterator(inTensor.shape); it.IsValid(); it.Next()) - { - float value = inTensor[it.index]; - - outTensor[it.d0 * outStride[0] + - it.d1 * outStride[1] + - it.d2 * outStride[2] + - it.d3 * outStride[3] + - it.d4 * outStride[4] + - it.d5 * outStride[5] + - it.d6 * outStride[6] + - it.d7 * outStride[7]] = value; - } - - Profiler.EndSample(); - return outTensor; - } - - // slow version - kept just for performance comparison and validation - internal static Tensor PermuteSlow(Tensor readTensor, int[] permutations) // TODO: unify Permute() arguments - { - var padPermutationsToBarracudaRank = 8 - permutations.Length; - if (padPermutationsToBarracudaRank > 0) - permutations = permutations.Concat(Enumerable.Range(permutations.Length, padPermutationsToBarracudaRank)).ToArray(); - Assert.IsTrue(permutations.Length == 8); - - var outputTensor = new Tensor(ONNXLayout.Permute(readTensor.shape.ToArray(), permutations)); - Assert.IsTrue(outputTensor.length == readTensor.length); - - var inShape = readTensor.shape.ToArray(); - for (var s = 0; s < inShape[0]; ++s) - for (var n = 0; n < inShape[1]; ++n) - for (var i0 = 0; i0 < inShape[2]; ++i0) - for (var i1 = 0; i1 < inShape[3]; ++i1) - for (var i2 = 0; i2 < inShape[4]; ++i2) - for (var h = 0; h < inShape[5]; ++h) - for (var w = 0; w < inShape[6]; ++w) - for (var c = 0; c < inShape[7]; ++c) - { - var it = new int[] {0, s, n, i0, i1, i2, h, w, c}; // prepend with 0 to handle "new axis" -1 value in permutations - var oS = it[permutations[0] + 1]; - var oN = it[permutations[1] + 1]; - var oI0 = it[permutations[2] + 1]; - var oI1 = it[permutations[3] + 1]; - var oI2 = it[permutations[4] + 1]; - var oH = it[permutations[5] + 1]; - var oW = it[permutations[6] + 1]; - var oC = it[permutations[7] + 1]; - outputTensor[oS, oN, oI0, oI1, oI2, oH, oW, oC] = readTensor[s, n, i0, i1, i2, h, w, c]; - } - - return outputTensor; - } - } - - // Description of the layer's output - internal struct VariableTensor - { - public enum Layout - { - Unknown = 0, - NCHW = 1, ChannelsFirst = NCHW, - NHWC = 2, ChannelsLast = NHWC, - }; - - public int features; - public int rank; - public string productOfShape; - public Layout layout; - } - - // Keeps track of constant and variable tensors of the model - internal class ONNXModelTensors - { - internal Dictionary constants = - new Dictionary(); - - internal Dictionary variables = - new Dictionary(); - - public void AddConstant(string name, ONNXTensor onnxTensor) - { - if (!onnxTensor.IsEmpty()) - { - constants[name] = onnxTensor; - AddVariable(name, onnxTensor); - } - } - - public void AddVariable(string nodeId, int features, string productOfShape, - VariableTensor.Layout layout = VariableTensor.Layout.Unknown) - { - variables[nodeId] = new VariableTensor { - features = features, - rank = 1, - productOfShape = productOfShape, - layout = VariableTensor.Layout.Unknown }; - } - public void AddVariable(string nodeId, int features = -1, int rank = -1, - VariableTensor.Layout layout = VariableTensor.Layout.Unknown) - { - variables[nodeId] = new VariableTensor { - features = features, - rank = rank, - layout = layout, - productOfShape = null }; - } - public void AddVariable(string nodeId, ONNXTensor onnxTensor) - { - variables[nodeId] = new VariableTensor { - features = -1, - rank = onnxTensor.rank, - layout = VariableTensor.Layout.Unknown, - productOfShape = null }; - } - public void AddVariable(string nodeId, long[] onnxShape, string onnxLayout) - { - var onnxRank = onnxShape.Length; - var permuatations = ONNXLayout.AxisPermutationsForMappingONNXLayoutToBarracuda(onnxRank, onnxLayout); - var barracudaChannelIndex = permuatations.Length - 1; - var onnxChannelIndex = permuatations[barracudaChannelIndex]; - var channels = (onnxLayout != "?" && onnxChannelIndex >= 0) ? (int)onnxShape[onnxChannelIndex]: -1; - var layout = VariableTensor.Layout.Unknown; - if (onnxLayout == "NCHW") - layout = VariableTensor.Layout.NCHW; - else if (onnxLayout == "NHWC") - layout = VariableTensor.Layout.NHWC; - - variables[nodeId] = new VariableTensor { - features = channels, - rank = onnxRank, - layout = layout, - productOfShape = null }; - } - - public void CompleteUninitializedFields(ONNXNodeWrapper node) - { - Assert.IsTrue(variables.ContainsKey(node.Name)); - var output = variables[node.Name]; - - if (output.features == -1) - { - if (variables.ContainsKey(node.Input0Optional)) - output.features = variables[node.Input0Optional].features; - } - if (output.rank == -1) - { - if (constants.ContainsKey(node.Name)) - output.rank = constants[node.Name].rank; - else if (variables.ContainsKey(node.Input0Optional)) - output.rank = variables[node.Input0Optional].rank; - } - if (output.layout == VariableTensor.Layout.Unknown) - { - if (variables.ContainsKey(node.Input0Optional)) - output.layout = variables[node.Input0Optional].layout; - } - if (!node.IsTerminatorForProductOfShape && output.productOfShape == null) - { - if (variables.ContainsKey(node.Input0Optional)) - output.productOfShape = variables[node.Input0Optional].productOfShape; - } - - variables[node.Name] = output; - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXTensor.cs.meta b/Packages/com.unity.barracuda/Runtime/ONNX/ONNXTensor.cs.meta deleted file mode 100644 index f7d3b11..0000000 --- a/Packages/com.unity.barracuda/Runtime/ONNX/ONNXTensor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d1fb4fd94bf0d4bd6b127c5c01ee6362 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins.meta b/Packages/com.unity.barracuda/Runtime/Plugins.meta deleted file mode 100644 index 3dbebb3..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c1be707eadd73384a869f7df7447115d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/Burst.meta b/Packages/com.unity.barracuda/Runtime/Plugins/Burst.meta deleted file mode 100644 index 04e3572..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/Burst.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2733d1f9336f7c149935af90b2171cb8 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/Burst/BurstBLAS.cs b/Packages/com.unity.barracuda/Runtime/Plugins/Burst/BurstBLAS.cs deleted file mode 100644 index 01482ed..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/Burst/BurstBLAS.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using Unity.Burst; -using Unity.Jobs; -using UnityEngine.Scripting; - -[assembly: AlwaysLinkAssembly] -[assembly: BurstCompile(OptimizeFor = OptimizeFor.FastCompilation)] - -namespace Unity.Barracuda -{ - - /// - /// Burst specific BLAS implementation - /// - [Preserve] - public class BurstBLAS : BLASPlugin - { - /// - public bool IsNative() - { - return false; // not a native fast BLAS implementation - } - - /// - public bool IsCurrentPlatformSupported() - { - try - { - // Sanity test if all the dependencies of the job are met at runtime - // Also prevent compiler from optimising this out - new BurstCPUOps.MatrixMultiplyJob(); - } - catch (Exception e) - { - D.Log($"C# Job system not found. Disabling {this.GetType()}. Error: {e}"); - return false; - } - - return true; - } - - /// - public unsafe void SGEMM(float* Ap, int AM, int AN, float* Bp, int BM, int BN, float* Cp, int CM, int CN, - int bs, - bool transposeA = false, bool transposeB = false) - { - var noDependencies = new JobHandle(); - var fence = ScheduleSGEMM(noDependencies, Ap, AM, AN, Bp, BM, BN, Cp, CM, CN, bs, transposeA, transposeB); - fence.Complete(); - } - - /// - public unsafe JobHandle ScheduleSGEMM(JobHandle dependsOn, - float* Ap, int AM, int AN, float* Bp, int BM, int BN, float* Cp, int CM, int CN, - int bs, // NOTE: bs (block size) is ignored - bool transposeA = false, bool transposeB = false) - { - var job = new BurstCPUOps.MatrixMultiplyJob(); - job.A = Ap; job.AM = AM; job.AN = AN; - job.B = Bp; job.BM = BM; job.BN = BN; - job.C = Cp; job.CM = CM; job.CN = CN; - job.transposeA = transposeA; - job.transposeB = transposeB; - - return job.Schedule(dependsOn); - } - } -} diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/Burst/BurstBLAS.cs.meta b/Packages/com.unity.barracuda/Runtime/Plugins/Burst/BurstBLAS.cs.meta deleted file mode 100644 index fbe1bbd..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/Burst/BurstBLAS.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5991aeeb69c95451aad913637fdf5036 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/Burst/Unity.Barracuda.BurstBLAS.asmdef b/Packages/com.unity.barracuda/Runtime/Plugins/Burst/Unity.Barracuda.BurstBLAS.asmdef deleted file mode 100644 index 54a5d20..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/Burst/Unity.Barracuda.BurstBLAS.asmdef +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "Unity.Barracuda.BurstBLAS", - "references": [ - "Unity.Barracuda", - "Unity.Burst" - ], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": true -} diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/OSX.meta b/Packages/com.unity.barracuda/Runtime/Plugins/OSX.meta deleted file mode 100644 index f1908d8..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/OSX.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 102f8610baebf43419e6ebf9702b21ee -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/OSX/MacBLAS.cs b/Packages/com.unity.barracuda/Runtime/Plugins/OSX/MacBLAS.cs deleted file mode 100644 index 99ff803..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/OSX/MacBLAS.cs +++ /dev/null @@ -1,93 +0,0 @@ -#if UNITY_2018_1_OR_NEWER && (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX) -using System.Runtime.InteropServices; -using UnityEngine; -using UnityEngine.Scripting; - -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs; - -[assembly: AlwaysLinkAssembly] - -namespace Unity.Barracuda -{ - - [Preserve] - public class MacBLAS : BLASPlugin - { - [DllImport("/System/Library/Frameworks/Accelerate.framework/Accelerate")] - static extern unsafe void cblas_sgemm(CBLAS_ORDER __Order, CBLAS_TRANSPOSE __TransA, CBLAS_TRANSPOSE __TransB, - int __M, int __N, int __K, float __alpha, float *__A, int __lda, float *__B, int __ldb, - float __beta, float *__C, int __ldc); - - public bool IsNative() - { - return true; - } - - public bool IsCurrentPlatformSupported() - { - return Application.platform == RuntimePlatform.OSXEditor || - Application.platform == RuntimePlatform.OSXPlayer; - } - - public unsafe void SGEMM(float* Ap, int AM, int AN, float* Bp, int BM, int BN, float* Cp, int CM, int CN, - int bs, - bool transposeA = false, bool transposeB = false) - { - cblas_sgemm(CBLAS_ORDER.CblasRowMajor, transposeA ? CBLAS_TRANSPOSE.CblasTrans : CBLAS_TRANSPOSE.CblasNoTrans, - transposeB ? CBLAS_TRANSPOSE.CblasTrans : CBLAS_TRANSPOSE.CblasNoTrans, - AM, BN, BM, 1.0f, Ap, AN, Bp, BN, 1.0f, Cp, CN); - } - - public unsafe JobHandle ScheduleSGEMM(JobHandle dependsOn, - float* Ap, int AM, int AN, float* Bp, int BM, int BN, float* Cp, int CM, int CN, - int bs, - bool transposeA = false, bool transposeB = false) - { - var job = new SGEMMJob(); - job.Ap = Ap; job.AM = AM; job.AN = AN; - job.Bp = Bp; job.BM = BM; job.BN = BN; - job.Cp = Cp; job.CM = CM; job.CN = CN; - job.transposeA = transposeA; - job.transposeB = transposeB; - job.bs = bs; - return job.Schedule(dependsOn); - } - - unsafe struct SGEMMJob : IJob - { - [NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* Ap; - public int AM, AN; - [NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* Bp; - public int BM, BN; - [NativeDisableUnsafePtrRestriction] public unsafe float* Cp; - public int CM, CN; - public int bs; - public bool transposeA; - public bool transposeB; - - public void Execute() - { - cblas_sgemm(CBLAS_ORDER.CblasRowMajor, transposeA ? CBLAS_TRANSPOSE.CblasTrans : CBLAS_TRANSPOSE.CblasNoTrans, - transposeB ? CBLAS_TRANSPOSE.CblasTrans : CBLAS_TRANSPOSE.CblasNoTrans, - AM, BN, BM, 1.0f, Ap, AN, Bp, BN, 1.0f, Cp, CN); - } - } - - internal enum CBLAS_ORDER - { - CblasRowMajor=101, - CblasColMajor=102 - }; - - internal enum CBLAS_TRANSPOSE - { - CblasNoTrans=111, - CblasTrans=112, - CblasConjTrans=113, - AtlasConj=114 - }; - } -} -#endif // UNITY_OSX diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/OSX/MacBLAS.cs.meta b/Packages/com.unity.barracuda/Runtime/Plugins/OSX/MacBLAS.cs.meta deleted file mode 100644 index b90d4ac..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/OSX/MacBLAS.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 680f04373f71f48a89408105d3f58a08 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/OSX/Unity.Barracuda.MacBLAS.asmdef b/Packages/com.unity.barracuda/Runtime/Plugins/OSX/Unity.Barracuda.MacBLAS.asmdef deleted file mode 100644 index 195772f..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/OSX/Unity.Barracuda.MacBLAS.asmdef +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "Unity.Barracuda.MacBLAS", - "references": [ - "Unity.Barracuda" - ], - "optionalUnityReferences": [], - "includePlatforms": [ - "Editor", - "macOSStandalone" - ], - "excludePlatforms": [], - "allowUnsafeCode": true -} diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/OSX/Unity.Barracuda.MacBLAS.asmdef.meta b/Packages/com.unity.barracuda/Runtime/Plugins/OSX/Unity.Barracuda.MacBLAS.asmdef.meta deleted file mode 100644 index 4a3cefc..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/OSX/Unity.Barracuda.MacBLAS.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 53fc9961397934ed38a573ce1392c80c -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/ProtoBuffer.meta b/Packages/com.unity.barracuda/Runtime/Plugins/ProtoBuffer.meta deleted file mode 100644 index 33bcbc6..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/ProtoBuffer.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 63044871e4b2444f58fc1f851449f1ab -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/iOS.meta b/Packages/com.unity.barracuda/Runtime/Plugins/iOS.meta deleted file mode 100644 index caf39f7..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/iOS.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e8a84647db5428f47a64012075c02b25 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/Unity.Barracuda.iOSBLAS.asmdef b/Packages/com.unity.barracuda/Runtime/Plugins/iOS/Unity.Barracuda.iOSBLAS.asmdef deleted file mode 100644 index b611d80..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/Unity.Barracuda.iOSBLAS.asmdef +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "Unity.Barracuda.iOSBLAS", - "references": [ - "Unity.Barracuda" - ], - "optionalUnityReferences": [], - "includePlatforms": [ - "Editor", - "iOS" - ], - "excludePlatforms": [], - "allowUnsafeCode": true -} diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/Unity.Barracuda.iOSBLAS.asmdef.meta b/Packages/com.unity.barracuda/Runtime/Plugins/iOS/Unity.Barracuda.iOSBLAS.asmdef.meta deleted file mode 100644 index 5b93d76..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/Unity.Barracuda.iOSBLAS.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 005937e819cd540429ad05eabcfb642f -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.cs b/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.cs deleted file mode 100644 index 595290b..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.cs +++ /dev/null @@ -1,73 +0,0 @@ -#if UNITY_IOS -using System.Runtime.InteropServices; -using UnityEngine; -using UnityEngine.Scripting; - -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs; - -[assembly: AlwaysLinkAssembly] - -namespace Unity.Barracuda { - - [Preserve] - public class iOSBLAS : BLASPlugin - { - [DllImport("__Internal")] - static extern unsafe void iossgemm(float* Ap, int AM, int AN, - float* Bp, int BM, int BN, - float* Cp, int CM, int CN, - int bs, bool transposeA, bool transposeB); - - public bool IsNative() - { - return true; - } - - public bool IsCurrentPlatformSupported() - { - return Application.platform == RuntimePlatform.IPhonePlayer; - } - - public unsafe void SGEMM(float* Ap, int AM, int AN, float* Bp, int BM, int BN, float* Cp, int CM, int CN, int bs, - bool transposeA = false, bool transposeB = false) - { - iossgemm(Ap, AM, AN, Bp, BM, BN, Cp, CM, CN, bs, transposeA, transposeB); - } - - public unsafe JobHandle ScheduleSGEMM(JobHandle dependsOn, - float* Ap, int AM, int AN, float* Bp, int BM, int BN, float* Cp, int CM, int CN, - int bs, - bool transposeA = false, bool transposeB = false) - { - var job = new SGEMMJob(); - job.Ap = Ap; job.AM = AM; job.AN = AN; - job.Bp = Bp; job.BM = BM; job.BN = BN; - job.Cp = Cp; job.CM = CM; job.CN = CN; - job.transposeA = transposeA; - job.transposeB = transposeB; - job.bs = bs; - return job.Schedule(dependsOn); - } - - unsafe struct SGEMMJob : IJob - { - [NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* Ap; - public int AM, AN; - [NativeDisableUnsafePtrRestriction][ReadOnly] public unsafe float* Bp; - public int BM, BN; - [NativeDisableUnsafePtrRestriction] public unsafe float* Cp; - public int CM, CN; - public int bs; - public bool transposeA; - public bool transposeB; - - public void Execute() - { - iossgemm(Ap, AM, AN, Bp, BM, BN, Cp, CM, CN, bs, transposeA, transposeB); - } - } - } -} -#endif // UNITY_IOS diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.cs.meta b/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.cs.meta deleted file mode 100644 index 9304817..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 75424b0c6afc14ea7a1debef68240d9e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.mm b/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.mm deleted file mode 100644 index a4e17ee..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.mm +++ /dev/null @@ -1,15 +0,0 @@ -#import - -extern "C" -{ -void iossgemm(float* Ap, int AM, int AN, - float* Bp, int BM, int BN, - float* Cp, int CM, int CN, - int bs, bool transposeA, bool transposeB) - { - cblas_sgemm(CblasRowMajor, transposeA ? CblasTrans : CblasNoTrans, - transposeB ? CblasTrans : CblasNoTrans, - AM, BN, BM, 1.0f, Ap, AN, Bp, BN, 1.0f, Cp, CN); - } - -} diff --git a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.mm.meta b/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.mm.meta deleted file mode 100644 index 2fa3f6d..0000000 --- a/Packages/com.unity.barracuda/Runtime/Plugins/iOS/iOSBLAS.mm.meta +++ /dev/null @@ -1,102 +0,0 @@ -fileFormatVersion: 2 -guid: 100b08f95d9f349118f287b0170140d4 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - isPreloaded: 0 - isOverridable: 0 - platformData: - - first: - '': Any - second: - enabled: 0 - settings: - Exclude Android: 1 - Exclude Editor: 1 - Exclude Linux: 1 - Exclude Linux64: 1 - Exclude LinuxUniversal: 1 - Exclude OSXUniversal: 1 - Exclude WebGL: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 0 - - first: - Android: Android - second: - enabled: 0 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Facebook: Win - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Facebook: Win64 - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Linux - second: - enabled: 0 - settings: - CPU: x86 - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: x86_64 - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - iPhone: iOS - second: - enabled: 1 - settings: - AddToEmbeddedBinaries: false - CompileFlags: - FrameworkDependencies: Accelerate; - - first: - tvOS: tvOS - second: - enabled: 1 - settings: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Tests/Editor.meta b/Packages/com.unity.barracuda/Tests/Editor.meta deleted file mode 100644 index 671a1df..0000000 --- a/Packages/com.unity.barracuda/Tests/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 214a06e95f63946e0802c5f9121c2e2b -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Tests/Editor/BasicNNInferenceTestSuite.cs b/Packages/com.unity.barracuda/Tests/Editor/BasicNNInferenceTestSuite.cs deleted file mode 100644 index 66c4663..0000000 --- a/Packages/com.unity.barracuda/Tests/Editor/BasicNNInferenceTestSuite.cs +++ /dev/null @@ -1,86 +0,0 @@ -using NUnit.Framework; -using Unity.Barracuda; -using UnityEditor; -using UnityEngine; - -namespace Unity.Barracuda.Editor.Tests -{ - public class BasicNNInferenceTestSuite - { - private static string modelFileName = "mnist-cnn-mini"; - private static float epsilon = 1e-3f; - - [Test] - public void BasicNNInferenceTest() - { - - string[] allCandidates = AssetDatabase.FindAssets(modelFileName); - - Assert.True(allCandidates.Length > 0); - - var nnModel = - AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(allCandidates[0]), typeof(NNModel)) as - NNModel; - var model = ModelLoader.Load(nnModel); - var engine = WorkerFactory.CreateWorker(model, WorkerFactory.Device.CPU); - - var inputTensor = new Tensor(1, 28, 28, 1, input); - engine.Execute(inputTensor); - - var outputTensor = engine.PeekOutput(); - - Assert.AreEqual(output.Length, outputTensor.length); - - // Check if output matches expected output down to epsilon - for (var i = 0; i < output.Length; i++) - { - Assert.LessOrEqual(Mathf.Abs(outputTensor[i] - output[i]), epsilon); - } - - inputTensor.Dispose(); - engine.Dispose(); - } - - // Bitmap of the handwritten number 7 - private static float[] input = - { - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, - 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f - }; - - // One hot encoding of the expected output - private static float[] output = - { - 2.0996596e-12f, 3.3146248e-09f, 5.6115475e-08f, 1.4575244e-06f, - 2.6770785e-11f, 6.5430744e-10f, 1.2471284e-20f, 9.9999809e-01f, - 1.3933428e-10f, 3.3245624e-07f - }; - } -} - diff --git a/Packages/com.unity.barracuda/Tests/Editor/BasicNNInferenceTestSuite.cs.meta b/Packages/com.unity.barracuda/Tests/Editor/BasicNNInferenceTestSuite.cs.meta deleted file mode 100644 index a53fe4a..0000000 --- a/Packages/com.unity.barracuda/Tests/Editor/BasicNNInferenceTestSuite.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0ba852d7e580642ba96f422ebfc86f2d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Tests/Editor/Unity.Barracuda.Editor.Tests.asmdef b/Packages/com.unity.barracuda/Tests/Editor/Unity.Barracuda.Editor.Tests.asmdef deleted file mode 100644 index 63a37bf..0000000 --- a/Packages/com.unity.barracuda/Tests/Editor/Unity.Barracuda.Editor.Tests.asmdef +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "Unity.Barracuda.Editor.Tests", - "references": [ - "Unity.Barracuda" - ], - "optionalUnityReferences": [ - "TestAssemblies" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [ - "UNITY_INCLUDE_TESTS" - ], - "versionDefines": [] -} diff --git a/Packages/com.unity.barracuda/Tests/Editor/Unity.Barracuda.Editor.Tests.asmdef.meta b/Packages/com.unity.barracuda/Tests/Editor/Unity.Barracuda.Editor.Tests.asmdef.meta deleted file mode 100644 index 78ffaec..0000000 --- a/Packages/com.unity.barracuda/Tests/Editor/Unity.Barracuda.Editor.Tests.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6641b37355ccc4fda9ca4962c97755fe -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.barracuda/Tests/Editor/mnist-cnn-mini.onnx b/Packages/com.unity.barracuda/Tests/Editor/mnist-cnn-mini.onnx deleted file mode 100644 index 4511d28..0000000 Binary files a/Packages/com.unity.barracuda/Tests/Editor/mnist-cnn-mini.onnx and /dev/null differ diff --git a/Packages/com.unity.barracuda/Tests/Editor/mnist-cnn-mini.onnx.meta b/Packages/com.unity.barracuda/Tests/Editor/mnist-cnn-mini.onnx.meta deleted file mode 100644 index aa36b36..0000000 --- a/Packages/com.unity.barracuda/Tests/Editor/mnist-cnn-mini.onnx.meta +++ /dev/null @@ -1,14 +0,0 @@ -fileFormatVersion: 2 -guid: ace239a794155483188aa968ecd7d5ae -ScriptedImporter: - fileIDToRecycleName: - 11400000: main obj - 11400002: model data - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: - script: {fileID: 11500000, guid: 683b6cb6d0a474744822c888b46772c9, type: 3} - optimizeModel: 1 - forceArbitraryBatchSize: 1 - treatErrorsAsWarnings: 0 diff --git a/Packages/com.unity.barracuda/package.json b/Packages/com.unity.barracuda/package.json deleted file mode 100644 index 4e3bd1d..0000000 --- a/Packages/com.unity.barracuda/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "com.unity.barracuda", - "displayName": "Barracuda", - "version": "3.0.0", - "unity": "2019.4", - "description": "Barracuda is lightweight and cross-platform Neural Net inference library. Barracuda supports inference both on GPU and CPU.", - "dependencies": { - "com.unity.burst": "1.6.0", - "com.unity.modules.jsonserialize": "1.0.0", - "com.unity.modules.imageconversion": "1.0.0" - } -} \ No newline at end of file diff --git a/Packages/manifest.json b/Packages/manifest.json index 50a2c9d..f87140d 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,7 +1,16 @@ { + "scopedRegistries": [ + { + "name": "NatML", + "url": "https://registry.npmjs.com/", + "scopes": [ + "ai.natml" + ] + } + ], "dependencies": { + "ai.natml.natml": "1.1.3", "com.unity.2d.sprite": "1.0.0", - "com.unity.barracuda": "3.0.0", "com.unity.collab-proxy": "2.0.0", "com.unity.ide.rider": "3.0.18", "com.unity.ide.visualstudio": "2.0.17", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index c1efa11..3e3a80c 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -1,5 +1,21 @@ { "dependencies": { + "ai.natml.hub": { + "version": "1.0.20", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://registry.npmjs.com" + }, + "ai.natml.natml": { + "version": "1.1.3", + "depth": 0, + "source": "registry", + "dependencies": { + "ai.natml.hub": "1.0.20" + }, + "url": "https://registry.npmjs.com" + }, "com.github.homuler.mediapipe": { "version": "file:com.github.homuler.mediapipe", "depth": 0, @@ -12,25 +28,6 @@ "source": "builtin", "dependencies": {} }, - "com.unity.barracuda": { - "version": "file:com.unity.barracuda", - "depth": 0, - "source": "embedded", - "dependencies": { - "com.unity.burst": "1.6.0", - "com.unity.modules.jsonserialize": "1.0.0", - "com.unity.modules.imageconversion": "1.0.0" - } - }, - "com.unity.burst": { - "version": "1.6.6", - "depth": 1, - "source": "registry", - "dependencies": { - "com.unity.mathematics": "1.2.1" - }, - "url": "https://packages.unity.com" - }, "com.unity.collab-proxy": { "version": "2.0.0", "depth": 0, @@ -70,13 +67,6 @@ "dependencies": {}, "url": "https://packages.unity.com" }, - "com.unity.mathematics": { - "version": "1.2.6", - "depth": 2, - "source": "registry", - "dependencies": {}, - "url": "https://packages.unity.com" - }, "com.unity.settings-manager": { "version": "1.0.3", "depth": 1, diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index bf86ff2..ebaed27 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -39,21 +39,21 @@ EditorBuildSettings: path: Assets/Common/Scenes/MinigameActivityScreen.unity guid: 8e27404f21454dc4583f76b4c7df0c30 - enabled: 1 - path: Assets/JustSign/Scenes/Game.unity + path: Assets/JustSign/Scenes/JustSignGame.unity guid: 1283017ac1c1f6226854442564bd7e3d - enabled: 1 path: Assets/Common/Scenes/ThemeSelectionScreen.unity guid: 2dfa1265c9d65014c90941ac4240a977 - enabled: 1 - path: Assets/Courses/Scenes/TemplateCourse.unity + path: Assets/Courses/Scenes/CourseScreen.unity guid: 2cda990e2423bbf4892e6590ba056729 - enabled: 1 - path: Assets/SpellingBee/Scenes/Game.unity + path: Assets/SpellingBee/Scenes/SpellingBeeGame.unity guid: 652195ae9a0ff3ad18f6338db6a909bd - enabled: 1 - path: Assets/Hangman/Scenes/Hangman.unity + path: Assets/Hangman/Scenes/HangmanGame.unity guid: 5ddd59ce344ac51459725a4878330faf - enabled: 1 - path: Assets/JustSign/Scenes/Game.unity + path: Assets/JustSign/Scenes/JustSignGame.unity guid: 1283017ac1c1f6226854442564bd7e3d m_configObjects: {} diff --git a/ProjectSettings/NatMLHub.asset b/ProjectSettings/NatMLHub.asset new file mode 100644 index 0000000..a0e3482 Binary files /dev/null and b/ProjectSettings/NatMLHub.asset differ diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset index bad0c21..50bc4bc 100644 --- a/ProjectSettings/PackageManagerSettings.asset +++ b/ProjectSettings/PackageManagerSettings.asset @@ -26,11 +26,19 @@ MonoBehaviour: m_IsDefault: 1 m_Capabilities: 7 m_ConfigSource: 0 - m_UserSelectedRegistryName: + - m_Id: scoped:project:NatML + m_Name: NatML + m_Url: https://registry.npmjs.com + m_Scopes: + - ai.natml + m_IsDefault: 0 + m_Capabilities: 0 + m_ConfigSource: 4 + m_UserSelectedRegistryName: NatML m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: m_Modified: 0 m_ErrorMessage: - m_UserModificationsInstanceId: -826 - m_OriginalInstanceId: -828 + m_UserModificationsInstanceId: -824 + m_OriginalInstanceId: -826 m_LoadAssets: 0 diff --git a/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json b/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json index 2510fe1..ad11087 100644 --- a/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json +++ b/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json @@ -2,22 +2,6 @@ "m_Name": "Settings", "m_Path": "ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json", "m_Dictionary": { - "m_DictionaryValues": [ - { - "type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", - "key": "IncludeAssemblies", - "value": "{\"m_Value\":\"AccountsScripts,AccountsTests,Assembly-CSharp,Assembly-CSharp-Editor,CommonScripts,CommonTests,CourseScripts,CoursesTests,HangmanTests,InterfacesScripts,JustSignTests,MediaPipeUnityScripts,SignPredictor,SpellingBeeScripts,SpellingBeeTests,Tween\"}" - }, - { - "type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", - "key": "Path", - "value": "{\"m_Value\":\"{ProjectPath}\"}" - }, - { - "type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", - "key": "HistoryPath", - "value": "{\"m_Value\":\"{ProjectPath}\"}" - } - ] + "m_DictionaryValues": [] } } \ No newline at end of file diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index aae41a5..8502e64 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -135,7 +135,41 @@ PlayerSettings: 16:9: 1 Others: 1 bundleVersion: 1.0 - preloadedAssets: [] + preloadedAssets: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} metroInputSource: 0 wsaTransparentSwapchain: 0 m_HolographicPauseOnTrackingLoss: 1 diff --git a/README.md b/README.md deleted file mode 100644 index eb72bb1..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Unity Application - -An overview of all the nessecary information can be found on the following links: - - [Getting Started](https://gitlab.ilabt.imec.be/wesign/unity-application/-/wikis/home) diff --git a/UserList b/UserList deleted file mode 100644 index e69de29..0000000 diff --git a/wesign-builds/WeSign-MacOS.zip b/wesign-builds/WeSign-MacOS-new.zip similarity index 68% rename from wesign-builds/WeSign-MacOS.zip rename to wesign-builds/WeSign-MacOS-new.zip index 60b43d5..a4592e1 100644 Binary files a/wesign-builds/WeSign-MacOS.zip and b/wesign-builds/WeSign-MacOS-new.zip differ